From f0eb58dd08770a2e24bfc41db5ee3ff7c3a684ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Tue, 16 Jan 2024 13:54:31 -0800 Subject: [PATCH 001/814] Input: navpoint - remove driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver does not use the SPI core as it should, instead tampering with the SSP registers manually. Refactoring the driver is almost certainly not worth it as the hardware seems to have been designed for and used only in the HP iPAQ hx4700 removed more than a year ago in d6df7df7ae5a ("ARM: pxa: remove unused board files"), so let's remove it. Signed-off-by: Duje Mihanović Link: https://lore.kernel.org/r/20240116-navpoint-removal-v2-2-e566806f1009@skole.hr Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 12 -- drivers/input/mouse/Makefile | 1 - drivers/input/mouse/navpoint.c | 350 --------------------------------- include/linux/input/navpoint.h | 8 - 4 files changed, 371 deletions(-) delete mode 100644 drivers/input/mouse/navpoint.c delete mode 100644 include/linux/input/navpoint.h diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 32cc4c62a716..833b643f0616 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -439,16 +439,4 @@ config MOUSE_SYNAPTICS_USB To compile this driver as a module, choose M here: the module will be called synaptics_usb. -config MOUSE_NAVPOINT_PXA27x - tristate "Synaptics NavPoint (PXA27x SSP/SPI)" - depends on PXA27x && PXA_SSP - help - This driver adds support for the Synaptics NavPoint touchpad connected - to a PXA27x SSP port in SPI slave mode. The device emulates a mouse; - a tap or tap-and-a-half drag gesture emulates the left mouse button. - For example, use the xf86-input-evdev driver for an X pointing device. - - To compile this driver as a module, choose M here: the - module will be called navpoint. - endif diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 92b3204ce84e..a1336d5bee6f 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o -obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c deleted file mode 100644 index ba757783c258..000000000000 --- a/drivers/input/mouse/navpoint.c +++ /dev/null @@ -1,350 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Synaptics NavPoint (PXA27x SSP/SPI) driver. - * - * Copyright (C) 2012 Paul Parsons - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Synaptics Modular Embedded Protocol: Module Packet Format. - * Module header byte 2:0 = Length (# bytes that follow) - * Module header byte 4:3 = Control - * Module header byte 7:5 = Module Address - */ -#define HEADER_LENGTH(byte) ((byte) & 0x07) -#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03) -#define HEADER_ADDRESS(byte) ((byte) >> 5) - -struct navpoint { - struct ssp_device *ssp; - struct input_dev *input; - struct device *dev; - struct gpio_desc *gpiod; - int index; - u8 data[1 + HEADER_LENGTH(0xff)]; -}; - -/* - * Initialization values for SSCR0_x, SSCR1_x, SSSR_x. - */ -static const u32 sscr0 = 0 - | SSCR0_TUM /* TIM = 1; No TUR interrupts */ - | SSCR0_RIM /* RIM = 1; No ROR interrupts */ - | SSCR0_SSE /* SSE = 1; SSP enabled */ - | SSCR0_Motorola /* FRF = 0; Motorola SPI */ - | SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */ - ; -static const u32 sscr1 = 0 - | SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */ - | SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */ - | SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */ - | SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */ - | SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */ - | SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */ - | SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */ - ; -static const u32 sssr = 0 - | SSSR_BCE /* BCE = 1; Clear BCE */ - | SSSR_TUR /* TUR = 1; Clear TUR */ - | SSSR_EOC /* EOC = 1; Clear EOC */ - | SSSR_TINT /* TINT = 1; Clear TINT */ - | SSSR_PINT /* PINT = 1; Clear PINT */ - | SSSR_ROR /* ROR = 1; Clear ROR */ - ; - -/* - * MEP Query $22: Touchpad Coordinate Range Query is not supported by - * the NavPoint module, so sampled values provide the default limits. - */ -#define NAVPOINT_X_MIN 1278 -#define NAVPOINT_X_MAX 5340 -#define NAVPOINT_Y_MIN 1572 -#define NAVPOINT_Y_MAX 4396 -#define NAVPOINT_PRESSURE_MIN 0 -#define NAVPOINT_PRESSURE_MAX 255 - -static void navpoint_packet(struct navpoint *navpoint) -{ - int finger; - int gesture; - int x, y, z; - - switch (navpoint->data[0]) { - case 0xff: /* Garbage (packet?) between reset and Hello packet */ - case 0x00: /* Module 0, NULL packet */ - break; - - case 0x0e: /* Module 0, Absolute packet */ - finger = (navpoint->data[1] & 0x01); - gesture = (navpoint->data[1] & 0x02); - x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3]; - y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5]; - z = navpoint->data[6]; - input_report_key(navpoint->input, BTN_TOUCH, finger); - input_report_abs(navpoint->input, ABS_X, x); - input_report_abs(navpoint->input, ABS_Y, y); - input_report_abs(navpoint->input, ABS_PRESSURE, z); - input_report_key(navpoint->input, BTN_TOOL_FINGER, finger); - input_report_key(navpoint->input, BTN_LEFT, gesture); - input_sync(navpoint->input); - break; - - case 0x19: /* Module 0, Hello packet */ - if ((navpoint->data[1] & 0xf0) == 0x10) - break; - fallthrough; - default: - dev_warn(navpoint->dev, - "spurious packet: data=0x%02x,0x%02x,...\n", - navpoint->data[0], navpoint->data[1]); - break; - } -} - -static irqreturn_t navpoint_irq(int irq, void *dev_id) -{ - struct navpoint *navpoint = dev_id; - struct ssp_device *ssp = navpoint->ssp; - irqreturn_t ret = IRQ_NONE; - u32 status; - - status = pxa_ssp_read_reg(ssp, SSSR); - if (status & sssr) { - dev_warn(navpoint->dev, - "unexpected interrupt: status=0x%08x\n", status); - pxa_ssp_write_reg(ssp, SSSR, (status & sssr)); - ret = IRQ_HANDLED; - } - - while (status & SSSR_RNE) { - u32 data; - - data = pxa_ssp_read_reg(ssp, SSDR); - navpoint->data[navpoint->index + 0] = (data >> 8); - navpoint->data[navpoint->index + 1] = data; - navpoint->index += 2; - if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) { - navpoint_packet(navpoint); - navpoint->index = 0; - } - status = pxa_ssp_read_reg(ssp, SSSR); - ret = IRQ_HANDLED; - } - - return ret; -} - -static void navpoint_up(struct navpoint *navpoint) -{ - struct ssp_device *ssp = navpoint->ssp; - int timeout; - - clk_prepare_enable(ssp->clk); - - pxa_ssp_write_reg(ssp, SSCR1, sscr1); - pxa_ssp_write_reg(ssp, SSSR, sssr); - pxa_ssp_write_reg(ssp, SSTO, 0); - pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */ - - /* Wait until SSP port is ready for slave clock operations */ - for (timeout = 100; timeout != 0; --timeout) { - if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS)) - break; - msleep(1); - } - - if (timeout == 0) - dev_err(navpoint->dev, - "timeout waiting for SSSR[CSS] to clear\n"); - - gpiod_set_value(navpoint->gpiod, 1); -} - -static void navpoint_down(struct navpoint *navpoint) -{ - struct ssp_device *ssp = navpoint->ssp; - - gpiod_set_value(navpoint->gpiod, 0); - - pxa_ssp_write_reg(ssp, SSCR0, 0); - - clk_disable_unprepare(ssp->clk); -} - -static int navpoint_open(struct input_dev *input) -{ - struct navpoint *navpoint = input_get_drvdata(input); - - navpoint_up(navpoint); - - return 0; -} - -static void navpoint_close(struct input_dev *input) -{ - struct navpoint *navpoint = input_get_drvdata(input); - - navpoint_down(navpoint); -} - -static int navpoint_probe(struct platform_device *pdev) -{ - const struct navpoint_platform_data *pdata = - dev_get_platdata(&pdev->dev); - struct ssp_device *ssp; - struct input_dev *input; - struct navpoint *navpoint; - int error; - - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - - ssp = pxa_ssp_request(pdata->port, pdev->name); - if (!ssp) - return -ENODEV; - - /* HaRET does not disable devices before jumping into Linux */ - if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) { - pxa_ssp_write_reg(ssp, SSCR0, 0); - dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port); - } - - navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL); - input = input_allocate_device(); - if (!navpoint || !input) { - error = -ENOMEM; - goto err_free_mem; - } - - navpoint->gpiod = gpiod_get_optional(&pdev->dev, - NULL, GPIOD_OUT_LOW); - if (IS_ERR(navpoint->gpiod)) { - error = PTR_ERR(navpoint->gpiod); - dev_err(&pdev->dev, "error getting GPIO\n"); - goto err_free_mem; - } - gpiod_set_consumer_name(navpoint->gpiod, "SYNAPTICS_ON"); - - navpoint->ssp = ssp; - navpoint->input = input; - navpoint->dev = &pdev->dev; - - input->name = pdev->name; - input->dev.parent = &pdev->dev; - - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_LEFT, input->keybit); - __set_bit(BTN_TOUCH, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - - input_set_abs_params(input, ABS_X, - NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0); - input_set_abs_params(input, ABS_Y, - NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0); - input_set_abs_params(input, ABS_PRESSURE, - NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX, - 0, 0); - - input->open = navpoint_open; - input->close = navpoint_close; - - input_set_drvdata(input, navpoint); - - error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint); - if (error) - goto err_free_mem; - - error = input_register_device(input); - if (error) - goto err_free_irq; - - platform_set_drvdata(pdev, navpoint); - dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq); - - return 0; - -err_free_irq: - free_irq(ssp->irq, navpoint); -err_free_mem: - input_free_device(input); - kfree(navpoint); - pxa_ssp_free(ssp); - - return error; -} - -static void navpoint_remove(struct platform_device *pdev) -{ - struct navpoint *navpoint = platform_get_drvdata(pdev); - struct ssp_device *ssp = navpoint->ssp; - - free_irq(ssp->irq, navpoint); - - input_unregister_device(navpoint->input); - kfree(navpoint); - - pxa_ssp_free(ssp); -} - -static int navpoint_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct navpoint *navpoint = platform_get_drvdata(pdev); - struct input_dev *input = navpoint->input; - - mutex_lock(&input->mutex); - if (input_device_enabled(input)) - navpoint_down(navpoint); - mutex_unlock(&input->mutex); - - return 0; -} - -static int navpoint_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct navpoint *navpoint = platform_get_drvdata(pdev); - struct input_dev *input = navpoint->input; - - mutex_lock(&input->mutex); - if (input_device_enabled(input)) - navpoint_up(navpoint); - mutex_unlock(&input->mutex); - - return 0; -} - -static DEFINE_SIMPLE_DEV_PM_OPS(navpoint_pm_ops, - navpoint_suspend, navpoint_resume); - -static struct platform_driver navpoint_driver = { - .probe = navpoint_probe, - .remove_new = navpoint_remove, - .driver = { - .name = "navpoint", - .pm = pm_sleep_ptr(&navpoint_pm_ops), - }, -}; - -module_platform_driver(navpoint_driver); - -MODULE_AUTHOR("Paul Parsons "); -MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:navpoint"); diff --git a/include/linux/input/navpoint.h b/include/linux/input/navpoint.h deleted file mode 100644 index 5192ae3f5ec1..000000000000 --- a/include/linux/input/navpoint.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2012 Paul Parsons - */ - -struct navpoint_platform_data { - int port; /* PXA SSP port for pxa_ssp_request() */ -}; From bc4996184d56cfaf56d3811ac2680c8a0e2af56e Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Thu, 18 Jan 2024 11:37:59 -0800 Subject: [PATCH 002/814] Input: synaptics-rmi4 - fail probing if memory allocation for "phys" fails While input core can work with input->phys set to NULL userspace might depend on it, so better fail probing if allocation fails. The system must be in a pretty bad shape for it to happen anyway. Signed-off-by: Kunwu Chan Link: https://lore.kernel.org/r/20240117073124.143636-1-chentao@kylinos.cn Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 258d5fe3d395..aa32371f04af 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -1196,7 +1196,11 @@ static int rmi_driver_probe(struct device *dev) } rmi_driver_set_input_params(rmi_dev, data->input); data->input->phys = devm_kasprintf(dev, GFP_KERNEL, - "%s/input0", dev_name(dev)); + "%s/input0", dev_name(dev)); + if (!data->input->phys) { + retval = -ENOMEM; + goto err; + } } retval = rmi_init_functions(data); From 2a992413a112c8411e2eb0b31ca8d6d523a8dbe8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 15 Jan 2024 21:19:04 +0100 Subject: [PATCH 003/814] Input: remove usage of the deprecated ida_simple_xx() API ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove(). Note that the upper limit of ida_simple_get() is exclusive, but the one of ida_alloc_range() is inclusive. So a -1 has been added when needed. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/a885de14beead2cc3c1c946f192b8b178dac696a.1705349930.git.christophe.jaillet@wanadoo.fr Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index f71ea4fb173f..de7884a5be39 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2629,17 +2629,15 @@ int input_get_new_minor(int legacy_base, unsigned int legacy_num, * locking is needed here. */ if (legacy_base >= 0) { - int minor = ida_simple_get(&input_ida, - legacy_base, - legacy_base + legacy_num, - GFP_KERNEL); + int minor = ida_alloc_range(&input_ida, legacy_base, + legacy_base + legacy_num - 1, + GFP_KERNEL); if (minor >= 0 || !allow_dynamic) return minor; } - return ida_simple_get(&input_ida, - INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES, - GFP_KERNEL); + return ida_alloc_range(&input_ida, INPUT_FIRST_DYNAMIC_DEV, + INPUT_MAX_CHAR_DEVICES - 1, GFP_KERNEL); } EXPORT_SYMBOL(input_get_new_minor); @@ -2652,7 +2650,7 @@ EXPORT_SYMBOL(input_get_new_minor); */ void input_free_minor(unsigned int minor) { - ida_simple_remove(&input_ida, minor); + ida_free(&input_ida, minor); } EXPORT_SYMBOL(input_free_minor); From 8bafa2f2eab86db491f9b5010825c3ca8a4127c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 15 Jan 2024 19:20:57 +0100 Subject: [PATCH 004/814] dt-bindings: input: silead,gsl1680: do not override firmware-name $ref dtschema package defines firmware-name as string-array, so individual bindings should not make it a string but instead just narrow the number of expected firmware file names. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240115182057.1610195-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/silead,gsl1680.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead,gsl1680.yaml b/Documentation/devicetree/bindings/input/touchscreen/silead,gsl1680.yaml index 95b554be25b4..5381a96f4949 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/silead,gsl1680.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/silead,gsl1680.yaml @@ -31,7 +31,7 @@ properties: maxItems: 1 firmware-name: - $ref: /schemas/types.yaml#/definitions/string + maxItems: 1 description: > File basename for board specific firmware From 8109e032cf07af15d3bba860ce554cc258dcff67 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Wed, 9 Aug 2023 18:16:26 +0800 Subject: [PATCH 005/814] Input: bcm-keypad - 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 Link: https://lore.kernel.org/r/20230809101626.2664651-1-ruanjinjie@huawei.com 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 f3c3746acd4c..6b46f83a9edb 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -418,7 +418,7 @@ static struct platform_driver bcm_kp_device_driver = { .probe = bcm_kp_probe, .driver = { .name = "bcm-keypad", - .of_match_table = of_match_ptr(bcm_kp_of_match), + .of_match_table = bcm_kp_of_match, } }; From d259f137461b9067ff46a10922e66a6e9fc38e12 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Tue, 2 Jan 2024 09:19:34 +0100 Subject: [PATCH 006/814] dt-bindings: input: touchscreen: goodix: clarify irq-gpios misleading text The irq-gpios description misleading, apparently saying that driving the IRQ GPIO resets the device, which is even more puzzling as there is a reset GPIO as well. In reality the IRQ pin can be driven during the reset sequence to configure the client address, as it becomes clear after checking both the datasheet and the driver code. Improve the text to clarify that. Also rephrase to remove reference to the driver, which is not appropriate in the bindings. Signed-off-by: Luca Ceresoli Acked-by: Rob Herring Reviewed-by: Jeff LaBundy Link: https://lore.kernel.org/r/20240102081934.11293-1-luca.ceresoli@bootlin.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/goodix.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml b/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml index 3d016b87c8df..2a2d86cfd104 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml @@ -37,8 +37,9 @@ properties: maxItems: 1 irq-gpios: - description: GPIO pin used for IRQ. The driver uses the interrupt gpio pin - as output to reset the device. + description: GPIO pin used for IRQ input. Additionally, this line is + sampled by the device on reset deassertion to select the I2C client + address, thus it can be driven by the host during the reset sequence. maxItems: 1 reset-gpios: From 698b43780ba2b0566c6940f0ebb65b14f2f99f5f Mon Sep 17 00:00:00 2001 From: Bernhard Seibold Date: Sat, 13 Jan 2024 11:37:42 +0100 Subject: [PATCH 007/814] Input: leds - set default-trigger for mute Set the default-trigger for the mute led to audio-mute. Signed-off-by: Bernhard Seibold Link: https://lore.kernel.org/r/20240113103743.97205-1-mail@bernhard-seibold.de Signed-off-by: Dmitry Torokhov --- drivers/input/input-leds.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 0e935914bc3a..b16fc81940f5 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -18,6 +18,12 @@ #define VT_TRIGGER(_name) .trigger = NULL #endif +#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO) +#define AUDIO_TRIGGER(_name) .trigger = _name +#else +#define AUDIO_TRIGGER(_name) .trigger = NULL +#endif + static const struct { const char *name; const char *trigger; @@ -29,7 +35,7 @@ static const struct { [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") }, [LED_SLEEP] = { "sleep" } , [LED_SUSPEND] = { "suspend" }, - [LED_MUTE] = { "mute" }, + [LED_MUTE] = { "mute", AUDIO_TRIGGER("audio-mute") }, [LED_MISC] = { "misc" }, [LED_MAIL] = { "mail" }, [LED_CHARGING] = { "charging" }, From 9f8bbb531a17c5afcc3a02d92f64194819178254 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Nov 2023 16:10:08 -0600 Subject: [PATCH 008/814] dt-bindings: Turn on undocumented compatible checks The undocumented compatibles in the examples are down to just a few left. Turn on the warning by default. The increased visibility should get the remaining warnings fixed. Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231128221008.4050638-2-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile index 2323fd5b7cda..7653ac50e3b1 100644 --- a/Documentation/devicetree/bindings/Makefile +++ b/Documentation/devicetree/bindings/Makefile @@ -61,9 +61,6 @@ override DTC_FLAGS := \ -Wno-unique_unit_address \ -Wunique_unit_address_if_enabled -# Disable undocumented compatible checks until warning free -override DT_CHECKER_FLAGS ?= - $(obj)/processed-schema.json: $(DT_DOCS) $(src)/.yamllint check_dtschema_version FORCE $(call if_changed_rule,chkdt) From ed3648d264c7f95c7ae0a13d98da0da2018a5bbd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 8 Jan 2024 09:37:49 +0100 Subject: [PATCH 009/814] docs: dt: submitting-patches: drop outdated points to TXT format New bindings in TXT format are not accepted and DT schema format expects all compatibles to be explicitly defined, thus guidance about "wildcard " is not correct anymore. Drop that paragraph and update one more place which still mentions TXT files. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240108083750.16350-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/submitting-patches.rst | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/submitting-patches.rst b/Documentation/devicetree/bindings/submitting-patches.rst index 36a17b250ccc..b460ebffee42 100644 --- a/Documentation/devicetree/bindings/submitting-patches.rst +++ b/Documentation/devicetree/bindings/submitting-patches.rst @@ -42,28 +42,18 @@ I. For patch submitters the code implementing the binding. 6) Any compatible strings used in a chip or board DTS file must be - previously documented in the corresponding DT binding text file + previously documented in the corresponding DT binding file in Documentation/devicetree/bindings. This rule applies even if the Linux device driver does not yet match on the compatible string. [ checkpatch will emit warnings if this step is not followed as of commit bff5da4335256513497cc8c79f9a9d1665e09864 ("checkpatch: add DT compatible string documentation checks"). ] - 7) The wildcard "" may be used in compatible strings, as in - the following example: - - - compatible: Must contain '"nvidia,-pcie", - "nvidia,tegra20-pcie"' where is tegra30, tegra132, ... - - As in the above example, the known values of "" should be - documented if it is used. - - 8) If a documented compatible string is not yet matched by the + 7) If a documented compatible string is not yet matched by the driver, the documentation should also include a compatible - string that is matched by the driver (as in the "nvidia,tegra20-pcie" - example above). + string that is matched by the driver. - 9) Bindings are actively used by multiple projects other than the Linux + 8) Bindings are actively used by multiple projects other than the Linux Kernel, extra care and consideration may need to be taken when making changes to existing bindings. From 9c08be64059e562b2ddcfe884ab35610117e6371 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 8 Jan 2024 09:37:50 +0100 Subject: [PATCH 010/814] docs: dt: submitting-patches: add commit subject prefix in reversed format ASoC, media, regulators and SPI subsystems prefer commits starting with subsystem name (e.g. "spi: dt-bindings:"), so document this to avoid confusing contributors. Cc: Mark Brown Cc: Mauro Carvalho Chehab Signed-off-by: Krzysztof Kozlowski Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20240108083750.16350-2-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/submitting-patches.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/submitting-patches.rst b/Documentation/devicetree/bindings/submitting-patches.rst index b460ebffee42..a64f21a5f299 100644 --- a/Documentation/devicetree/bindings/submitting-patches.rst +++ b/Documentation/devicetree/bindings/submitting-patches.rst @@ -15,6 +15,11 @@ I. For patch submitters "dt-bindings: : ..." + Few subsystems, like ASoC, media, regulators and SPI, expect reverse order + of the prefixes:: + + ": dt-bindings: ..." + The 80 characters of the subject are precious. It is recommended to not use "Documentation" or "doc" because that is implied. All bindings are docs. Repeating "binding" again should also be avoided. From 3b8435db840cde070fa78a777fa20b098b9abc87 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Tue, 16 Jan 2024 12:37:33 -0600 Subject: [PATCH 011/814] dt-bindings: Add DPS310 as trivial device Infineon DPS310 is a barometric pressure and temperature sensor. Acked-by: Krzysztof Kozlowski Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20240116183734.3944028-3-ninad@linux.ibm.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 79dcd92c4a43..5b52950e6bfc 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -137,6 +137,8 @@ properties: - ibm,cffps1 # IBM Common Form Factor Power Supply Versions 2 - ibm,cffps2 + # Infineon barometric pressure and temperature sensor + - infineon,dps310 # Infineon IR36021 digital POL buck controller - infineon,ir36021 # Infineon IR38060 Voltage Regulator From e20cd62b1f1708a4dec7ff4beb9e748a0bdb5716 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 17 Jan 2024 09:32:06 +0100 Subject: [PATCH 012/814] of: property: Make 'no port node found' output a debug message There are cases where an unavailable port is not an error, making this error message a false-positive. Since commit d56de8c9a17d8 ("usb: typec: tcpm: try to get role switch from tcpc fwnode") the role switch is tried on the port dev first and tcpc fwnode afterwards. If using the latter bindings getting from port dev fails every time. The kernel log is flooded with the messages like: OF: graph: no port node found in /soc@0/bus@42000000/i2c@42530000/usb-typec@50 Silence this message by making it a debug message. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20240117083206.2901534-1-alexander.stein@ew.tq-group.com Signed-off-by: Rob Herring --- drivers/of/property.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/property.c b/drivers/of/property.c index 641a40cf5cf3..a02a985c13ba 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -665,7 +665,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, of_node_put(node); if (!port) { - pr_err("graph: no port node found in %pOF\n", parent); + pr_debug("graph: no port node found in %pOF\n", parent); return NULL; } } else { From ab30e1a93c07bab9374fac83fdde9bf5794da2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Mon, 22 Jan 2024 11:13:17 -0800 Subject: [PATCH 013/814] Input: 88pm80x_onkey - add SPDX and drop GPL boilerplate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a SPDX-License-Identifier to the 88PM80x onkey driver and drop the GPL boilerplate in accordance with current kernel code guidelines. Signed-off-by: Duje Mihanović Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240121-88pm80x-onkey-spdx-v1-1-b646d4749f5b@skole.hr Signed-off-by: Dmitry Torokhov --- drivers/input/misc/88pm80x_onkey.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 31f0702c3d01..4b0685f96113 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell 88PM80x ONKEY driver * * Copyright (C) 2012 Marvell International Ltd. * Haojian Zhuang * Qiao Zhou - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include From 1cf2bf8ffadf2f0ab9ad10a1e0f65b3a0a10d402 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Sun, 21 Jan 2024 17:57:43 +0100 Subject: [PATCH 014/814] dt-bindings: phy: Add QMP UFS PHY compatible for SC7180 Document the QMP UFS PHY compatible for SC7180 Acked-by: Rob Herring Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20240121-sm7125-upstream-v4-3-f7d1212c8ebb@gmail.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) 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 8474eef8d0ff..5faa1cb3a12e 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -19,6 +19,7 @@ properties: - qcom,msm8996-qmp-ufs-phy - qcom,msm8998-qmp-ufs-phy - qcom,sa8775p-qmp-ufs-phy + - qcom,sc7180-qmp-ufs-phy - qcom,sc7280-qmp-ufs-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy @@ -102,6 +103,7 @@ allOf: contains: enum: - qcom,msm8998-qmp-ufs-phy + - qcom,sc7180-qmp-ufs-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy - qcom,sdm845-qmp-ufs-phy From 7551d945cb9ad8e8cfa4888c6b7be19855754baf Mon Sep 17 00:00:00 2001 From: David Wronek Date: Sun, 21 Jan 2024 17:57:45 +0100 Subject: [PATCH 015/814] phy: qcom: qmp-ufs: Add SC7180 support The SC7180 UFS PHY is identical to the one found on SM7150. Add a compatible for it. Reviewed-by: Dmitry Baryshkov Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20240121-sm7125-upstream-v4-5-f7d1212c8ebb@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 3c2e6255e26f..0276de802d78 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1880,6 +1880,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { }, { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = &sa8775p_ufsphy_cfg, + }, { + .compatible = "qcom,sc7180-qmp-ufs-phy", + .data = &sm7150_ufsphy_cfg, }, { .compatible = "qcom,sc7280-qmp-ufs-phy", .data = &sc7280_ufsphy_cfg, From b34ae8598c9c3a95e7f8eaeaa1fcf6fdba0aef68 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 25 Dec 2023 18:31:30 -0800 Subject: [PATCH 016/814] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550 On SM8550, two sets of UFS PHY settings are provided, one set is to support HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY settings are programming different values to different registers, mixing the two sets and/or overwriting one set with another set is definitely not blessed by UFS PHY designers. To add HS-G5 support for SM8550, split the two sets of PHY settings into their dedicated overlay tables, only the common parts of the two sets of PHY settings are left in the .tbls. Consider we are going to add even higher gear support in future, to avoid adding more tables with different names, rename the .tbls_hs_g4 and make it an array, a size of 2 is enough as of now. In this case, .tbls alone is not a complete set of PHY settings, so either tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the .tbls to become a complete set of PHY settings. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1703557892-1822-1-git-send-email-quic_cang@quicinc.com Signed-off-by: Vinod Koul --- .../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 + .../qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 + .../phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 8 + drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 169 +++++++++++++++--- 4 files changed, 159 insertions(+), 22 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h index fe6c450f6123..970cc0667809 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h @@ -19,6 +19,7 @@ #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060 #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158 #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184 @@ -28,5 +29,6 @@ #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8 #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4 #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220 #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h index ec7291424dd1..328c6c0b0b09 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h @@ -60,6 +60,8 @@ #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8 #define QSERDES_V6_COM_PLL_IVCO 0xf4 #define QSERDES_V6_COM_PLL_IVCO_MODE1 0xf8 +#define QSERDES_V6_COM_CMN_IETRIM 0xfc +#define QSERDES_V6_COM_CMN_IPTRIM 0x100 #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110 #define QSERDES_V6_COM_RESETSM_CNTRL 0x118 #define QSERDES_V6_COM_LOCK_CMP_EN 0x120 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h index 35d497fd9f9a..d9a87bd95590 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h @@ -15,13 +15,19 @@ #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08 #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24 #define QSERDES_UFS_V6_RX_UCDR_SO_SATURATION 0x28 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54 #define QSERDES_UFS_V6_RX_UCDR_PI_CTRL1 0x58 #define QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0 0xc4 #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4 #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0 +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4 #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178 +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc #define QSERDES_UFS_V6_RX_INTERFACE_MODE 0x1e0 +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214 @@ -33,6 +39,8 @@ #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264 #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270 #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284 #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8 #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 0276de802d78..490f4cecf054 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -41,6 +41,8 @@ #define PHY_INIT_COMPLETE_TIMEOUT 10000 +#define NUM_OVERLAY 2 + struct qmp_phy_init_tbl { unsigned int offset; unsigned int val; @@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), @@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07), }; -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), @@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), }; +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), +}; + static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), }; +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), +}; + static const struct qmp_phy_init_tbl sm8650_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), @@ -889,6 +932,8 @@ struct qmp_phy_cfg_tbls { int rx_num; const struct qmp_phy_init_tbl *pcs; int pcs_num; + /* Maximum supported Gear of this tbls */ + u32 max_gear; }; /* struct qmp_phy_cfg - per-PHY initialization config */ @@ -896,13 +941,15 @@ struct qmp_phy_cfg { int lanes; const struct qmp_ufs_offsets *offsets; + /* Maximum supported Gear of this config */ + u32 max_supported_gear; /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_cfg_tbls tbls; /* Additional sequence for HS Series B */ const struct qmp_phy_cfg_tbls tbls_hs_b; - /* Additional sequence for HS G4 */ - const struct qmp_phy_cfg_tbls tbls_hs_g4; + /* Additional sequence for different HS Gears */ + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; /* clock ids to be requested */ const char * const *clk_list; @@ -1005,6 +1052,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = msm8996_ufsphy_serdes, @@ -1030,6 +1078,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1045,13 +1094,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sm8450_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), @@ -1064,6 +1114,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1079,13 +1130,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sc7280_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sm8450_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), @@ -1098,6 +1150,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1113,13 +1166,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sdm845_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), @@ -1132,6 +1186,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1160,6 +1215,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sm6115_ufsphy_serdes, @@ -1188,6 +1244,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1216,6 +1273,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1231,13 +1289,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8150_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx), .rx = sm8150_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sdm845_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), @@ -1250,6 +1309,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1265,13 +1325,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sm8250_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sdm845_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), @@ -1284,6 +1345,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1299,13 +1361,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sdm845_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), @@ -1318,6 +1381,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1333,13 +1397,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, .clk_list = sm8450_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), @@ -1352,6 +1417,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8550_ufsphy_serdes, @@ -1367,6 +1433,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .serdes = sm8550_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), }, + .tbls_hs_overlay[0] = { + .serdes = sm8550_ufsphy_g4_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes), + .tx = sm8550_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx), + .rx = sm8550_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx), + .pcs = sm8550_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .tbls_hs_overlay[1] = { + .serdes = sm8550_ufsphy_g5_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes), + .rx = sm8550_ufsphy_g5_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx), + .pcs = sm8550_ufsphy_g5_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs), + .max_gear = UFS_HS_G5, + }, .clk_list = sdm845_ufs_phy_clk_l, .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, @@ -1378,6 +1464,7 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8650_ufsphy_serdes, @@ -1451,17 +1538,49 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num); } +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) +{ + u32 max_gear, floor_max_gear = cfg->max_supported_gear; + int idx, ret = -EINVAL; + + for (idx = NUM_OVERLAY - 1; idx >= 0; idx--) { + max_gear = cfg->tbls_hs_overlay[idx].max_gear; + + /* Skip if the table is not available */ + if (max_gear == 0) + continue; + + /* Direct matching, bail */ + if (qmp->submode == max_gear) + return idx; + + /* If no direct matching, the lowest gear is the best matching */ + if (max_gear < floor_max_gear) { + ret = idx; + floor_max_gear = max_gear; + } + } + + return ret; +} + static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) { + int i; + qmp_ufs_serdes_init(qmp, &cfg->tbls); + qmp_ufs_lanes_init(qmp, &cfg->tbls); + qmp_ufs_pcs_init(qmp, &cfg->tbls); + + i = qmp_ufs_get_gear_overlay(qmp, cfg); + if (i >= 0) { + qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]); + qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]); + qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]); + } + if (qmp->mode == PHY_MODE_UFS_HS_B) qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b); - qmp_ufs_lanes_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4); - qmp_ufs_pcs_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4); } static int qmp_ufs_com_init(struct qmp_ufs *qmp) @@ -1633,6 +1752,12 @@ static int qmp_ufs_disable(struct phy *phy) static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_ufs *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + if (submode > cfg->max_supported_gear || submode == 0) { + dev_err(qmp->dev, "Invalid PHY submode %d\n", submode); + return -EINVAL; + } qmp->mode = mode; qmp->submode = submode; From 159919a184c5ef82fac3605b2390b17a549c06ac Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 13 Jan 2024 22:55:46 +0200 Subject: [PATCH 017/814] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: split from sc8280xp PHY schema In preparation to defining the USB-C handling on MSM8998, QCM2290 and SM6115 split existing QMP USB3 PHY schema into pure USB3 and USB-C schema definitions. Signed-off-by: Dmitry Baryshkov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-3-182d9aa0a5b3@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,msm8998-qmp-usb3-phy.yaml | 132 ++++++++++++++++++ .../phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml | 22 --- 2 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml new file mode 100644 index 000000000000..868fabd44d72 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,msm8998-qmp-usb3-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP PHY controller (USB, MSM8998) + +maintainers: + - Vinod Koul + +description: + The QMP PHY controller supports physical layer functionality for USB-C on + several Qualcomm chipsets. + +properties: + compatible: + enum: + - qcom,msm8998-qmp-usb3-phy + - qcom,qcm2290-qmp-usb3-phy + - qcom,sm6115-qmp-usb3-phy + + reg: + maxItems: 1 + + clocks: + maxItems: 4 + + clock-names: + maxItems: 4 + + resets: + maxItems: 2 + + reset-names: + items: + - const: phy + - const: phy_phy + + vdda-phy-supply: true + + vdda-pll-supply: true + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + - "#clock-cells" + - clock-output-names + - "#phy-cells" + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-usb3-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: aux + - const: ref + - const: cfg_ahb + - const: pipe + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcm2290-qmp-usb3-phy + - qcom,sm6115-qmp-usb3-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: cfg_ahb + - const: ref + - const: com_aux + - const: pipe + +additionalProperties: false + +examples: + - | + #include + #include + + phy@c010000 { + compatible = "qcom,msm8998-qmp-usb3-phy"; + reg = <0x0c010000 0x1000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; + + vdda-phy-supply = <&vreg_l1a_0p875>; + vdda-pll-supply = <&vreg_l2a_1p2>; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml index 15d82c67f157..1e2d4ddc5391 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml @@ -20,15 +20,12 @@ properties: - qcom,ipq8074-qmp-usb3-phy - qcom,ipq9574-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy - - qcom,msm8998-qmp-usb3-phy - - qcom,qcm2290-qmp-usb3-phy - qcom,sa8775p-qmp-usb3-uni-phy - qcom,sc8280xp-qmp-usb3-uni-phy - qcom,sdm845-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy - qcom,sdx75-qmp-usb3-uni-phy - - qcom,sm6115-qmp-usb3-phy - qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8250-qmp-usb3-uni-phy - qcom,sm8350-qmp-usb3-uni-phy @@ -93,7 +90,6 @@ allOf: - qcom,ipq8074-qmp-usb3-phy - qcom,ipq9574-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy - - qcom,msm8998-qmp-usb3-phy - qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy - qcom,sdx75-qmp-usb3-uni-phy @@ -108,24 +104,6 @@ allOf: - const: cfg_ahb - const: pipe - - if: - properties: - compatible: - contains: - enum: - - qcom,qcm2290-qmp-usb3-phy - - qcom,sm6115-qmp-usb3-phy - then: - properties: - clocks: - maxItems: 4 - clock-names: - items: - - const: cfg_ahb - - const: ref - - const: com_aux - - const: pipe - - if: properties: compatible: From c1214b579733df7017c0e5f97f26eeb4b66df0c6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 13 Jan 2024 22:55:47 +0200 Subject: [PATCH 018/814] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: support USB-C data Extend the Qualcomm USB-C QMP PHY schema with the USB-C related entry points: orientation-switch property and USB-C connection graph. Reviewed-by: Bryan O'Donoghue Signed-off-by: Dmitry Baryshkov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-4-182d9aa0a5b3@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,msm8998-qmp-usb3-phy.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml index 868fabd44d72..da5d4cbca24c 100644 --- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml @@ -50,6 +50,22 @@ properties: "#phy-cells": const: 0 + orientation-switch: + description: + Flag the PHY as possible handler of USB Type-C orientation switching + type: boolean + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Output endpoint of the PHY + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Incoming endpoint from the USB controller + required: - compatible - reg @@ -129,4 +145,27 @@ examples: vdda-phy-supply = <&vreg_l1a_0p875>; vdda-pll-supply = <&vreg_l2a_1p2>; + + orientation-switch; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + endpoint { + remote-endpoint = <&pmic_typec_mux_in>; + }; + }; + + port@1 { + reg = <1>; + + endpoint { + remote-endpoint = <&usb_dwc3_ss>; + }; + }; + }; }; From 19281571a4d5b6049dad9318db081af48818b1d2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 13 Jan 2024 22:55:53 +0200 Subject: [PATCH 019/814] phy: qcom: qmp-usb: split USB-C PHY driver In preparation to adding Type-C handling for MSM8998, QCM2290 and SM6115 platforms, create new QMP USB-C PHY driver by splitting mentioned platforms to a separate file. In future it will also be extended with support for the DisplayPort handling. It will also be reused later for such platforms as SDM660, SM6125, SM6150. Signed-off-by: Dmitry Baryshkov Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-10-182d9aa0a5b3@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/Makefile | 2 +- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 266 ------ drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 1078 ++++++++++++++++++++++ 3 files changed, 1079 insertions(+), 267 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-usbc.c diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index ffd609ac6233..eb60e950ad53 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o -obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o +obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o 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 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index 243cc2b9a0fb..c7698369d3dc 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -121,15 +121,6 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_MISC_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, }; -static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[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, @@ -514,115 +505,6 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), }; -static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), - 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_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), - 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 msm8998_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_TX, 0x00), -}; - -static const struct qmp_phy_init_tbl msm8998_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, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), -}; - -static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { - 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), - 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_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, 0x0d), - 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_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_RX_SIGDET_LVL, 0x8a), - 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_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), @@ -1089,99 +971,6 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_usb_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), }; -static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), -}; - -static const struct qmp_phy_init_tbl qcm2290_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, 0xc6), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), -}; - -static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), - 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_VGA_CAL_CNTRL2, 0x0a), - 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_SIGDET_ENABLES, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), -}; - -static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), - 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, 0x85), - 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_RXEQTRAINING_WAIT_TIME, 0x75), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), - 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_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_RX_SIGDET_LVL, 0x88), -}; - static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), @@ -1571,16 +1360,6 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v3 = { .rx = 0x400, }; -static const struct qmp_usb_offsets qmp_usb_offsets_v3_qcm2290 = { - .serdes = 0x0, - .pcs = 0xc00, - .pcs_misc = 0xa00, - .tx = 0x200, - .rx = 0x400, - .tx2 = 0x600, - .rx2 = 0x800, -}; - static const struct qmp_usb_offsets qmp_usb_offsets_v4 = { .serdes = 0, .pcs = 0x0800, @@ -1727,24 +1506,6 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { - .lanes = 2, - - .offsets = &qmp_usb_offsets_v3_qcm2290, - - .serdes_tbl = msm8998_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), - .tx_tbl = msm8998_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), - .rx_tbl = msm8998_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), - .pcs_tbl = msm8998_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), - .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_usb3_uniphy_cfg = { .lanes = 1, @@ -1882,24 +1643,6 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { - .lanes = 2, - - .offsets = &qmp_usb_offsets_v3_qcm2290, - - .serdes_tbl = qcm2290_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), - .tx_tbl = qcm2290_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), - .rx_tbl = qcm2290_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), - .pcs_tbl = qcm2290_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v3_usb3phy_regs_layout_qcm2290, -}; - static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { .lanes = 1, @@ -2573,12 +2316,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = { }, { .compatible = "qcom,msm8996-qmp-usb3-phy", .data = &msm8996_usb3phy_cfg, - }, { - .compatible = "qcom,msm8998-qmp-usb3-phy", - .data = &msm8998_usb3phy_cfg, - }, { - .compatible = "qcom,qcm2290-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, }, { .compatible = "qcom,sa8775p-qmp-usb3-uni-phy", .data = &sa8775p_usb3_uniphy_cfg, @@ -2597,9 +2334,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = { }, { .compatible = "qcom,sdx75-qmp-usb3-uni-phy", .data = &sdx75_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sm6115-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, }, { .compatible = "qcom,sm8150-qmp-usb3-uni-phy", .data = &sm8150_usb3_uniphy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c new file mode 100644 index 000000000000..52f1b3f7b81e --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -0,0 +1,1078 @@ +// 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 "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-misc-v3.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, + QPHY_PCS_MISC_CLAMP_ENABLE, + /* 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, + [QPHY_PCS_MISC_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, +}; + +static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[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 struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + 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_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), + 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 msm8998_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_TX, 0x00), +}; + +static const struct qmp_phy_init_tbl msm8998_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, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { + 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), + 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_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, 0x0d), + 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_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_RX_SIGDET_LVL, 0x8a), + 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 qcm2290_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), +}; + +static const struct qmp_phy_init_tbl qcm2290_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, 0xc6), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + 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_VGA_CAL_CNTRL2, 0x0a), + 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_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + 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, 0x85), + 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_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + 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_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_RX_SIGDET_LVL, 0x88), +}; + +struct qmp_usbc_offsets { + u16 serdes; + u16 pcs; + u16 pcs_misc; + u16 tx; + u16 rx; + /* for PHYs with >= 2 lanes */ + u16 tx2; + u16 rx2; +}; + +/* struct qmp_phy_cfg - per-PHY initialization config */ +struct qmp_phy_cfg { + const struct qmp_usbc_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; + + /* regulators to be requested */ + const char * const *vreg_list; + int num_vregs; + + /* array of registers with different offsets */ + const unsigned int *regs; + + /* true, if PHY needs delay after POWER_DOWN */ + bool has_pwrdn_delay; +}; + +struct qmp_usbc { + struct device *dev; + + const struct qmp_phy_cfg *cfg; + + void __iomem *serdes; + void __iomem *pcs; + void __iomem *pcs_misc; + void __iomem *tx; + void __iomem *rx; + void __iomem *tx2; + void __iomem *rx2; + + struct clk *pipe_clk; + struct clk_bulk_data *clks; + int num_clks; + int num_resets; + 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_usbc_phy_clk_l[] = { + "aux", "cfg_ahb", "ref", "com_aux", +}; + +/* list of resets */ +static const char * const usb3phy_legacy_reset_l[] = { + "phy", "common", +}; + +static const char * const usb3phy_reset_l[] = { + "phy_phy", "phy", +}; + +/* list of regulators */ +static const char * const qmp_phy_vreg_l[] = { + "vdda-phy", "vdda-pll", +}; + +static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { + .serdes = 0x0, + .pcs = 0xc00, + .pcs_misc = 0xa00, + .tx = 0x200, + .rx = 0x400, + .tx2 = 0x600, + .rx2 = 0x800, +}; + +static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = msm8998_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), + .tx_tbl = msm8998_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), + .rx_tbl = msm8998_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), + .pcs_tbl = msm8998_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), + .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 qcm2290_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + +static void qmp_usbc_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_usbc_configure(void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num) +{ + qmp_usbc_configure_lane(base, tbl, num, 0xff); +} + +static int qmp_usbc_init(struct phy *phy) +{ + struct qmp_usbc *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(qmp->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset assert failed\n"); + goto err_disable_regulators; + } + + ret = reset_control_bulk_deassert(qmp->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset deassert failed\n"); + goto err_disable_regulators; + } + + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); + if (ret) + goto err_assert_reset; + + qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + + return 0; + +err_assert_reset: + reset_control_bulk_assert(qmp->num_resets, qmp->resets); +err_disable_regulators: + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return ret; +} + +static int qmp_usbc_exit(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + reset_control_bulk_assert(qmp->num_resets, qmp->resets); + + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return 0; +} + +static int qmp_usbc_power_on(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *status; + unsigned int val; + int ret; + + qmp_usbc_configure(qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); + + 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_usbc_configure_lane(qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_usbc_configure_lane(qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + + qmp_usbc_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_usbc_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + + qmp_usbc_configure(qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + + if (cfg->has_pwrdn_delay) + usleep_range(10, 20); + + /* Pull PHY out of reset state */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* start SerDes and Phy-Coding-Sublayer */ + qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START); + + status = qmp->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_usbc_power_off(struct phy *phy) +{ + struct qmp_usbc *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_usbc_enable(struct phy *phy) +{ + int ret; + + ret = qmp_usbc_init(phy); + if (ret) + return ret; + + ret = qmp_usbc_power_on(phy); + if (ret) + qmp_usbc_exit(phy); + + return ret; +} + +static int qmp_usbc_disable(struct phy *phy) +{ + int ret; + + ret = qmp_usbc_power_off(phy); + if (ret) + return ret; + return qmp_usbc_exit(phy); +} + +static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + qmp->mode = mode; + + return 0; +} + +static const struct phy_ops qmp_usbc_phy_ops = { + .init = qmp_usbc_enable, + .exit = qmp_usbc_disable, + .set_mode = qmp_usbc_set_mode, + .owner = THIS_MODULE, +}; + +static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = 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, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + + qphy_clrbits(pcs, 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, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); + + /* Enable i/o clamp_n for autonomous mode */ + if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE]) + qphy_clrbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN); +} + +static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + void __iomem *pcs_misc = qmp->pcs_misc; + + /* Disable i/o clamp_n on resume for normal mode */ + if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE]) + qphy_setbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN); + + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], + ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN); + + qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); +} + +static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + + 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_usbc_enable_autonomous_mode(qmp); + + clk_disable_unprepare(qmp->pipe_clk); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + + return 0; +} + +static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + 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(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(qmp->num_clks, qmp->clks); + return ret; + } + + qmp_usbc_disable_autonomous_mode(qmp); + + return 0; +} + +static const struct dev_pm_ops qmp_usbc_pm_ops = { + SET_RUNTIME_PM_OPS(qmp_usbc_runtime_suspend, + qmp_usbc_runtime_resume, NULL) +}; + +static int qmp_usbc_vreg_init(struct qmp_usbc *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_usbc_reset_init(struct qmp_usbc *qmp, + const char *const *reset_list, + int num_resets) +{ + struct device *dev = qmp->dev; + int i; + int ret; + + qmp->resets = devm_kcalloc(dev, num_resets, + sizeof(*qmp->resets), GFP_KERNEL); + if (!qmp->resets) + return -ENOMEM; + + for (i = 0; i < num_resets; i++) + qmp->resets[i].id = reset_list[i]; + + qmp->num_resets = num_resets; + + ret = devm_reset_control_bulk_get_exclusive(dev, num_resets, qmp->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to get resets\n"); + + return 0; +} + +static int qmp_usbc_clk_init(struct qmp_usbc *qmp) +{ + struct device *dev = qmp->dev; + int num = ARRAY_SIZE(qmp_usbc_phy_clk_l); + 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 = qmp_usbc_phy_clk_l[i]; + + qmp->num_clks = num; + + return devm_clk_bulk_get_optional(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_usbc *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 int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + struct device *dev = qmp->dev; + int ret; + + qmp->serdes = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qmp->serdes)) + return PTR_ERR(qmp->serdes); + + /* + * 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 = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qmp->pcs)) + return PTR_ERR(qmp->pcs); + + 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); + 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"); + } + + ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks); + if (ret < 0) + return ret; + + qmp->num_clks = ret; + + ret = qmp_usbc_reset_init(qmp, usb3phy_legacy_reset_l, + ARRAY_SIZE(usb3phy_legacy_reset_l)); + if (ret) + return ret; + + return 0; +} + +static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_usbc_offsets *offs = cfg->offsets; + struct device *dev = qmp->dev; + void __iomem *base; + int ret; + + 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; + if (offs->pcs_misc) + qmp->pcs_misc = base + offs->pcs_misc; + qmp->tx = base + offs->tx; + qmp->rx = base + offs->rx; + + qmp->tx2 = base + offs->tx2; + qmp->rx2 = base + offs->rx2; + + ret = qmp_usbc_clk_init(qmp); + if (ret) + return ret; + + 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"); + } + + ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l, + ARRAY_SIZE(usb3phy_reset_l)); + if (ret) + return ret; + + return 0; +} + +static int qmp_usbc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct device_node *np; + struct qmp_usbc *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_usbc_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_usbc_parse_dt_legacy(qmp, np); + } else { + np = of_node_get(dev->of_node); + ret = qmp_usbc_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_usbc_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_usbc_of_match_table[] = { + { + .compatible = "qcom,msm8998-qmp-usb3-phy", + .data = &msm8998_usb3phy_cfg, + }, { + .compatible = "qcom,qcm2290-qmp-usb3-phy", + .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,sm6115-qmp-usb3-phy", + .data = &qcm2290_usb3phy_cfg, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table); + +static struct platform_driver qmp_usbc_driver = { + .probe = qmp_usbc_probe, + .driver = { + .name = "qcom-qmp-usbc-phy", + .pm = &qmp_usbc_pm_ops, + .of_match_table = qmp_usbc_of_match_table, + }, +}; + +module_platform_driver(qmp_usbc_driver); + +MODULE_AUTHOR("Vivek Gautam "); +MODULE_DESCRIPTION("Qualcomm QMP USB-C PHY driver"); +MODULE_LICENSE("GPL"); From 52cfdc9c6c3306f0bda4f217396f508d3f5459fb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 13 Jan 2024 22:55:54 +0200 Subject: [PATCH 020/814] phy: qcom: qmp-usb: drop dual-lane handling Now as all dual-lane PHYs have been migrated to a new driver, drop support for dual lanes configuration. If the PHY uses two lanes for USB, it is symthom that it should use either a combo USB+DP or a USB-C PHY driver. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-11-182d9aa0a5b3@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 57 +------------------------ 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index c7698369d3dc..e62539ce99a6 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -1237,15 +1237,10 @@ struct qmp_usb_offsets { u16 pcs_usb; u16 tx; u16 rx; - /* for PHYs with >= 2 lanes */ - u16 tx2; - u16 rx2; }; /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - int lanes; - const struct qmp_usb_offsets *offsets; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ @@ -1285,8 +1280,6 @@ struct qmp_usb { void __iomem *pcs_usb; void __iomem *tx; void __iomem *rx; - void __iomem *tx2; - void __iomem *rx2; struct clk *pipe_clk; struct clk_bulk_data *clks; @@ -1393,8 +1386,6 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v7 = { }; static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v3, .serdes_tbl = ipq8074_usb3_serdes_tbl, @@ -1411,8 +1402,6 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { }; static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_ipq9574, .serdes_tbl = ipq9574_usb3_serdes_tbl, @@ -1429,8 +1418,6 @@ static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = { }; static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v3, .serdes_tbl = msm8996_usb3_serdes_tbl, @@ -1447,8 +1434,6 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { }; static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, @@ -1467,8 +1452,6 @@ static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, @@ -1487,8 +1470,6 @@ static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v3, .serdes_tbl = qmp_v3_usb3_uniphy_serdes_tbl, @@ -1507,8 +1488,6 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1530,8 +1509,6 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1553,8 +1530,6 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1576,8 +1551,6 @@ static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1599,7 +1572,6 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx75_usb3_uniphy_cfg = { - .lanes = 1, .offsets = &qmp_usb_offsets_v6, .serdes_tbl = sdx75_usb3_uniphy_serdes_tbl, @@ -1621,8 +1593,6 @@ static const struct qmp_phy_cfg sdx75_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1644,8 +1614,6 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v7, .serdes_tbl = x1e80100_usb3_uniphy_serdes_tbl, @@ -1780,11 +1748,6 @@ static int qmp_usb_power_on(struct phy *phy) qmp_usb_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); qmp_usb_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->lanes >= 2) { - qmp_usb_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_usb_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - } - qmp_usb_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (pcs_usb) @@ -2131,7 +2094,6 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) /* * 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); @@ -2149,19 +2111,7 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) 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); - } + 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"); @@ -2213,11 +2163,6 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp) qmp->tx = base + offs->tx; qmp->rx = base + offs->rx; - if (cfg->lanes >= 2) { - qmp->tx2 = base + offs->tx2; - qmp->rx2 = base + offs->rx2; - } - ret = qmp_usb_clk_init(qmp); if (ret) return ret; From dfdaba27b4660ec26de955cf4459499ddb005e2d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 13 Jan 2024 22:55:55 +0200 Subject: [PATCH 021/814] phy: qcom: qmp-usbc: add support for the Type-C handling The USB-C PHYs on the msm8998, QCM2290 and SM6115 platforms use special register to control which lanes of the Type-C port are used for the SuperSpeed USB connection. Mimic the qmp-combo driver and handle this register. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-12-182d9aa0a5b3@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 97 +++++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 52f1b3f7b81e..214cf4203de4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" @@ -374,11 +376,17 @@ struct qmp_usbc { struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; + struct mutex phy_mutex; + enum phy_mode mode; + unsigned int usb_init_count; struct phy *phy; struct clk_fixed_rate pipe_clk_fixed; + + struct typec_switch_dev *sw; + enum typec_orientation orientation; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -497,6 +505,7 @@ static int qmp_usbc_init(struct phy *phy) struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; + u32 val = 0; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -523,6 +532,14 @@ static int qmp_usbc_init(struct phy *phy) qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + return 0; err_assert_reset: @@ -620,23 +637,34 @@ static int qmp_usbc_power_off(struct phy *phy) static int qmp_usbc_enable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_init(phy); if (ret) - return ret; + goto out_unlock; ret = qmp_usbc_power_on(phy); - if (ret) + if (ret) { qmp_usbc_exit(phy); + goto out_unlock; + } + + qmp->usb_init_count++; +out_unlock: + mutex_unlock(&qmp->phy_mutex); return ret; } static int qmp_usbc_disable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + qmp->usb_init_count--; ret = qmp_usbc_power_off(phy); if (ret) return ret; @@ -874,6 +902,61 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } +#if IS_ENABLED(CONFIG_TYPEC) +static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct qmp_usbc *qmp = typec_switch_get_drvdata(sw); + + if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) + return 0; + + mutex_lock(&qmp->phy_mutex); + qmp->orientation = orientation; + + if (qmp->usb_init_count) { + qmp_usbc_power_off(qmp->phy); + qmp_usbc_exit(qmp->phy); + + qmp_usbc_init(qmp->phy); + qmp_usbc_power_on(qmp->phy); + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static void qmp_usbc_typec_unregister(void *data) +{ + struct qmp_usbc *qmp = data; + + typec_switch_unregister(qmp->sw); +} + +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + struct typec_switch_desc sw_desc = {}; + struct device *dev = qmp->dev; + + sw_desc.drvdata = qmp; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = qmp_usbc_typec_switch_set; + qmp->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(qmp->sw)) { + dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); + return PTR_ERR(qmp->sw); + } + + return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp); +} +#else +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + return 0; +} +#endif + static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) { struct platform_device *pdev = to_platform_device(qmp->dev); @@ -994,16 +1077,24 @@ static int qmp_usbc_probe(struct platform_device *pdev) qmp->dev = dev; + qmp->orientation = TYPEC_ORIENTATION_NORMAL; + qmp->cfg = of_device_get_match_data(dev); if (!qmp->cfg) return -EINVAL; + mutex_init(&qmp->phy_mutex); + ret = qmp_usbc_vreg_init(qmp); if (ret) return ret; + ret = qmp_usbc_typec_switch_register(qmp); + if (ret) + return ret; + /* Check for legacy binding with child node. */ - np = of_get_next_available_child(dev->of_node, NULL); + np = of_get_child_by_name(dev->of_node, "phy"); if (np) { ret = qmp_usbc_parse_dt_legacy(qmp, np); } else { From f2b2f86a8bd19feb70649abf8a63d639f4c838d8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 17 Jan 2024 16:04:23 +0200 Subject: [PATCH 022/814] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: add TCSR registers The QMP USB PHYs on msm8998, qcm2290 and some other platforms don't have the PCS_MISC_CLAMP_ENABLE register. Instead they need to toggle the register in the TCSR space. Declare the registers accessible through the TCSR space. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240117-usbc-phy-vls-clamp-v2-2-a950c223f10f@linaro.org Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml index da5d4cbca24c..140843347d1e 100644 --- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml @@ -55,6 +55,14 @@ properties: Flag the PHY as possible handler of USB Type-C orientation switching type: boolean + qcom,tcsr-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to TCSR hardware block + - description: offset of the VLS CLAMP register + description: Clamp register present in the TCSR + ports: $ref: /schemas/graph.yaml#/properties/ports properties: @@ -78,6 +86,7 @@ required: - "#clock-cells" - clock-output-names - "#phy-cells" + - qcom,tcsr-reg allOf: - if: @@ -148,6 +157,8 @@ examples: orientation-switch; + qcom,tcsr-reg = <&tcsr_regs_1 0x6b244>; + ports { #address-cells = <1>; #size-cells = <0>; From 01b086ccdeffac96f107228d581e0925e1c83f87 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 17 Jan 2024 16:04:24 +0200 Subject: [PATCH 023/814] phy: qcom: qmp-usbc: handle CLAMP register in a correct way The QMP USB PHYs on msm8998, qcm2290 and some other platforms don't have the PCS_MISC_CLAMP_ENABLE register. Instead they need to toggle the register in the TCSR space. Make the new phy-qcom-qmp-usbc driver correctly handle the clamp register. Fixes: a51969fafc82 ("phy: qcom-qmp: Add QMP V3 USB3 PHY support for msm8998") Fixes: 8abe5e778b2c ("phy: qcom-qmp: Add QCM2290 USB3 PHY support") Cc: Jeffrey Hugo Signed-off-by: Dmitry Baryshkov Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240117-usbc-phy-vls-clamp-v2-3-a950c223f10f@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 48 ++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 214cf4203de4..3a4b4849db0f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -56,9 +58,6 @@ /* 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 { @@ -94,7 +93,6 @@ enum qphy_reg_layout { QPHY_PCS_AUTONOMOUS_MODE_CTRL, QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, QPHY_PCS_POWER_DOWN_CONTROL, - QPHY_PCS_MISC_CLAMP_ENABLE, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -106,7 +104,6 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [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, - [QPHY_PCS_MISC_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, }; static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = { @@ -369,6 +366,9 @@ struct qmp_usbc { void __iomem *tx2; void __iomem *rx2; + struct regmap *tcsr_map; + u32 vls_clamp_reg; + struct clk *pipe_clk; struct clk_bulk_data *clks; int num_clks; @@ -691,7 +691,6 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; - void __iomem *pcs_misc = qmp->pcs_misc; u32 intr_mask; if (qmp->mode == PHY_MODE_USB_HOST_SS || @@ -712,19 +711,18 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); /* Enable i/o clamp_n for autonomous mode */ - if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE]) - qphy_clrbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN); + if (qmp->tcsr_map && qmp->vls_clamp_reg) + regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1); } static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; - void __iomem *pcs_misc = qmp->pcs_misc; /* Disable i/o clamp_n on resume for normal mode */ - if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE]) - qphy_setbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN); + if (qmp->tcsr_map && qmp->vls_clamp_reg) + regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0); qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN); @@ -1063,6 +1061,30 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) return 0; } +static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) +{ + struct of_phandle_args tcsr_args; + struct device *dev = qmp->dev; + int ret; + + /* for backwards compatibility ignore if there is no property */ + ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0, + &tcsr_args); + if (ret == -ENOENT) + return 0; + else if (ret < 0) + return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n"); + + qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np); + of_node_put(tcsr_args.np); + if (IS_ERR(qmp->tcsr_map)) + return PTR_ERR(qmp->tcsr_map); + + qmp->vls_clamp_reg = tcsr_args.args[0]; + + return 0; +} + static int qmp_usbc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1093,6 +1115,10 @@ static int qmp_usbc_probe(struct platform_device *pdev) if (ret) return ret; + ret = qmp_usbc_parse_vls_clamp(qmp); + if (ret) + return ret; + /* Check for legacy binding with child node. */ np = of_get_child_by_name(dev->of_node, "phy"); if (np) { From 0ca5e2bf2f4753a879ed3f4a747ee5c947152838 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 16 Jan 2024 03:10:55 +0200 Subject: [PATCH 024/814] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: support SDM660 Declare the USB-C QMP PHY present on the Qualcomm SDM660 / SDM630 platforms. Signed-off-by: Dmitry Baryshkov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240116-sdm660-usb3-support-v1-1-2fbd683aea77@linaro.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml index 140843347d1e..f1f4e4f83352 100644 --- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml @@ -18,6 +18,7 @@ properties: enum: - qcom,msm8998-qmp-usb3-phy - qcom,qcm2290-qmp-usb3-phy + - qcom,sdm660-qmp-usb3-phy - qcom,sm6115-qmp-usb3-phy reg: @@ -95,6 +96,7 @@ allOf: contains: enum: - qcom,msm8998-qmp-usb3-phy + - qcom,sdm660-qmp-usb3-phy then: properties: clocks: From 78f2d7df63cd3811ef878e881fa017a20a648c0f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 16 Jan 2024 03:10:56 +0200 Subject: [PATCH 025/814] phy: qcom: qmp-usbc: enable SDM630 support Provide PHY configuration for the USB QMP PHY for the SDM630 / SDM660 platforms. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240116-sdm660-usb3-support-v1-2-2fbd683aea77@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 3a4b4849db0f..02babec76881 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -293,6 +293,27 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), }; +/* the only difference is QSERDES_V3_RX_UCDR_PI_CONTROLS */ +static const struct qmp_phy_init_tbl sdm660_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + 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_VGA_CAL_CNTRL2, 0x0a), + 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_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), +}; + static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), @@ -474,6 +495,22 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = sdm660_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + static void qmp_usbc_configure_lane(void __iomem *base, const struct qmp_phy_init_tbl tbl[], int num, @@ -1171,6 +1208,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = { }, { .compatible = "qcom,qcm2290-qmp-usb3-phy", .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,sdm660-qmp-usb3-phy", + .data = &sdm660_usb3phy_cfg, }, { .compatible = "qcom,sm6115-qmp-usb3-phy", .data = &qcm2290_usb3phy_cfg, From 55067a491000a28288e25c3fb906ce796d4d5e7d Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 22 Jan 2024 19:33:35 -0800 Subject: [PATCH 026/814] dt-bindings: input: melfas,mms114: add MMS252 compatible Add a compatible for MMS252 touchscreen which appears to work fine with the MMS114 driver. Signed-off-by: Luca Weiss Signed-off-by: Bryant Mairs Reviewed-by: Krzysztof Kozlowski Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231105204759.37107-2-bryant@mai.rs Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/melfas,mms114.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml b/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml index 07f9dd6b1c9c..90ebd4f8354c 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml @@ -17,13 +17,17 @@ properties: pattern: "^touchscreen(@.*)?$" compatible: - items: + oneOf: - enum: - melfas,mms114 - melfas,mms134s - melfas,mms136 - melfas,mms152 - melfas,mms345l + - items: + - enum: + - melfas,mms252 + - const: melfas,mms114 reg: description: I2C address From 2777e73fc154e2e87233bdcc0e2402b33815198e Mon Sep 17 00:00:00 2001 From: Maramaina Naresh Date: Tue, 19 Dec 2023 18:07:05 +0530 Subject: [PATCH 027/814] scsi: ufs: core: Add CPU latency QoS support for UFS driver Register UFS driver to CPU latency PM QoS framework to improve UFS device random I/O performance. PM QoS initialization will insert new QoS request into the CPU latency QoS list with the maximum latency PM_QOS_DEFAULT_VALUE value. The UFS driver will vote for performance mode on scale up and power save mode for scale down. If clock scaling feature is not enabled then voting will be based on clock on or off condition. Also provide a sysfs interface to enable/disable PM QoS feature. tiotest benchmark tool I/O performance results on sm8550 platform: 1. Without PM QoS support Type (Speed in) | Average of 18 iterations Random Write(IPOS) | 41065.13 Random Read(IPOS) | 37101.3 2. With PM QoS support Type (Speed in) | Average of 18 iterations Random Write(IPOS) | 46784.9 Random Read(IPOS) | 42943.4 (Improvement with PM QoS = ~15%). Reviewed-by: Peter Wang Reviewed-by: AngeloGioacchino Del Regno Co-developed-by: Nitin Rawat Signed-off-by: Nitin Rawat Co-developed-by: Naveen Kumar Goud Arepalli Signed-off-by: Naveen Kumar Goud Arepalli Signed-off-by: Maramaina Naresh Link: https://lore.kernel.org/r/20231219123706.6463-2-quic_mnaresh@quicinc.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 49 +++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd.c | 50 ++++++++++++++++++++++++++++++++++++ include/ufs/ufshcd.h | 6 +++++ 3 files changed, 105 insertions(+) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index e6d12289e017..3d049967f6bc 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -405,6 +405,53 @@ static ssize_t wb_flush_threshold_store(struct device *dev, return count; } +/** + * pm_qos_enable_show - sysfs handler to show pm qos enable value + * @dev: device associated with the UFS controller + * @attr: sysfs attribute handle + * @buf: buffer for sysfs file + * + * Print 1 if PM QoS feature is enabled, 0 if disabled. + * + * Returns number of characters written to @buf. + */ +static ssize_t pm_qos_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", hba->pm_qos_enabled); +} + +/** + * pm_qos_enable_store - sysfs handler to store value + * @dev: device associated with the UFS controller + * @attr: sysfs attribute handle + * @buf: buffer for sysfs file + * @count: stores buffer characters count + * + * Input 0 to disable PM QoS and 1 value to enable. + * Default state: 1 + * + * Return: number of characters written to @buf on success, < 0 upon failure. + */ +static ssize_t pm_qos_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + bool value; + + if (kstrtobool(buf, &value)) + return -EINVAL; + + if (value) + ufshcd_pm_qos_init(hba); + else + ufshcd_pm_qos_exit(hba); + + return count; +} + static DEVICE_ATTR_RW(rpm_lvl); static DEVICE_ATTR_RO(rpm_target_dev_state); static DEVICE_ATTR_RO(rpm_target_link_state); @@ -416,6 +463,7 @@ static DEVICE_ATTR_RW(wb_on); static DEVICE_ATTR_RW(enable_wb_buf_flush); static DEVICE_ATTR_RW(wb_flush_threshold); static DEVICE_ATTR_RW(rtc_update_ms); +static DEVICE_ATTR_RW(pm_qos_enable); static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_rpm_lvl.attr, @@ -429,6 +477,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_enable_wb_buf_flush.attr, &dev_attr_wb_flush_threshold.attr, &dev_attr_rtc_update_ms.attr, + &dev_attr_pm_qos_enable.attr, NULL }; diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 029d017fc1b6..10b0c9cea0f0 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1014,6 +1014,48 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) return ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6; } +/** + * ufshcd_pm_qos_init - initialize PM QoS request + * @hba: per adapter instance + */ +void ufshcd_pm_qos_init(struct ufs_hba *hba) +{ + + if (hba->pm_qos_enabled) + return; + + cpu_latency_qos_add_request(&hba->pm_qos_req, PM_QOS_DEFAULT_VALUE); + + if (cpu_latency_qos_request_active(&hba->pm_qos_req)) + hba->pm_qos_enabled = true; +} + +/** + * ufshcd_pm_qos_exit - remove request from PM QoS + * @hba: per adapter instance + */ +void ufshcd_pm_qos_exit(struct ufs_hba *hba) +{ + if (!hba->pm_qos_enabled) + return; + + cpu_latency_qos_remove_request(&hba->pm_qos_req); + hba->pm_qos_enabled = false; +} + +/** + * ufshcd_pm_qos_update - update PM QoS request + * @hba: per adapter instance + * @on: If True, vote for perf PM QoS mode otherwise power save mode + */ +static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on) +{ + if (!hba->pm_qos_enabled) + return; + + cpu_latency_qos_update_request(&hba->pm_qos_req, on ? 0 : PM_QOS_DEFAULT_VALUE); +} + /** * ufshcd_set_clk_freq - set UFS controller clock frequencies * @hba: per adapter instance @@ -1160,8 +1202,11 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, hba->devfreq->previous_freq); else ufshcd_set_clk_freq(hba, !scale_up); + goto out; } + ufshcd_pm_qos_update(hba, scale_up); + out: trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), (scale_up ? "up" : "down"), @@ -9279,6 +9324,8 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on) if (ret) return ret; + if (!ufshcd_is_clkscaling_supported(hba)) + ufshcd_pm_qos_update(hba, on); out: if (ret) { list_for_each_entry(clki, head, list) { @@ -9456,6 +9503,7 @@ out: static void ufshcd_hba_exit(struct ufs_hba *hba) { if (hba->is_powered) { + ufshcd_pm_qos_exit(hba); ufshcd_exit_clk_scaling(hba); ufshcd_exit_clk_gating(hba); if (hba->eh_wq) @@ -10108,6 +10156,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) ufshcd_vreg_set_lpm(hba); /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); + ufshcd_pm_qos_update(hba, false); return ret; } @@ -10654,6 +10703,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufs_sysfs_add_nodes(hba->dev); device_enable_async_suspend(dev); + ufshcd_pm_qos_init(hba); return 0; free_tmf_queue: diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 8e2bce9a4f21..c491671e79b7 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -914,6 +914,8 @@ enum ufshcd_mcq_opr { * @dev_cmd_queue: Queue for issuing device management commands * @mcq_opr: MCQ operation and runtime registers * @ufs_rtc_update_work: A work for UFS RTC periodic update + * @pm_qos_req: PM QoS request handle + * @pm_qos_enabled: flag to check if pm qos is enabled */ struct ufs_hba { void __iomem *mmio_base; @@ -1080,6 +1082,8 @@ struct ufs_hba { struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX]; struct delayed_work ufs_rtc_update_work; + struct pm_qos_request pm_qos_req; + bool pm_qos_enabled; }; /** @@ -1400,6 +1404,8 @@ 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); +void ufshcd_pm_qos_init(struct ufs_hba *hba); +void ufshcd_pm_qos_exit(struct ufs_hba *hba); /* Wrapper functions for safely calling variant operations */ static inline int ufshcd_vops_init(struct ufs_hba *hba) From 0652205b4ce2c954a08f9cbba432aadda79c6484 Mon Sep 17 00:00:00 2001 From: Maramaina Naresh Date: Tue, 19 Dec 2023 18:07:06 +0530 Subject: [PATCH 028/814] scsi: ufs: ufs-mediatek: Migrate to UFSHCD generic CPU latency PM QoS support The PM QoS feature found in the MediaTek UFS driver was moved to the UFSHCD core. Hence remove it from MediaTek UFS driver as it is redundant now. Reviewed-by: Peter Wang Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Maramaina Naresh Link: https://lore.kernel.org/r/20231219123706.6463-3-quic_mnaresh@quicinc.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 17 ----------------- drivers/ufs/host/ufs-mediatek.h | 3 --- 2 files changed, 20 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 776bca4f70c8..f43eb945e011 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -626,21 +625,9 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) dev_info(hba->dev, "caps: 0x%x", host->caps); } -static void ufs_mtk_boost_pm_qos(struct ufs_hba *hba, bool boost) -{ - struct ufs_mtk_host *host = ufshcd_get_variant(hba); - - if (!host || !host->pm_qos_init) - return; - - cpu_latency_qos_update_request(&host->pm_qos_req, - boost ? 0 : PM_QOS_DEFAULT_VALUE); -} - static void ufs_mtk_scale_perf(struct ufs_hba *hba, bool scale_up) { ufs_mtk_boost_crypt(hba, scale_up); - ufs_mtk_boost_pm_qos(hba, scale_up); } static void ufs_mtk_pwr_ctrl(struct ufs_hba *hba, bool on) @@ -959,10 +946,6 @@ static int ufs_mtk_init(struct ufs_hba *hba) host->ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER); - /* Initialize pm-qos request */ - cpu_latency_qos_add_request(&host->pm_qos_req, PM_QOS_DEFAULT_VALUE); - host->pm_qos_init = true; - goto out; out_variant_clear: diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h index f76e80d91729..38eab95b0f79 100644 --- a/drivers/ufs/host/ufs-mediatek.h +++ b/drivers/ufs/host/ufs-mediatek.h @@ -7,7 +7,6 @@ #define _UFS_MEDIATEK_H #include -#include #include /* @@ -167,7 +166,6 @@ struct ufs_mtk_mcq_intr_info { struct ufs_mtk_host { struct phy *mphy; - struct pm_qos_request pm_qos_req; struct regulator *reg_va09; struct reset_control *hci_reset; struct reset_control *unipro_reset; @@ -178,7 +176,6 @@ struct ufs_mtk_host { struct ufs_mtk_hw_ver hw_ver; enum ufs_mtk_host_caps caps; bool mphy_powered_on; - bool pm_qos_init; bool unipro_lpm; bool ref_clk_enabled; u16 ref_clk_ungating_wait_us; From 29b3a373e2df30b1f8bb9ef8a0d480cce3d0e295 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Thu, 21 Dec 2023 19:04:14 +0800 Subject: [PATCH 029/814] scsi: ufs: ufs-mediatek: Check link status after exiting hibern8 To prevent SSU(Active) error, check link status after exiting hibern8. If link is not VS_LINK_UP, return error and do ufshcd_link_recovery. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20231221110416.16176-2-peter.wang@mediatek.com Reviewed-by: Chun-Hung Wu Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index f43eb945e011..dcccb63f74b9 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1189,11 +1189,18 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) return err; err = ufshcd_uic_hibern8_exit(hba); - if (!err) - ufshcd_set_link_active(hba); - else + if (err) return err; + /* Check link state to make sure exit h8 success */ + ufs_mtk_wait_idle_state(hba, 5); + err = ufs_mtk_wait_link_state(hba, VS_LINK_UP, 100); + if (err) { + dev_warn(hba->dev, "exit h8 state fail, err=%d\n", err); + return err; + } + ufshcd_set_link_active(hba); + if (!hba->mcq_enabled) { err = ufshcd_make_hba_operational(hba); } else { From 468b3e0a3bca659bff6ddc48d5baeddfd678be7b Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Thu, 21 Dec 2023 19:04:15 +0800 Subject: [PATCH 030/814] scsi: ufs: ufs-mediatek: Fix MCQ mode TM cmd timeout Fix TM cmd timeout issue in MCQ mode using the default resume call ufshcd_make_hba_operational() to set TM cmd DMA address. This flow is the same as UFS initialization after link startup and then setting MCQ related registers if using MCQ mode. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20231221110416.16176-3-peter.wang@mediatek.com Reviewed-by: Chun-Hung Wu Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index dcccb63f74b9..47b5f49cda9d 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1201,9 +1201,11 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) } ufshcd_set_link_active(hba); - if (!hba->mcq_enabled) { - err = ufshcd_make_hba_operational(hba); - } else { + err = ufshcd_make_hba_operational(hba); + if (err) + return err; + + if (is_mcq_enabled(hba)) { ufs_mtk_config_mcq(hba, false); ufshcd_mcq_make_queues_operational(hba); ufshcd_mcq_config_mac(hba, hba->nutrs); @@ -1212,9 +1214,6 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) REG_UFS_MEM_CFG); } - if (err) - return err; - return 0; } From e0dc13e5a3cb9de98fd00b7718738f9eef4bd0ce Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Thu, 21 Dec 2023 19:04:16 +0800 Subject: [PATCH 031/814] scsi: ufs: ufs-mediatek: Disable MCQ IRQ when clock off Disable MCQ IRQ when clock is off. This is same as legacy mode. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20231221110416.16176-4-peter.wang@mediatek.com Reviewed-by: Chun-Hung Wu Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 41 +++++++++++++++++++++++++++++++++ drivers/ufs/host/ufs-mediatek.h | 1 + 2 files changed, 42 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 47b5f49cda9d..0b1b8efa864b 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -647,6 +647,45 @@ static void ufs_mtk_pwr_ctrl(struct ufs_hba *hba, bool on) } } +static void ufs_mtk_mcq_disable_irq(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + u32 irq, i; + + if (!is_mcq_enabled(hba)) + return; + + if (host->mcq_nr_intr == 0) + return; + + for (i = 0; i < host->mcq_nr_intr; i++) { + irq = host->mcq_intr_info[i].irq; + disable_irq(irq); + } + host->is_mcq_intr_enabled = false; +} + +static void ufs_mtk_mcq_enable_irq(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + u32 irq, i; + + if (!is_mcq_enabled(hba)) + return; + + if (host->mcq_nr_intr == 0) + return; + + if (host->is_mcq_intr_enabled == true) + return; + + for (i = 0; i < host->mcq_nr_intr; i++) { + irq = host->mcq_intr_info[i].irq; + enable_irq(irq); + } + host->is_mcq_intr_enabled = true; +} + /** * ufs_mtk_setup_clocks - enables/disable clocks * @hba: host controller instance @@ -690,8 +729,10 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, if (clk_pwr_off) ufs_mtk_pwr_ctrl(hba, false); + ufs_mtk_mcq_disable_irq(hba); } else if (on && status == POST_CHANGE) { ufs_mtk_pwr_ctrl(hba, true); + ufs_mtk_mcq_enable_irq(hba); } return ret; diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h index 38eab95b0f79..d0673f1021ec 100644 --- a/drivers/ufs/host/ufs-mediatek.h +++ b/drivers/ufs/host/ufs-mediatek.h @@ -183,6 +183,7 @@ struct ufs_mtk_host { u32 ip_ver; bool mcq_set_intr; + bool is_mcq_intr_enabled; int mcq_nr_intr; struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR]; }; From 4380e64a94e16c757552e8e2fbdc856415012fc8 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Tue, 9 Jan 2024 20:40:14 +0800 Subject: [PATCH 032/814] scsi: core: Move autosuspend timer delay to Scsi_Host The runtime suspend timer delay is a const value in scsi_host_template which a host driver cannot modify at runtime. Move the delay to Scsi_Host to allow a driver to update it. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20240109124015.31359-2-peter.wang@mediatek.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 2 +- drivers/ufs/core/ufshcd.c | 9 +++++++-- include/scsi/scsi_host.h | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0833b3e6aa6e..d1b87670764c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3728,7 +3728,7 @@ static int sd_probe(struct device *dev) blk_pm_runtime_init(sdp->request_queue, dev); if (sdp->rpm_autosuspend) { pm_runtime_set_autosuspend_delay(dev, - sdp->host->hostt->rpm_autosuspend_delay); + sdp->host->rpm_autosuspend_delay); } error = device_add_disk(dev, gd, NULL); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 10b0c9cea0f0..e519695b704f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8031,11 +8031,13 @@ out: static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev) { + struct Scsi_Host *shost = sdev->host; + scsi_autopm_get_device(sdev); blk_pm_runtime_init(sdev->request_queue, &sdev->sdev_gendev); if (sdev->rpm_autosuspend) pm_runtime_set_autosuspend_delay(&sdev->sdev_gendev, - RPM_AUTOSUSPEND_DELAY_MS); + shost->rpm_autosuspend_delay); scsi_autopm_put_device(sdev); } @@ -9109,7 +9111,6 @@ static const struct scsi_host_template ufshcd_driver_template = { .track_queue_depth = 1, .skip_settle_delay = 1, .sdev_groups = ufshcd_driver_groups, - .rpm_autosuspend_delay = RPM_AUTOSUSPEND_DELAY_MS, }; static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, @@ -10568,6 +10569,10 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) host->max_cmd_len = UFS_CDB_SIZE; host->queuecommand_may_block = !!(hba->caps & UFSHCD_CAP_CLK_GATING); + /* Use default RPM delay if host not set */ + if (host->rpm_autosuspend_delay == 0) + host->rpm_autosuspend_delay = RPM_AUTOSUSPEND_DELAY_MS; + hba->max_pwr_info.is_valid = false; /* Initialize work queues */ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 3b907fc2ef08..b259d42a1e1a 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -497,9 +497,6 @@ struct scsi_host_template { * scsi_netlink.h */ u64 vendor_id; - - /* Delay for runtime autosuspend */ - int rpm_autosuspend_delay; }; /* @@ -713,6 +710,9 @@ struct Scsi_Host { */ struct device *dma_dev; + /* Delay for runtime autosuspend */ + int rpm_autosuspend_delay; + /* * We should ensure that this is aligned, both for better performance * and also because some compilers (m68k) don't automatically force From 332973850054aaf540f9e02a6f037fac449cdeae Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Tue, 9 Jan 2024 20:40:15 +0800 Subject: [PATCH 033/814] scsi: ufs: ufs-mediatek: Change default autosuspend timer Change default autosuspend timer from 2000 ms to 500 ms for the MediaTek driver. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20240109124015.31359-3-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 4 ++++ drivers/ufs/host/ufs-mediatek.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 0b1b8efa864b..72a7b3a7cc00 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -921,6 +921,7 @@ static int ufs_mtk_init(struct ufs_hba *hba) const struct of_device_id *id; struct device *dev = hba->dev; struct ufs_mtk_host *host; + struct Scsi_Host *shost = hba->host; int err = 0; host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); @@ -965,6 +966,9 @@ static int ufs_mtk_init(struct ufs_hba *hba) /* Enable clk scaling*/ hba->caps |= UFSHCD_CAP_CLK_SCALING; + /* Set runtime pm delay to replace default */ + shost->rpm_autosuspend_delay = MTK_RPM_AUTOSUSPEND_DELAY_MS; + hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL; hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_INTR; hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_RTC; diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h index d0673f1021ec..fb53882f42ca 100644 --- a/drivers/ufs/host/ufs-mediatek.h +++ b/drivers/ufs/host/ufs-mediatek.h @@ -188,6 +188,9 @@ struct ufs_mtk_host { struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR]; }; +/* MTK delay of autosuspend: 500 ms */ +#define MTK_RPM_AUTOSUSPEND_DELAY_MS 500 + /* * Multi-VCC by Numbering */ From 796cae1a79b192510041563c95d3fc0fab31ec6e Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Thu, 11 Jan 2024 17:24:19 +0100 Subject: [PATCH 034/814] scsi: core: Safe warning about bad dev info string Both "model" and "strflags" are passed to "%s" even when one or both are NULL. It is safe because vsprintf() would detect the NULL pointer and print "(null)". But it is a kernel-specific feature and compiler warns about it: In file included from include/linux/kernel.h:19, from arch/x86/include/asm/percpu.h:27, from arch/x86/include/asm/current.h:6, from include/linux/sched.h:12, from include/linux/blkdev.h:5, from drivers/scsi/scsi_devinfo.c:3: drivers/scsi/scsi_devinfo.c: In function 'scsi_dev_info_list_add_str': >> include/linux/printk.h:434:44: warning: '%s' directive argument is null [-Wformat-overflow=] 434 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__) | ^ include/linux/printk.h:430:3: note: in definition of macro 'printk_index_wrap' 430 | _p_func(_fmt, ##__VA_ARGS__); \ | ^~~~~~~ drivers/scsi/scsi_devinfo.c:551:4: note: in expansion of macro 'printk' 551 | printk(KERN_ERR "%s: bad dev info string '%s' '%s'" | ^~~~~~ drivers/scsi/scsi_devinfo.c:552:14: note: format string is defined here 552 | " '%s'\n", __func__, vendor, model, | ^~ Do not rely on the kernel specific behavior and print the message a safe way. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401112002.AOjwMNM0-lkp@intel.com/ Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20240111162419.12406-1-pmladek@suse.com Reviewed-by: Bart Van Assche Acked-by: Chris Down Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_devinfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 3fcaf10a9dfe..ba7237e83863 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -551,9 +551,9 @@ static int scsi_dev_info_list_add_str(char *dev_list) if (model) strflags = strsep(&next, next_check); if (!model || !strflags) { - printk(KERN_ERR "%s: bad dev info string '%s' '%s'" - " '%s'\n", __func__, vendor, model, - strflags); + pr_err("%s: bad dev info string '%s' '%s' '%s'\n", + __func__, vendor, model ? model : "", + strflags ? strflags : ""); res = -EINVAL; } else res = scsi_dev_info_list_add(0 /* compatible */, vendor, From ab3e6c4e0ea149f16d5b719ecf7572862060d215 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Tue, 2 Jan 2024 10:42:22 +0900 Subject: [PATCH 035/814] scsi: ufs: mcq: Add definition for REG_UFS_MEM_CFG register Instead of hardcoding the register field, add the proper definition. While at it, let's also use ufshcd_rmwl() to simplify updating this register. Reviewed-by: Peter Wang Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20240102014222.23351-1-cw9316.lee@samsung.com Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 6 ++++++ drivers/ufs/core/ufshcd.c | 4 +--- drivers/ufs/host/ufs-mediatek.c | 4 +--- include/ufs/ufshcd.h | 1 + include/ufs/ufshci.h | 3 +++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 0787456c2b89..edc752e55878 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -399,6 +399,12 @@ void ufshcd_mcq_enable_esi(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); +void ufshcd_mcq_enable(struct ufs_hba *hba) +{ + ufshcd_rmwl(hba, MCQ_MODE_SELECT, MCQ_MODE_SELECT, REG_UFS_MEM_CFG); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_enable); + void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) { ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index e519695b704f..f10a92681bba 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8847,9 +8847,7 @@ static void ufshcd_config_mcq(struct ufs_hba *hba) hba->host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED; hba->reserved_slot = hba->nutrs - UFSHCD_NUM_RESERVED; - /* Select MCQ mode */ - ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1, - REG_UFS_MEM_CFG); + ufshcd_mcq_enable(hba); hba->mcq_enabled = true; dev_info(hba->dev, "MCQ configured, nr_queues=%d, io_queues=%d, read_queue=%d, poll_queues=%d, queue_depth=%d\n", diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 72a7b3a7cc00..b8a8801322e2 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1254,9 +1254,7 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) 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); + ufshcd_mcq_enable(hba); } return 0; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index c491671e79b7..cb2afcebbdf5 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1267,6 +1267,7 @@ 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_enable(struct ufs_hba *hba); void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index d5accacae6bc..a196e1c4c3bb 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -282,6 +282,9 @@ enum { /* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */ #define UTP_TASK_REQ_LIST_RUN_STOP_BIT 0x1 +/* REG_UFS_MEM_CFG - Global Config Registers 300h */ +#define MCQ_MODE_SELECT BIT(0) + /* CQISy - CQ y Interrupt Status Register */ #define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS 0x1 From 325ec4ac7da6272da9b2da51b7c5cc75e48bf654 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 5 Jan 2024 11:10:40 +0900 Subject: [PATCH 036/814] scsi: ufs: mcq: Use ufshcd_mcq_req_to_hwq() to simplify updating hwq Use ufshcd_mcq_req_to_hwq() to remove unnecessary variables and simplify. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20240105021041.20400-2-cw9316.lee@samsung.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f10a92681bba..c416826762e9 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5645,7 +5645,6 @@ static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba, struct ufshcd_lrb *lrbp; struct scsi_cmnd *cmd; unsigned long flags; - u32 hwq_num, utag; int tag; for (tag = 0; tag < hba->nutrs; tag++) { @@ -5655,9 +5654,7 @@ static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba, test_bit(SCMD_STATE_COMPLETE, &cmd->state)) continue; - utag = blk_mq_unique_tag(scsi_cmd_to_rq(cmd)); - hwq_num = blk_mq_unique_tag_to_hwq(utag); - hwq = &hba->uhq[hwq_num]; + hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); if (force_compl) { ufshcd_mcq_compl_all_cqes_lock(hba, hwq); From 01f256228c0f89c4b48fbc7c67b64a26cdcfd740 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 5 Jan 2024 11:10:41 +0900 Subject: [PATCH 037/814] scsi: ufs: mcq: Remove unused parameters The 'hwq' parameter is not used in this function. Remove unused parameters. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20240105021041.20400-3-cw9316.lee@samsung.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index edc752e55878..8db81f1a12d5 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -258,9 +258,7 @@ EXPORT_SYMBOL_GPL(ufshcd_mcq_write_cqis); * Current MCQ specification doesn't provide a Task Tag or its equivalent in * the Completion Queue Entry. Find the Task Tag using an indirect method. */ -static int ufshcd_mcq_get_tag(struct ufs_hba *hba, - struct ufs_hw_queue *hwq, - struct cq_entry *cqe) +static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe) { u64 addr; @@ -278,7 +276,7 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, struct ufs_hw_queue *hwq) { struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq); - int tag = ufshcd_mcq_get_tag(hba, hwq, cqe); + int tag = ufshcd_mcq_get_tag(hba, cqe); if (cqe->command_desc_base_addr) { ufshcd_compl_one_cqe(hba, tag, cqe); From 9759cdc1bcb8659dae638bd0c3927eac6db9c874 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 18 Jan 2024 12:14:41 +0000 Subject: [PATCH 038/814] scsi: megaraid: Remove redundant assignment to variable 'retval' The variable 'retval' is being assigned a value that is not being read afterwards. The assignment is redundant and can be removed. Cleans up clang scan warning: Although the value stored to 'retval' is used in the enclosing expression, the value is never actually read from 'retval' [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240118121441.2533620-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 66a30a3e6cd5..38976f94453e 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -219,7 +219,7 @@ mega_query_adapter(adapter_t *adapter) raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ /* Issue a blocking command to the card */ - if ((retval = issue_scb_block(adapter, raw_mbox))) { + if (issue_scb_block(adapter, raw_mbox)) { /* the adapter does not support 40ld */ mraid_ext_inquiry *ext_inq; From be7fc734b658497aa8fe937c8109e0121c1881af Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 18 Jan 2024 12:20:39 +0000 Subject: [PATCH 039/814] scsi: message: fusion: Remove redundant pointer 'hd' The pointer 'hd' is being assigned a value that is not being read later. The variable is redundant and can be removed. Cleans up clang scan build warning: warning: Although the value stored to 'hd' is used in the enclosing expression, the value is never actually read from 'hd' [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240118122039.2541425-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 0581f855c72e..c459f709107b 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1401,7 +1401,6 @@ static struct pci_driver mptfc_driver = { static int mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { - MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; unsigned long flags; int rc=1; @@ -1412,8 +1411,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); - if (ioc->sh == NULL || - ((hd = shost_priv(ioc->sh)) == NULL)) + if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) return 1; switch (event) { From 165470fb260020861bea61a18f3e3a543a20c804 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 12 Dec 2023 01:20:20 +0000 Subject: [PATCH 040/814] scsi: ibmvscsi_tgt: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We don't need the NUL-padding behavior that strncpy() provides as vscsi is NUL-allocated in ibmvscsis_probe() which proceeds to call ibmvscsis_adapter_info(): | vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL); ibmvscsis_probe() -> ibmvscsis_handle_crq() -> ibmvscsis_parse_command() -> ibmvscsis_mad() -> ibmvscsis_process_mad() -> ibmvscsis_adapter_info() Following the same idea, `partition_name` is defiend as: | static char partition_name[PARTITION_NAMELEN] = "UNKNOWN"; ... which is NUL-padded already, meaning strscpy() is the best option. Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. However, for cap->name and info let's use strscpy_pad() as they are allocated via dma_alloc_coherent(): | cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token, | GFP_ATOMIC); & | info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token, | GFP_ATOMIC); Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231212-strncpy-drivers-scsi-ibmvscsi_tgt-ibmvscsi_tgt-c-v2-1-bdb9a7cd96c8@google.com Acked-by: Tyrel Datwyler Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 4dc411a58107..6b16020b1f59 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -1551,18 +1551,18 @@ static long ibmvscsis_adapter_info(struct scsi_info *vscsi, if (vscsi->client_data.partition_number == 0) vscsi->client_data.partition_number = be32_to_cpu(info->partition_number); - strncpy(vscsi->client_data.srp_version, info->srp_version, + strscpy(vscsi->client_data.srp_version, info->srp_version, sizeof(vscsi->client_data.srp_version)); - strncpy(vscsi->client_data.partition_name, info->partition_name, + strscpy(vscsi->client_data.partition_name, info->partition_name, sizeof(vscsi->client_data.partition_name)); vscsi->client_data.mad_version = be32_to_cpu(info->mad_version); vscsi->client_data.os_type = be32_to_cpu(info->os_type); /* Copy our info */ - strncpy(info->srp_version, SRP_VERSION, - sizeof(info->srp_version)); - strncpy(info->partition_name, vscsi->dds.partition_name, - sizeof(info->partition_name)); + strscpy_pad(info->srp_version, SRP_VERSION, + sizeof(info->srp_version)); + strscpy_pad(info->partition_name, vscsi->dds.partition_name, + sizeof(info->partition_name)); info->partition_number = cpu_to_be32(vscsi->dds.partition_num); info->mad_version = cpu_to_be32(MAD_VERSION_1); info->os_type = cpu_to_be32(LINUX); @@ -1645,8 +1645,8 @@ static int ibmvscsis_cap_mad(struct scsi_info *vscsi, struct iu_entry *iue) be64_to_cpu(mad->buffer), vscsi->dds.window[LOCAL].liobn, token); if (rc == H_SUCCESS) { - strncpy(cap->name, dev_name(&vscsi->dma_dev->dev), - SRP_MAX_LOC_LEN); + strscpy_pad(cap->name, dev_name(&vscsi->dma_dev->dev), + sizeof(cap->name)); len = olen - min_len; status = VIOSRP_MAD_SUCCESS; @@ -3650,7 +3650,7 @@ static int ibmvscsis_get_system_info(void) name = of_get_property(rootdn, "ibm,partition-name", NULL); if (name) - strncpy(partition_name, name, sizeof(partition_name)); + strscpy(partition_name, name, sizeof(partition_name)); num = of_get_property(rootdn, "ibm,partition-no", NULL); if (num) From 29b75184f721b16c51ef6e67eec0e40ed88381c7 Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Fri, 29 Dec 2023 12:03:31 +0800 Subject: [PATCH 041/814] scsi: mpi3mr: Use ida to manage mrioc ID To ensure that the same ID is not obtained during concurrent execution of the probe, an ida is used to manage the mrioc's ID. Signed-off-by: Guixin Liu Link: https://lore.kernel.org/r/20231229040331.52518-1-kanie@linux.alibaba.com Reviewed-by: Lee Duncan Reviewed-by: Martin Wilck Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 1bffd629c124..73c831a97d27 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -8,11 +8,12 @@ */ #include "mpi3mr.h" +#include /* global driver scop variables */ LIST_HEAD(mrioc_list); DEFINE_SPINLOCK(mrioc_list_lock); -static int mrioc_ids; +static DEFINE_IDA(mrioc_ida); static int warn_non_secure_ctlr; atomic64_t event_counter; @@ -5072,7 +5073,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) } mrioc = shost_priv(shost); - mrioc->id = mrioc_ids++; + retval = ida_alloc_range(&mrioc_ida, 1, U8_MAX, GFP_KERNEL); + if (retval < 0) + goto id_alloc_failed; + mrioc->id = (u8)retval; sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME); sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id); INIT_LIST_HEAD(&mrioc->list); @@ -5222,9 +5226,11 @@ init_ioc_failed: resource_alloc_failed: destroy_workqueue(mrioc->fwevt_worker_thread); fwevtthread_failed: + ida_free(&mrioc_ida, mrioc->id); spin_lock(&mrioc_list_lock); list_del(&mrioc->list); spin_unlock(&mrioc_list_lock); +id_alloc_failed: scsi_host_put(shost); shost_failed: return retval; @@ -5310,6 +5316,7 @@ static void mpi3mr_remove(struct pci_dev *pdev) mrioc->sas_hba.num_phys = 0; } + ida_free(&mrioc_ida, mrioc->id); spin_lock(&mrioc_list_lock); list_del(&mrioc->list); spin_unlock(&mrioc_list_lock); @@ -5525,6 +5532,7 @@ static void __exit mpi3mr_exit(void) &driver_attr_event_counter); pci_unregister_driver(&mpi3mr_pci_driver); sas_release_transport(mpi3mr_transport_template); + ida_destroy(&mrioc_ida); } module_init(mpi3mr_init); From f1aa6437733a5433cf7e22d4c2058129cf98b0f8 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 18 Jan 2024 10:01:28 +0800 Subject: [PATCH 042/814] scsi: fnic: Clean up some inconsistent indenting No functional modification involved. drivers/scsi/fnic/fnic_scsi.c:1964 fnic_abort_cmd() warn: inconsistent indenting. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7930 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20240118020128.24432-1-jiapeng.chong@linux.alibaba.com Reviewed-by: Karan Tilak Kumar Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 8d7fc5284293..5b4768e669f0 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1961,8 +1961,8 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, - "Issuing host reset due to out of order IO\n"); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Issuing host reset due to out of order IO\n"); ret = FAILED; goto fnic_abort_cmd_end; From e94b29f2bd73db149ce7fee9a41a7b6ca17f7918 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Sat, 23 Dec 2023 13:55:21 +0200 Subject: [PATCH 043/814] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the X1E80100 QMP PCIe PHYs Document the QMP PCIe PHYs on the X1E80100 platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Abel Vesa Link: https://lore.kernel.org/r/20231223-x1e80100-phy-pcie-v2-1-223c0556908a@linaro.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 6 ++++++ 1 file changed, 6 insertions(+) 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 6c03f2d5fca3..ba966a78a128 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -38,6 +38,8 @@ properties: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,x1e80100-qmp-gen3x2-pcie-phy + - qcom,x1e80100-qmp-gen4x2-pcie-phy reg: minItems: 1 @@ -151,6 +153,8 @@ allOf: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,x1e80100-qmp-gen3x2-pcie-phy + - qcom,x1e80100-qmp-gen4x2-pcie-phy then: properties: clocks: @@ -194,6 +198,8 @@ allOf: enum: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,x1e80100-qmp-gen3x2-pcie-phy + - qcom,x1e80100-qmp-gen4x2-pcie-phy then: properties: resets: From 70e0af37e81e8a19e207ccf14953109d793087cb Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Sat, 23 Dec 2023 13:55:22 +0200 Subject: [PATCH 044/814] phy: qcom: qmp-pcie: Add QMP v6 registers layout For consistency, add the QMP v6 registers layout even though they are the same as v5. Also switch all QMP v6 PHYs to use this new layout. Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231223-x1e80100-phy-pcie-v2-2-223c0556908a@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 2af7115ef968..03a4898a7e6f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -116,6 +116,13 @@ static const unsigned int pciephy_v5_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V6_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V6_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V6_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), @@ -2936,7 +2943,7 @@ static const struct qmp_phy_cfg sdx65_qmp_pciephy_cfg = { .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, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS_4_20, @@ -3069,7 +3076,7 @@ static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), .vreg_list = sm8550_qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), - .regs = pciephy_v5_regs_layout, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, @@ -3099,7 +3106,7 @@ static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = { .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), .vreg_list = sm8550_qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), - .regs = pciephy_v5_regs_layout, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, From 606060ce8fd09891d97358e35fb2d2c00c787449 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Sat, 23 Dec 2023 13:55:23 +0200 Subject: [PATCH 045/814] phy: qcom-qmp-pcie: Add support for X1E80100 g3x2 and g4x2 PCIE Add the X1E80100 G3 and G4 configurations. Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231223-x1e80100-phy-pcie-v2-3-223c0556908a@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 173 +++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 03a4898a7e6f..3ba302a7285c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -989,6 +989,143 @@ static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), }; +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_POST_DIV_MUX, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MISC_1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_2, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_3, 0x51), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN, 0x34), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_BKUP_CTRL1, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B1, 0xb3), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B2, 0x58), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B4, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B6, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B0, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B1, 0xa4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B2, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B3, 0xdf), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_RX_SIGDET_LVL, 0xcc), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG4, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG5, 0x22), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1, 0x03), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG3, 0x28), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_TX_RX_CONFIG, 0xc0), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_POWER_STATE_CONFIG2, 0x1d), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG5, 0x0f), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_FOM_EQ_CONFIG5, 0xf2), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5, 0xf2), +}; + static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), @@ -3190,6 +3327,36 @@ static const struct qmp_phy_cfg sa8775p_qmp_gen4x4_pciephy_cfg = { .phy_status = PHYSTATUS_4_20, }; +static const struct qmp_phy_cfg x1e80100_qmp_gen4x2_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_v6_20, + + .tbls = { + .serdes = x1e80100_qmp_gen4x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_serdes_tbl), + .tx = x1e80100_qmp_gen4x2_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_tx_tbl), + .rx = x1e80100_qmp_gen4x2_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_rx_tbl), + .pcs = x1e80100_qmp_gen4x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_tbl), + .pcs_misc = x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl), + .ln_shrd = x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl, + .ln_shrd_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl), + }, + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = sm8550_qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), + .regs = pciephy_v6_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, + .has_nocsr_reset = true, +}; + static void qmp_pcie_configure_lane(void __iomem *base, const struct qmp_phy_init_tbl tbl[], int num, @@ -3892,6 +4059,12 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy", .data = &sm8650_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen3x2-pcie-phy", + .data = &sm8550_qmp_gen3x2_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen4x2-pcie-phy", + .data = &x1e80100_qmp_gen4x2_pciephy_cfg, }, { }, }; From f7c6249d76f1167f2fc9843311e54e2528666d11 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Sat, 6 Jan 2024 15:56:33 +0100 Subject: [PATCH 046/814] phy: armada-38x: add mux value for gbe port 0 on serdes 0 Armada 38x supports 3 functions on serdes #0: - pcie port 0 - sata port 0 - gbe port 0 Add missing entry for gbe port 0 on serdes 0 to the gbe_mux array. Because this array looks obscure to new readers, also add a comment explaining the meaning of rows, columns and values. Signed-off-by: Josua Mayer Link: https://lore.kernel.org/r/20240106-fix-a38x-comphy-sd0-gbe0-v1-1-c7fd87272050@solid-run.com Signed-off-by: Vinod Koul --- drivers/phy/marvell/phy-armada38x-comphy.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/phy/marvell/phy-armada38x-comphy.c b/drivers/phy/marvell/phy-armada38x-comphy.c index b7d99861526a..d3259984ee8e 100644 --- a/drivers/phy/marvell/phy-armada38x-comphy.c +++ b/drivers/phy/marvell/phy-armada38x-comphy.c @@ -47,8 +47,13 @@ struct a38x_comphy { struct a38x_comphy_lane lane[MAX_A38X_COMPHY]; }; +/* + * Map serdes lanes and gbe ports to serdes mux configuration values: + * row index = serdes lane, + * column index = gbe port number. + */ static const u8 gbe_mux[MAX_A38X_COMPHY][MAX_A38X_PORTS] = { - { 0, 0, 0 }, + { 3, 0, 0 }, { 4, 5, 0 }, { 0, 4, 0 }, { 0, 0, 4 }, From 1cd2b08f7cc4a57cc1b04f62b6349970d13456c3 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Mon, 15 Jan 2024 14:02:09 -0800 Subject: [PATCH 047/814] KVM: arm64: selftests: Handle feature fields with nonzero minimum value correctly There are some feature fields with nonzero minimum valid value. Make sure get_safe_value() won't return invalid field values for them. Also fix a bug that wrongly uses the feature bits type as the feature bits sign causing all fields as signed in the get_safe_value() and get_invalid_value(). Fixes: 54a9ea73527d ("KVM: arm64: selftests: Test for setting ID register from usersapce") Reported-by: Zenghui Yu Reported-by: Itaru Kitayama Tested-by: Itaru Kitayama Signed-off-by: Jing Zhang Link: https://lore.kernel.org/r/20240115220210.3966064-2-jingzhangos@google.com Signed-off-by: Oliver Upton --- .../selftests/kvm/aarch64/set_id_regs.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/set_id_regs.c b/tools/testing/selftests/kvm/aarch64/set_id_regs.c index bac05210b539..16e2338686c1 100644 --- a/tools/testing/selftests/kvm/aarch64/set_id_regs.c +++ b/tools/testing/selftests/kvm/aarch64/set_id_regs.c @@ -32,6 +32,10 @@ struct reg_ftr_bits { enum ftr_type type; uint8_t shift; uint64_t mask; + /* + * For FTR_EXACT, safe_val is used as the exact safe value. + * For FTR_LOWER_SAFE, safe_val is used as the minimal safe value. + */ int64_t safe_val; }; @@ -65,13 +69,13 @@ struct test_feature_reg { static const struct reg_ftr_bits ftr_id_aa64dfr0_el1[] = { S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, PMUVer, 0), - REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, DebugVer, 0), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, DebugVer, ID_AA64DFR0_EL1_DebugVer_IMP), REG_FTR_END, }; static const struct reg_ftr_bits ftr_id_dfr0_el1[] = { - S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, PerfMon, 0), - REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, CopDbg, 0), + S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, PerfMon, ID_DFR0_EL1_PerfMon_PMUv3), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, CopDbg, ID_DFR0_EL1_CopDbg_Armv8), REG_FTR_END, }; @@ -224,13 +228,13 @@ uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) { uint64_t ftr_max = GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0); - if (ftr_bits->type == FTR_UNSIGNED) { + if (ftr_bits->sign == FTR_UNSIGNED) { switch (ftr_bits->type) { case FTR_EXACT: ftr = ftr_bits->safe_val; break; case FTR_LOWER_SAFE: - if (ftr > 0) + if (ftr > ftr_bits->safe_val) ftr--; break; case FTR_HIGHER_SAFE: @@ -252,7 +256,7 @@ uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) ftr = ftr_bits->safe_val; break; case FTR_LOWER_SAFE: - if (ftr > 0) + if (ftr > ftr_bits->safe_val) ftr--; break; case FTR_HIGHER_SAFE: @@ -276,7 +280,7 @@ uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) { uint64_t ftr_max = GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0); - if (ftr_bits->type == FTR_UNSIGNED) { + if (ftr_bits->sign == FTR_UNSIGNED) { switch (ftr_bits->type) { case FTR_EXACT: ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1); From 3c4f53b2c341ec6428b98cb51a89a09b025d0953 Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Mon, 22 Jan 2024 14:25:44 +0800 Subject: [PATCH 048/814] scsi: hisi_sas: Fix a deadlock issue related to automatic dump If we issue a disabling PHY command, the device attached with it will go offline, if a 2 bit ECC error occurs at the same time, a hung task may be found: [ 4613.652388] INFO: task kworker/u256:0:165233 blocked for more than 120 seconds. [ 4613.666297] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 4613.674809] task:kworker/u256:0 state:D stack: 0 pid:165233 ppid: 2 flags:0x00000208 [ 4613.683959] Workqueue: 0000:74:02.0_disco_q sas_revalidate_domain [libsas] [ 4613.691518] Call trace: [ 4613.694678] __switch_to+0xf8/0x17c [ 4613.698872] __schedule+0x660/0xee0 [ 4613.703063] schedule+0xac/0x240 [ 4613.706994] schedule_timeout+0x500/0x610 [ 4613.711705] __down+0x128/0x36c [ 4613.715548] down+0x240/0x2d0 [ 4613.719221] hisi_sas_internal_abort_timeout+0x1bc/0x260 [hisi_sas_main] [ 4613.726618] sas_execute_internal_abort+0x144/0x310 [libsas] [ 4613.732976] sas_execute_internal_abort_dev+0x44/0x60 [libsas] [ 4613.739504] hisi_sas_internal_task_abort_dev.isra.0+0xbc/0x1b0 [hisi_sas_main] [ 4613.747499] hisi_sas_dev_gone+0x174/0x250 [hisi_sas_main] [ 4613.753682] sas_notify_lldd_dev_gone+0xec/0x2e0 [libsas] [ 4613.759781] sas_unregister_common_dev+0x4c/0x7a0 [libsas] [ 4613.765962] sas_destruct_devices+0xb8/0x120 [libsas] [ 4613.771709] sas_do_revalidate_domain.constprop.0+0x1b8/0x31c [libsas] [ 4613.778930] sas_revalidate_domain+0x60/0xa4 [libsas] [ 4613.784716] process_one_work+0x248/0x950 [ 4613.789424] worker_thread+0x318/0x934 [ 4613.793878] kthread+0x190/0x200 [ 4613.797810] ret_from_fork+0x10/0x18 [ 4613.802121] INFO: task kworker/u256:4:316722 blocked for more than 120 seconds. [ 4613.816026] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 4613.824538] task:kworker/u256:4 state:D stack: 0 pid:316722 ppid: 2 flags:0x00000208 [ 4613.833670] Workqueue: 0000:74:02.0 hisi_sas_rst_work_handler [hisi_sas_main] [ 4613.841491] Call trace: [ 4613.844647] __switch_to+0xf8/0x17c [ 4613.848852] __schedule+0x660/0xee0 [ 4613.853052] schedule+0xac/0x240 [ 4613.856984] schedule_timeout+0x500/0x610 [ 4613.861695] __down+0x128/0x36c [ 4613.865542] down+0x240/0x2d0 [ 4613.869216] hisi_sas_controller_prereset+0x58/0x1fc [hisi_sas_main] [ 4613.876324] hisi_sas_rst_work_handler+0x40/0x8c [hisi_sas_main] [ 4613.883019] process_one_work+0x248/0x950 [ 4613.887732] worker_thread+0x318/0x934 [ 4613.892204] kthread+0x190/0x200 [ 4613.896118] ret_from_fork+0x10/0x18 [ 4613.900423] INFO: task kworker/u256:1:348985 blocked for more than 121 seconds. [ 4613.914341] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 4613.922852] task:kworker/u256:1 state:D stack: 0 pid:348985 ppid: 2 flags:0x00000208 [ 4613.931984] Workqueue: 0000:74:02.0_event_q sas_port_event_worker [libsas] [ 4613.939549] Call trace: [ 4613.942702] __switch_to+0xf8/0x17c [ 4613.946892] __schedule+0x660/0xee0 [ 4613.951083] schedule+0xac/0x240 [ 4613.955015] schedule_timeout+0x500/0x610 [ 4613.959725] wait_for_common+0x200/0x610 [ 4613.964349] wait_for_completion+0x3c/0x5c [ 4613.969146] flush_workqueue+0x198/0x790 [ 4613.973776] sas_porte_broadcast_rcvd+0x1e8/0x320 [libsas] [ 4613.979960] sas_port_event_worker+0x54/0xa0 [libsas] [ 4613.985708] process_one_work+0x248/0x950 [ 4613.990420] worker_thread+0x318/0x934 [ 4613.994868] kthread+0x190/0x200 [ 4613.998800] ret_from_fork+0x10/0x18 This is because when the device goes offline, we obtain the hisi_hba semaphore and send the ABORT_DEV command to the device. However, the internal abort timed out due to the 2 bit ECC error and triggers automatic dump. In addition, since the hisi_hba semaphore has been obtained, the dump cannot be executed and the controller cannot be reset. Therefore, the deadlocks occur on the following circular dependencies: hisi_sas_dev_gone() -> down() -> hisi_sas_internal_task_abort_dev() -> ... -> hisi_sas_internal_abort_timeout() -> down(). The deadlock is triggered only when the timeout occurs during device goes offline. To fix this issue, use .rst_ha_timeout to distinguish the scenario where a device goes offline from other scenarios. Fixes: 2ff07b5c6fe9 ("scsi: hisi_sas: Directly call register snapshot instead of using workqueue") Signed-off-by: Yihang Li Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1705904747-62186-2-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index bbb7b2d9ffcf..1abc62b07d24 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1962,9 +1962,17 @@ static bool hisi_sas_internal_abort_timeout(struct sas_task *task, struct hisi_sas_internal_abort_data *timeout = data; if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) { - down(&hisi_hba->sem); + /* + * If timeout occurs in device gone scenario, to avoid + * circular dependency like: + * hisi_sas_dev_gone() -> down() -> ... -> + * hisi_sas_internal_abort_timeout() -> down(). + */ + if (!timeout->rst_ha_timeout) + down(&hisi_hba->sem); hisi_hba->hw->debugfs_snapshot_regs(hisi_hba); - up(&hisi_hba->sem); + if (!timeout->rst_ha_timeout) + up(&hisi_hba->sem); } if (task->task_state_flags & SAS_TASK_STATE_DONE) { From 3f030550476566b12091687c70071d05ad433e0d Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Mon, 22 Jan 2024 14:25:45 +0800 Subject: [PATCH 049/814] scsi: hisi_sas: Remove redundant checks for automatic debugfs dump In commit 63f0733d07ce ("scsi: hisi_sas: Allocate DFX memory during dump trigger"), the memory allocation time of the DFX is changed from device initialization to dump occurs, so .debugfs_itct is not a valid address and do not need to check. The parameter hisi_sas_debugfs_enable is enough to check whether automatic debugfs dump is triggered, so remove redunant checks. Fixes: 63f0733d07ce ("scsi: hisi_sas: Allocate DFX memory during dump trigger") Signed-off-by: Yihang Li Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1705904747-62186-3-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 1abc62b07d24..70c998d33ec9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1573,7 +1573,7 @@ static int hisi_sas_controller_prereset(struct hisi_hba *hisi_hba) return -EPERM; } - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) + if (hisi_sas_debugfs_enable) hisi_hba->hw->debugfs_snapshot_regs(hisi_hba); return 0; @@ -1961,7 +1961,7 @@ static bool hisi_sas_internal_abort_timeout(struct sas_task *task, struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct hisi_sas_internal_abort_data *timeout = data; - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) { + if (hisi_sas_debugfs_enable) { /* * If timeout occurs in device gone scenario, to avoid * circular dependency like: From 69097a631c034451a75ca7cb6025460ba3a08f80 Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Mon, 22 Jan 2024 14:25:46 +0800 Subject: [PATCH 050/814] scsi: hisi_sas: Check whether debugfs is enabled before removing or releasing it hisi_sas debugfs remove should be executed only when debugfs is enabled. Check whether debugfs is enabled and then remove it only if enabled. Signed-off-by: Yihang Li Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1705904747-62186-4-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ++- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 70c998d33ec9..0b66c733a40d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2625,7 +2625,8 @@ static __exit void hisi_sas_exit(void) { sas_release_transport(hisi_sas_stt); - debugfs_remove(hisi_sas_debugfs_dir); + if (hisi_sas_debugfs_enable) + debugfs_remove(hisi_sas_debugfs_dir); } module_init(hisi_sas_init); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index b56fbc61a15a..033298d59402 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4902,7 +4902,8 @@ err_out_unregister_ha: err_out_remove_host: scsi_remove_host(shost); err_out_undo_debugfs: - debugfs_exit_v3_hw(hisi_hba); + if (hisi_sas_debugfs_enable) + debugfs_exit_v3_hw(hisi_hba); err_out_free_host: hisi_sas_free(hisi_hba); scsi_host_put(shost); @@ -4942,7 +4943,9 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) hisi_sas_v3_destroy_irqs(pdev, hisi_hba); hisi_sas_free(hisi_hba); - debugfs_exit_v3_hw(hisi_hba); + if (hisi_sas_debugfs_enable) + debugfs_exit_v3_hw(hisi_hba); + scsi_host_put(shost); } From f9242f166770b681d9f71341d96adc01c4da00ef Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 22 Jan 2024 14:25:47 +0800 Subject: [PATCH 051/814] scsi: hisi_sas: Remove hisi_hba->timer for v3 hw hisi_hba->timer is not used for v3 hw but there are two places that some operations related to hisi_hba->timer are called by v3 hw: - Deleting the timer in function hisi_sas_v3_hw() which is only for v3 hw; - Deleting the timer in function hisi_sas_controller_reset_prepare() which is common for v1/v2/v3 hw. We can remove the timer in the first case, but for the second scenario we need to remove it only for v3 hw, so check hw->sht which is NULL only for v3 hw before deleting hisi_hba->timer. Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1705904747-62186-5-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 7 ++++++- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 0b66c733a40d..097dfe4b620d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1507,7 +1507,12 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) scsi_block_requests(shost); hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); - del_timer_sync(&hisi_hba->timer); + /* + * hisi_hba->timer is only used for v1/v2 hw, and check hw->sht + * which is also only used for v1/v2 hw to skip it for v3 hw + */ + if (hisi_hba->hw->sht) + del_timer_sync(&hisi_hba->timer); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 033298d59402..7d2a33514538 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4935,7 +4935,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) struct Scsi_Host *shost = sha->shost; pm_runtime_get_noresume(dev); - del_timer_sync(&hisi_hba->timer); sas_unregister_ha(sha); flush_workqueue(hisi_hba->wq); From 883a8b451cf4c659d5bba0becfc3780394b597c8 Mon Sep 17 00:00:00 2001 From: Andrew Halaney Date: Tue, 23 Jan 2024 13:13:36 -0600 Subject: [PATCH 052/814] scsi: ufs: qcom: Clarify comments about the initial phy_gear The comments that currently are within the hw_ver < 4 conditional are misleading. They really apply to various branches of the conditionals there and incorrectly state that the phy_gear value can increase. Right now the logic is to: - Default to max supported gear for phy_gear - Set phy_gear to minimum value if version < 4 since those versions only support one PHY init sequence (and therefore don't need reinit) - Set phy_gear to the optimal value if the device version is already populated in the controller registers on boot Let's move some of the comment to outside the if statement and clean up the bit left about switching to a higher gear on reinit. This way the comment more accurately reflects the logic. Signed-off-by: Andrew Halaney Link: https://lore.kernel.org/r/20240123-ufs-reinit-comments-v1-1-ff2b3532d7fe@redhat.com Reviewed-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 39eef470f8fa..d9ec2dfbbda4 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -843,15 +843,20 @@ static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) struct ufs_host_params *host_params = &host->host_params; u32 val, dev_major; + /* + * Default to powering up the PHY to the max gear possible, which is + * backwards compatible with lower gears but not optimal from + * a power usage point of view. After device negotiation, if the + * gear is lower a reinit will be performed to program the PHY + * to the ideal gear for this combo of controller and device. + */ host->phy_gear = host_params->hs_tx_gear; if (host->hw_ver.major < 0x4) { /* - * For controllers whose major HW version is < 4, power up the - * PHY using minimum supported gear (UFS_HS_G2). Switching to - * max gear will be performed during reinit if supported. - * For newer controllers, whose major HW version is >= 4, power - * up the PHY using max supported gear. + * These controllers only have one PHY init sequence, + * let's power up the PHY using that (the minimum supported + * gear, UFS_HS_G2). */ host->phy_gear = UFS_HS_G2; } else if (host->hw_ver.major >= 0x5) { From 10a39667a117daf0c1baaebcbe589715ee79178b Mon Sep 17 00:00:00 2001 From: Eric Chanudet Date: Tue, 23 Jan 2024 14:28:57 -0500 Subject: [PATCH 053/814] scsi: ufs: qcom: Avoid re-init quirk when gears match On sa8775p-ride, probing the HBA will go through the UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH path although the power info is the same during the second init. The REINIT quirk only applies starting with controller v4. For these, ufs_qcom_get_hs_gear() reads the highest supported gear when setting the host_params. After the negotiation, if the host and device are on the same gear, it is the highest gear supported between the two. Skip REINIT to save some time. Signed-off-by: Eric Chanudet Link: https://lore.kernel.org/r/20240123192854.1724905-4-echanude@redhat.com Reviewed-by: Manivannan Sadhasivam Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index d9ec2dfbbda4..0aeaee1c564c 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -738,8 +738,17 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, * the second init can program the optimal PHY settings. This allows one to start * the first init with either the minimum or the maximum support gear. */ - if (hba->ufshcd_state == UFSHCD_STATE_RESET) - host->phy_gear = dev_req_params->gear_tx; + if (hba->ufshcd_state == UFSHCD_STATE_RESET) { + /* + * Skip REINIT if the negotiated gear matches with the + * initial phy_gear. Otherwise, update the phy_gear to + * program the optimal gear setting during REINIT. + */ + if (host->phy_gear == dev_req_params->gear_tx) + hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + else + host->phy_gear = dev_req_params->gear_tx; + } /* enable the device ref clock before changing to HS mode */ if (!ufshcd_is_hs_mode(&hba->pwr_info) && From c0767560b012d07fb4915510e35148052cb83493 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 28 Dec 2023 17:18:09 +0530 Subject: [PATCH 054/814] scsi: mpt3sas: Reload SBR without rebooting HBA Add a new IOCTL command MPT3ENABLEDIAGSBRRELOAD. As a part of firmware update operation, applications use this IOCTL command to set the SBR reload bit in the Host Diagnostic register. This permits HBA firmware to be updated without powercycling the system. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312280909.MZyhxwBL-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202312281141.jDyPezRn-lkp@intel.com/ Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20231228114810.11923-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 113 ++++++++++++++++++--------- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 54 +++++++++++++ drivers/scsi/mpt3sas/mpt3sas_ctl.h | 10 +++ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1 + 5 files changed, 143 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8761bc58d965..fc8c45e15235 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5481,7 +5481,7 @@ mpt3sas_atto_validate_nvram(struct MPT3SAS_ADAPTER *ioc, * mpt3sas_atto_get_sas_addr - get the ATTO SAS address from mfg page 1 * * @ioc : per adapter object - * @*sas_addr : return sas address + * @sas_addr : return sas address * Return: 0 for success, non-zero for failure. */ static int @@ -7913,6 +7913,67 @@ mpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type) mutex_unlock(&ioc->base_cmds.mutex); } +/** +* mpt3sas_base_unlock_and_get_host_diagnostic- enable Host Diagnostic Register writes +* @ioc: per adapter object +* @host_diagnostic: host diagnostic register content +* +* Return: 0 for success, non-zero for failure. +*/ + +int +mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc, + u32 *host_diagnostic) +{ + + u32 count; + *host_diagnostic = 0; + count = 0; + + do { + /* Write magic sequence to WriteSequence register + * Loop until in diagnostic mode + */ + drsprintk(ioc, ioc_info(ioc, "write magic sequence\n")); + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); + + /* wait 100 msec */ + msleep(100); + + if (count++ > 20) { + ioc_info(ioc, + "Stop writing magic sequence after 20 retries\n"); + _base_dump_reg_set(ioc); + return -EFAULT; + } + + *host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); + drsprintk(ioc, + ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", + count, *host_diagnostic)); + + } while ((*host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); + return 0; +} + +/** + * mpt3sas_base_lock_host_diagnostic: Disable Host Diagnostic Register writes + * @ioc: per adapter object + */ + +void +mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc) +{ + drsprintk(ioc, ioc_info(ioc, "disable writes to the diagnostic register\n")); + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); +} + /** * _base_diag_reset - the "big hammer" start of day reset * @ioc: per adapter object @@ -7933,49 +7994,21 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) drsprintk(ioc, ioc_info(ioc, "clear interrupts\n")); - count = 0; - do { - /* Write magic sequence to WriteSequence register - * Loop until in diagnostic mode - */ - drsprintk(ioc, ioc_info(ioc, "write magic sequence\n")); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); - - /* wait 100 msec */ - msleep(100); - - if (count++ > 20) { - ioc_info(ioc, - "Stop writing magic sequence after 20 retries\n"); - _base_dump_reg_set(ioc); - goto out; - } - - host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); - drsprintk(ioc, - ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", - count, host_diagnostic)); - - } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); + mutex_lock(&ioc->hostdiag_unlock_mutex); + if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) + goto out; hcb_size = ioc->base_readl(&ioc->chip->HCBSize); - drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n")); writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, &ioc->chip->HostDiagnostic); - /*This delay allows the chip PCIe hardware time to finish reset tasks*/ + /* This delay allows the chip PCIe hardware time to finish reset tasks */ msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); /* Approximately 300 second max wait */ for (count = 0; count < (300000000 / - MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { + MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); @@ -7988,13 +8021,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) break; - msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC / 1000); + /* Wait to pass the second read delay window */ + msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC/1000); } if (host_diagnostic & MPI2_DIAG_HCB_MODE) { drsprintk(ioc, - ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n")); + ioc_info(ioc, "restart the adapter assuming the\n" + "HCB Address points to good F/W\n")); host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; writel(host_diagnostic, &ioc->chip->HostDiagnostic); @@ -8008,9 +8043,8 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, &ioc->chip->HostDiagnostic); - drsprintk(ioc, - ioc_info(ioc, "disable writes to the diagnostic register\n")); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); + mpt3sas_base_lock_host_diagnostic(ioc); + mutex_unlock(&ioc->hostdiag_unlock_mutex); drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n")); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20); @@ -8028,6 +8062,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) out: pci_cfg_access_unlock(ioc->pdev); ioc_err(ioc, "diag reset: FAILED\n"); + mutex_unlock(&ioc->hostdiag_unlock_mutex); return -EFAULT; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 6d0bc8c66700..de60ef8a7908 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1366,6 +1366,7 @@ struct MPT3SAS_ADAPTER { u8 got_task_abort_from_ioctl; struct mutex reset_in_progress_mutex; + struct mutex hostdiag_unlock_mutex; spinlock_t ioc_reset_in_progress_lock; u8 ioc_link_reset_in_progress; @@ -1790,6 +1791,9 @@ void mpt3sas_base_disable_msix(struct MPT3SAS_ADAPTER *ioc); int mpt3sas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num); void mpt3sas_base_pause_mq_polling(struct MPT3SAS_ADAPTER *ioc); void mpt3sas_base_resume_mq_polling(struct MPT3SAS_ADAPTER *ioc); +int mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc, + u32 *host_diagnostic); +void mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc); /* scsih shared API */ struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 147cb7088d55..1c9fd26195b8 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -2543,6 +2543,56 @@ out: return 0; } +/** + * _ctl_enable_diag_sbr_reload - enable sbr reload bit + * @ioc: per adapter object + * @arg: user space buffer containing ioctl content + * + * Enable the SBR reload bit + */ +static int +_ctl_enable_diag_sbr_reload(struct MPT3SAS_ADAPTER *ioc, void __user *arg) +{ + u32 ioc_state, host_diagnostic; + + if (ioc->shost_recovery || + ioc->pci_error_recovery || ioc->is_driver_loading || + ioc->remove_host) + return -EAGAIN; + + ioc_state = mpt3sas_base_get_iocstate(ioc, 1); + + if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) + return -EFAULT; + + host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic); + + if (host_diagnostic & MPI2_DIAG_SBR_RELOAD) + return 0; + + if (mutex_trylock(&ioc->hostdiag_unlock_mutex)) { + if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) { + mutex_unlock(&ioc->hostdiag_unlock_mutex); + return -EFAULT; + } + } else + return -EAGAIN; + + host_diagnostic |= MPI2_DIAG_SBR_RELOAD; + writel(host_diagnostic, &ioc->chip->HostDiagnostic); + host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic); + mpt3sas_base_lock_host_diagnostic(ioc); + mutex_unlock(&ioc->hostdiag_unlock_mutex); + + if (!(host_diagnostic & MPI2_DIAG_SBR_RELOAD)) { + ioc_err(ioc, "%s: Failed to set Diag SBR Reload Bit\n", __func__); + return -EFAULT; + } + + ioc_info(ioc, "%s: Successfully set the Diag SBR Reload Bit\n", __func__); + return 0; +} + #ifdef CONFIG_COMPAT /** * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. @@ -2719,6 +2769,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, if (_IOC_SIZE(cmd) == sizeof(struct mpt3_addnl_diag_query)) ret = _ctl_addnl_diag_query(ioc, arg); break; + case MPT3ENABLEDIAGSBRRELOAD: + if (_IOC_SIZE(cmd) == sizeof(struct mpt3_enable_diag_sbr_reload)) + ret = _ctl_enable_diag_sbr_reload(ioc, arg); + break; default: dctlprintk(ioc, ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index 8f6ffb40261c..171709e91006 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -98,6 +98,8 @@ struct mpt3_diag_read_buffer) #define MPT3ADDNLDIAGQUERY _IOWR(MPT3_MAGIC_NUMBER, 32, \ struct mpt3_addnl_diag_query) +#define MPT3ENABLEDIAGSBRRELOAD _IOWR(MPT3_MAGIC_NUMBER, 33, \ + struct mpt3_enable_diag_sbr_reload) /* Trace Buffer default UniqueId */ #define MPT2DIAGBUFFUNIQUEID (0x07075900) @@ -448,4 +450,12 @@ struct mpt3_addnl_diag_query { uint32_t reserved2[2]; }; +/** + * struct mpt3_enable_diag_sbr_reload - enable sbr reload + * @hdr - generic header + */ +struct mpt3_enable_diag_sbr_reload { + struct mpt3_ioctl_header hdr; +}; + #endif /* MPT3SAS_CTL_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 51b5788da040..ef8ee93005ea 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -12240,6 +12240,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); + mutex_init(&ioc->hostdiag_unlock_mutex); /* initializing pci_access_mutex lock */ mutex_init(&ioc->pci_access_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); From a34fc8c7361c4abb7474a77ce907065db371657f Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 28 Dec 2023 17:18:10 +0530 Subject: [PATCH 055/814] scsi: mpt3sas: Update driver version to 48.100.00.00 Update driver version to 48.100.00.00. Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20231228114810.11923-3-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index de60ef8a7908..bf100a4ebfc3 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -77,8 +77,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "43.100.00.00" -#define MPT3SAS_MAJOR_VERSION 43 +#define MPT3SAS_DRIVER_VERSION "48.100.00.00" +#define MPT3SAS_MAJOR_VERSION 48 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 From e01966e643c97eb8916bbbbbeceb687afb11f345 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 11:00:20 +0100 Subject: [PATCH 056/814] crypto: virtio - Less function calls in __virtio_crypto_akcipher_do_req() after error detection The kfree() function was called in up to two cases by the __virtio_crypto_akcipher_do_req() function during error handling even if the passed variable contained a null pointer. This issue was detected by using the Coccinelle software. * Adjust jump targets. * Delete two initialisations which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Reviewed-by: Gonglei Reviewed-by: Justin Stitt Signed-off-by: Herbert Xu --- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c index 2621ff8a9376..057da5bd8d30 100644 --- a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c @@ -224,11 +224,11 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request struct virtio_crypto *vcrypto = ctx->vcrypto; struct virtio_crypto_op_data_req *req_data = vc_req->req_data; struct scatterlist *sgs[4], outhdr_sg, inhdr_sg, srcdata_sg, dstdata_sg; - void *src_buf = NULL, *dst_buf = NULL; + void *src_buf, *dst_buf = NULL; unsigned int num_out = 0, num_in = 0; int node = dev_to_node(&vcrypto->vdev->dev); unsigned long flags; - int ret = -ENOMEM; + int ret; bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY; unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len; @@ -239,7 +239,7 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request /* src data */ src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node); if (!src_buf) - goto err; + return -ENOMEM; if (verify) { /* for verify operation, both src and dst data work as OUT direction */ @@ -254,7 +254,7 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request /* dst data */ dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); if (!dst_buf) - goto err; + goto free_src; sg_init_one(&dstdata_sg, dst_buf, req->dst_len); sgs[num_out + num_in++] = &dstdata_sg; @@ -277,9 +277,9 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request return 0; err: - kfree(src_buf); kfree(dst_buf); - +free_src: + kfree(src_buf); return -ENOMEM; } From 109303336a0cc8ed903d8b1b83114d79b841d8de Mon Sep 17 00:00:00 2001 From: Danny Tsen Date: Tue, 2 Jan 2024 15:58:56 -0500 Subject: [PATCH 057/814] crypto: vmx - Move to arch/powerpc/crypto Relocate all crypto files in vmx driver to arch/powerpc/crypto directory and remove vmx directory. drivers/crypto/vmx/aes.c rename to arch/powerpc/crypto/aes.c drivers/crypto/vmx/aes_cbc.c rename to arch/powerpc/crypto/aes_cbc.c drivers/crypto/vmx/aes_ctr.c rename to arch/powerpc/crypto/aes_ctr.c drivers/crypto/vmx/aes_xts.c rename to arch/powerpc/crypto/aes_xts.c drivers/crypto/vmx/aesp8-ppc.h rename to arch/powerpc/crypto/aesp8-ppc.h drivers/crypto/vmx/aesp8-ppc.pl rename to arch/powerpc/crypto/aesp8-ppc.pl drivers/crypto/vmx/ghash.c rename to arch/powerpc/crypto/ghash.c drivers/crypto/vmx/ghashp8-ppc.pl rename to arch/powerpc/crypto/ghashp8-ppc.pl drivers/crypto/vmx/vmx.c rename to arch/powerpc/crypto/vmx.c deleted files: drivers/crypto/vmx/Makefile drivers/crypto/vmx/Kconfig drivers/crypto/vmx/ppc-xlate.pl This patch has been tested has passed the selftest. The patch is also tested with CONFIG_CRYPTO_MANAGER_EXTRA_TESTS enabled. Signed-off-by: Danny Tsen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Kconfig | 20 ++ arch/powerpc/crypto/Makefile | 20 +- .../crypto/vmx => arch/powerpc/crypto}/aes.c | 0 .../vmx => arch/powerpc/crypto}/aes_cbc.c | 0 .../vmx => arch/powerpc/crypto}/aes_ctr.c | 0 .../vmx => arch/powerpc/crypto}/aes_xts.c | 0 .../vmx => arch/powerpc/crypto}/aesp8-ppc.h | 0 .../vmx => arch/powerpc/crypto}/aesp8-ppc.pl | 0 .../vmx => arch/powerpc/crypto}/ghash.c | 0 .../powerpc/crypto}/ghashp8-ppc.pl | 0 .../crypto/vmx => arch/powerpc/crypto}/vmx.c | 0 drivers/crypto/Kconfig | 14 +- drivers/crypto/Makefile | 2 +- drivers/crypto/vmx/.gitignore | 3 - drivers/crypto/vmx/Kconfig | 14 -- drivers/crypto/vmx/Makefile | 23 -- drivers/crypto/vmx/ppc-xlate.pl | 231 ------------------ 17 files changed, 46 insertions(+), 281 deletions(-) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aes.c (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aes_cbc.c (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aes_ctr.c (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aes_xts.c (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aesp8-ppc.h (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/aesp8-ppc.pl (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/ghash.c (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/ghashp8-ppc.pl (100%) rename {drivers/crypto/vmx => arch/powerpc/crypto}/vmx.c (100%) delete mode 100644 drivers/crypto/vmx/.gitignore delete mode 100644 drivers/crypto/vmx/Kconfig delete mode 100644 drivers/crypto/vmx/Makefile delete mode 100644 drivers/crypto/vmx/ppc-xlate.pl diff --git a/arch/powerpc/crypto/Kconfig b/arch/powerpc/crypto/Kconfig index 6fc2248ca561..1e201b7ae2fc 100644 --- a/arch/powerpc/crypto/Kconfig +++ b/arch/powerpc/crypto/Kconfig @@ -137,4 +137,24 @@ config CRYPTO_POLY1305_P10 - Power10 or later - Little-endian +config CRYPTO_DEV_VMX + bool "Support for VMX cryptographic acceleration instructions" + depends on PPC64 && VSX + help + Support for VMX cryptographic acceleration instructions. + +config CRYPTO_DEV_VMX_ENCRYPT + tristate "Encryption acceleration support on P8 CPU" + depends on CRYPTO_DEV_VMX + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_CTR + select CRYPTO_GHASH + select CRYPTO_XTS + default m + help + Support for VMX cryptographic acceleration instructions on Power8 CPU. + This module supports acceleration for AES and GHASH in hardware. If you + choose 'M' here, this module will be called vmx-crypto. + endmenu diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index ebdac1b9eb9a..fca0e9739869 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CRYPTO_VPMSUM_TESTER) += crc-vpmsum_test.o obj-$(CONFIG_CRYPTO_AES_GCM_P10) += aes-gcm-p10-crypto.o obj-$(CONFIG_CRYPTO_CHACHA20_P10) += chacha-p10-crypto.o obj-$(CONFIG_CRYPTO_POLY1305_P10) += poly1305-p10-crypto.o +obj-$(CONFIG_CRYPTO_DEV_VMX_ENCRYPT) += vmx-crypto.o aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes-spe-glue.o md5-ppc-y := md5-asm.o md5-glue.o @@ -27,14 +28,29 @@ crct10dif-vpmsum-y := crct10dif-vpmsum_asm.o crct10dif-vpmsum_glue.o aes-gcm-p10-crypto-y := aes-gcm-p10-glue.o aes-gcm-p10.o ghashp10-ppc.o aesp10-ppc.o chacha-p10-crypto-y := chacha-p10-glue.o chacha-p10le-8x.o poly1305-p10-crypto-y := poly1305-p10-glue.o poly1305-p10le_64.o +vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o aes_xts.o ghash.o + +ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) +override flavour := linux-ppc64le +else +ifdef CONFIG_PPC64_ELF_ABI_V2 +override flavour := linux-ppc64-elfv2 +else +override flavour := linux-ppc64 +endif +endif quiet_cmd_perl = PERL $@ - cmd_perl = $(PERL) $< $(if $(CONFIG_CPU_LITTLE_ENDIAN), linux-ppc64le, linux-ppc64) > $@ + cmd_perl = $(PERL) $< $(flavour) > $@ -targets += aesp10-ppc.S ghashp10-ppc.S +targets += aesp10-ppc.S ghashp10-ppc.S aesp8-ppc.S ghashp8-ppc.S $(obj)/aesp10-ppc.S $(obj)/ghashp10-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE $(call if_changed,perl) +$(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE + $(call if_changed,perl) + OBJECT_FILES_NON_STANDARD_aesp10-ppc.o := y OBJECT_FILES_NON_STANDARD_ghashp10-ppc.o := y +OBJECT_FILES_NON_STANDARD_aesp8-ppc.o := y diff --git a/drivers/crypto/vmx/aes.c b/arch/powerpc/crypto/aes.c similarity index 100% rename from drivers/crypto/vmx/aes.c rename to arch/powerpc/crypto/aes.c diff --git a/drivers/crypto/vmx/aes_cbc.c b/arch/powerpc/crypto/aes_cbc.c similarity index 100% rename from drivers/crypto/vmx/aes_cbc.c rename to arch/powerpc/crypto/aes_cbc.c diff --git a/drivers/crypto/vmx/aes_ctr.c b/arch/powerpc/crypto/aes_ctr.c similarity index 100% rename from drivers/crypto/vmx/aes_ctr.c rename to arch/powerpc/crypto/aes_ctr.c diff --git a/drivers/crypto/vmx/aes_xts.c b/arch/powerpc/crypto/aes_xts.c similarity index 100% rename from drivers/crypto/vmx/aes_xts.c rename to arch/powerpc/crypto/aes_xts.c diff --git a/drivers/crypto/vmx/aesp8-ppc.h b/arch/powerpc/crypto/aesp8-ppc.h similarity index 100% rename from drivers/crypto/vmx/aesp8-ppc.h rename to arch/powerpc/crypto/aesp8-ppc.h diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/arch/powerpc/crypto/aesp8-ppc.pl similarity index 100% rename from drivers/crypto/vmx/aesp8-ppc.pl rename to arch/powerpc/crypto/aesp8-ppc.pl diff --git a/drivers/crypto/vmx/ghash.c b/arch/powerpc/crypto/ghash.c similarity index 100% rename from drivers/crypto/vmx/ghash.c rename to arch/powerpc/crypto/ghash.c diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/arch/powerpc/crypto/ghashp8-ppc.pl similarity index 100% rename from drivers/crypto/vmx/ghashp8-ppc.pl rename to arch/powerpc/crypto/ghashp8-ppc.pl diff --git a/drivers/crypto/vmx/vmx.c b/arch/powerpc/crypto/vmx.c similarity index 100% rename from drivers/crypto/vmx/vmx.c rename to arch/powerpc/crypto/vmx.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0991f026cb07..3d02702456a5 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -611,13 +611,13 @@ config CRYPTO_DEV_QCOM_RNG To compile this driver as a module, choose M here. The module will be called qcom-rng. If unsure, say N. -config CRYPTO_DEV_VMX - bool "Support for VMX cryptographic acceleration instructions" - depends on PPC64 && VSX - help - Support for VMX cryptographic acceleration instructions. - -source "drivers/crypto/vmx/Kconfig" +#config CRYPTO_DEV_VMX +# bool "Support for VMX cryptographic acceleration instructions" +# depends on PPC64 && VSX +# help +# Support for VMX cryptographic acceleration instructions. +# +#source "drivers/crypto/vmx/Kconfig" config CRYPTO_DEV_IMGTEC_HASH tristate "Imagination Technologies hardware hash accelerator" diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index d859d6a5f3a4..95331bc6456b 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/ obj-y += stm32/ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/ -obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ +#obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/ obj-$(CONFIG_CRYPTO_DEV_SAFEXCEL) += inside-secure/ obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/ diff --git a/drivers/crypto/vmx/.gitignore b/drivers/crypto/vmx/.gitignore deleted file mode 100644 index 7aa71d83f739..000000000000 --- a/drivers/crypto/vmx/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -aesp8-ppc.S -ghashp8-ppc.S diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig deleted file mode 100644 index b2c28b87f14b..000000000000 --- a/drivers/crypto/vmx/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config CRYPTO_DEV_VMX_ENCRYPT - tristate "Encryption acceleration support on P8 CPU" - depends on CRYPTO_DEV_VMX - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_CTR - select CRYPTO_GHASH - select CRYPTO_XTS - default m - help - Support for VMX cryptographic acceleration instructions on Power8 CPU. - This module supports acceleration for AES and GHASH in hardware. If you - choose 'M' here, this module will be called vmx-crypto. diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile deleted file mode 100644 index 7257b8c44626..000000000000 --- a/drivers/crypto/vmx/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_CRYPTO_DEV_VMX_ENCRYPT) += vmx-crypto.o -vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o aes_xts.o ghash.o - -ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) -override flavour := linux-ppc64le -else -ifdef CONFIG_PPC64_ELF_ABI_V2 -override flavour := linux-ppc64-elfv2 -else -override flavour := linux-ppc64 -endif -endif - -quiet_cmd_perl = PERL $@ - cmd_perl = $(PERL) $< $(flavour) > $@ - -targets += aesp8-ppc.S ghashp8-ppc.S - -$(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE - $(call if_changed,perl) - -OBJECT_FILES_NON_STANDARD_aesp8-ppc.o := y diff --git a/drivers/crypto/vmx/ppc-xlate.pl b/drivers/crypto/vmx/ppc-xlate.pl deleted file mode 100644 index b583898c11ae..000000000000 --- a/drivers/crypto/vmx/ppc-xlate.pl +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0 - -# PowerPC assembler distiller by . - -my $flavour = shift; -my $output = shift; -open STDOUT,">$output" || die "can't open $output: $!"; - -my %GLOBALS; -my $dotinlocallabels=($flavour=~/linux/)?1:0; -my $elfv2abi=(($flavour =~ /linux-ppc64le/) or ($flavour =~ /linux-ppc64-elfv2/))?1:0; -my $dotfunctions=($elfv2abi=~1)?0:1; - -################################################################ -# directives which need special treatment on different platforms -################################################################ -my $globl = sub { - my $junk = shift; - my $name = shift; - my $global = \$GLOBALS{$name}; - my $ret; - - $name =~ s|^[\.\_]||; - - SWITCH: for ($flavour) { - /aix/ && do { $name = ".$name"; - last; - }; - /osx/ && do { $name = "_$name"; - last; - }; - /linux/ - && do { $ret = "_GLOBAL($name)"; - last; - }; - } - - $ret = ".globl $name\nalign 5\n$name:" if (!$ret); - $$global = $name; - $ret; -}; -my $text = sub { - my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; - $ret = ".abiversion 2\n".$ret if ($elfv2abi); - $ret; -}; -my $machine = sub { - my $junk = shift; - my $arch = shift; - if ($flavour =~ /osx/) - { $arch =~ s/\"//g; - $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); - } - ".machine $arch"; -}; -my $size = sub { - if ($flavour =~ /linux/) - { shift; - my $name = shift; $name =~ s|^[\.\_]||; - my $ret = ".size $name,.-".($dotfunctions?".":"").$name; - $ret .= "\n.size .$name,.-.$name" if ($dotfunctions); - $ret; - } - else - { ""; } -}; -my $asciz = sub { - shift; - my $line = join(",",@_); - if ($line =~ /^"(.*)"$/) - { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } - else - { ""; } -}; -my $quad = sub { - shift; - my @ret; - my ($hi,$lo); - for (@_) { - if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) - { $hi=$1?"0x$1":"0"; $lo="0x$2"; } - elsif (/^([0-9]+)$/o) - { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl - else - { $hi=undef; $lo=$_; } - - if (defined($hi)) - { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } - else - { push(@ret,".quad $lo"); } - } - join("\n",@ret); -}; - -################################################################ -# simplified mnemonics not handled by at least one assembler -################################################################ -my $cmplw = sub { - my $f = shift; - my $cr = 0; $cr = shift if ($#_>1); - # Some out-of-date 32-bit GNU assembler just can't handle cmplw... - ($flavour =~ /linux.*32/) ? - " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : - " cmplw ".join(',',$cr,@_); -}; -my $bdnz = sub { - my $f = shift; - my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint - " bc $bo,0,".shift; -} if ($flavour!~/linux/); -my $bltlr = sub { - my $f = shift; - my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint - ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints - " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : - " bclr $bo,0"; -}; -my $bnelr = sub { - my $f = shift; - my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint - ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints - " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : - " bclr $bo,2"; -}; -my $beqlr = sub { - my $f = shift; - my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint - ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints - " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : - " bclr $bo,2"; -}; -# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two -# arguments is 64, with "operand out of range" error. -my $extrdi = sub { - my ($f,$ra,$rs,$n,$b) = @_; - $b = ($b+$n)&63; $n = 64-$n; - " rldicl $ra,$rs,$b,$n"; -}; -my $vmr = sub { - my ($f,$vx,$vy) = @_; - " vor $vx,$vy,$vy"; -}; - -# Some ABIs specify vrsave, special-purpose register #256, as reserved -# for system use. -my $no_vrsave = ($elfv2abi); -my $mtspr = sub { - my ($f,$idx,$ra) = @_; - if ($idx == 256 && $no_vrsave) { - " or $ra,$ra,$ra"; - } else { - " mtspr $idx,$ra"; - } -}; -my $mfspr = sub { - my ($f,$rd,$idx) = @_; - if ($idx == 256 && $no_vrsave) { - " li $rd,-1"; - } else { - " mfspr $rd,$idx"; - } -}; - -# PowerISA 2.06 stuff -sub vsxmem_op { - my ($f, $vrt, $ra, $rb, $op) = @_; - " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); -} -# made-up unaligned memory reference AltiVec/VMX instructions -my $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x -my $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x -my $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx -my $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx -my $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x -my $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x - -# PowerISA 2.07 stuff -sub vcrypto_op { - my ($f, $vrt, $vra, $vrb, $op) = @_; - " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; -} -my $vcipher = sub { vcrypto_op(@_, 1288); }; -my $vcipherlast = sub { vcrypto_op(@_, 1289); }; -my $vncipher = sub { vcrypto_op(@_, 1352); }; -my $vncipherlast= sub { vcrypto_op(@_, 1353); }; -my $vsbox = sub { vcrypto_op(@_, 0, 1480); }; -my $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; -my $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; -my $vpmsumb = sub { vcrypto_op(@_, 1032); }; -my $vpmsumd = sub { vcrypto_op(@_, 1224); }; -my $vpmsubh = sub { vcrypto_op(@_, 1096); }; -my $vpmsumw = sub { vcrypto_op(@_, 1160); }; -my $vaddudm = sub { vcrypto_op(@_, 192); }; -my $vadduqm = sub { vcrypto_op(@_, 256); }; - -my $mtsle = sub { - my ($f, $arg) = @_; - " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); -}; - -print "#include \n" if $flavour =~ /linux/; - -while($line=<>) { - - $line =~ s|[#!;].*$||; # get rid of asm-style comments... - $line =~ s|/\*.*\*/||; # ... and C-style comments... - $line =~ s|^\s+||; # ... and skip white spaces in beginning... - $line =~ s|\s+$||; # ... and at the end - - { - $line =~ s|\b\.L(\w+)|L$1|g; # common denominator for Locallabel - $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); - } - - { - $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; - my $c = $1; $c = "\t" if ($c eq ""); - my $mnemonic = $2; - my $f = $3; - my $opcode = eval("\$$mnemonic"); - $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); - if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } - elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } - } - - print $line if ($line); - print "\n"; -} - -close STDOUT; From 23a22e831ed4e6aa0831312e8cc8b7c60a657f60 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 3 Jan 2024 17:26:02 +0100 Subject: [PATCH 058/814] crypto: qat - avoid memcpy() overflow warning The use of array_size() leads gcc to assume the memcpy() can have a larger limit than actually possible, which triggers a string fortification warning: In file included from include/linux/string.h:296, from include/linux/bitmap.h:12, from include/linux/cpumask.h:12, from include/linux/sched.h:16, from include/linux/delay.h:23, from include/linux/iopoll.h:12, from drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c:3: In function 'fortify_memcpy_chk', inlined from 'adf_gen4_init_thd2arb_map' at drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c:401:3: include/linux/fortify-string.h:579:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] 579 | __write_overflow_field(p_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/fortify-string.h:588:4: error: call to '__read_overflow2_field' declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Werror=attribute-warning] 588 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add an explicit range check to avoid this. Fixes: 5da6a2d5353e ("crypto: qat - generate dynamically arbiter mappings") Signed-off-by: Arnd Bergmann Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c index 9985683056d5..f752653ccb47 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c @@ -398,6 +398,9 @@ int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev) ADF_GEN4_ADMIN_ACCELENGINES; if (srv_id == SVC_DCC) { + if (ae_cnt > ICP_QAT_HW_AE_DELIMITER) + return -EINVAL; + memcpy(thd2arb_map, thrd_to_arb_map_dcc, array_size(sizeof(*thd2arb_map), ae_cnt)); return 0; From 5d7e1c411c0d703e51cc812a3dac22f1f0b11253 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 5 Jan 2024 17:15:43 +0100 Subject: [PATCH 059/814] dt-bindings: qcom-qce: Add compatible for SM6350 Add a compatible for the crypto block found on the SM6350 SoC. Signed-off-by: Luca Weiss Acked-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index a48bd381063a..e285e382d4ec 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -45,6 +45,7 @@ properties: - items: - enum: - qcom,sc7280-qce + - qcom,sm6350-qce - qcom,sm8250-qce - qcom,sm8350-qce - qcom,sm8450-qce From 4bb439e8562d36af715f2c22d23c5c3ad5563061 Mon Sep 17 00:00:00 2001 From: Clay Chang Date: Sun, 7 Jan 2024 21:28:42 +0800 Subject: [PATCH 060/814] KEYS: include header for EINVAL definition This patch includes linux/errno.h to address the issue of 'EINVAL' being undeclared. Signed-off-by: Clay Chang Signed-off-by: Herbert Xu --- include/crypto/public_key.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 462f8a34cdf8..b7f308977c84 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -10,6 +10,7 @@ #ifndef _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H +#include #include #include From 3274819b3c81c18c01e3c0e0ea726870ec237ac0 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Mon, 8 Jan 2024 16:53:48 -0600 Subject: [PATCH 061/814] crypto: iaa - Remove header table code The header table and related code is currently unused - it was included and used for canned mode, but canned mode has been removed, so this code can be safely removed as well. This indirectly fixes a bug reported by Dan Carpenter. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-crypto/b2e0bd974981291e16882686a2b9b1db3986abe4.camel@linux.intel.com/T/#m4403253d6a4347a925fab4fc1cdb4ef7c095fb86 Signed-off-by: Tom Zanussi Reviewed-by: Dave Jiang Signed-off-by: Herbert Xu --- drivers/crypto/intel/iaa/iaa_crypto.h | 25 ---- .../crypto/intel/iaa/iaa_crypto_comp_fixed.c | 1 - drivers/crypto/intel/iaa/iaa_crypto_main.c | 108 +----------------- 3 files changed, 3 insertions(+), 131 deletions(-) diff --git a/drivers/crypto/intel/iaa/iaa_crypto.h b/drivers/crypto/intel/iaa/iaa_crypto.h index 014420f7beb0..2524091a5f70 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto.h +++ b/drivers/crypto/intel/iaa/iaa_crypto.h @@ -59,10 +59,8 @@ struct iaa_device_compression_mode { const char *name; struct aecs_comp_table_record *aecs_comp_table; - struct aecs_decomp_table_record *aecs_decomp_table; dma_addr_t aecs_comp_table_dma_addr; - dma_addr_t aecs_decomp_table_dma_addr; }; /* Representation of IAA device with wqs, populated by probe */ @@ -107,23 +105,6 @@ struct aecs_comp_table_record { u32 reserved_padding[2]; } __packed; -/* AECS for decompress */ -struct aecs_decomp_table_record { - u32 crc; - u32 xor_checksum; - u32 low_filter_param; - u32 high_filter_param; - u32 output_mod_idx; - u32 drop_init_decomp_out_bytes; - u32 reserved[36]; - u32 output_accum_data[2]; - u32 out_bits_valid; - u32 bit_off_indexing; - u32 input_accum_data[64]; - u8 size_qw[32]; - u32 decomp_state[1220]; -} __packed; - int iaa_aecs_init_fixed(void); void iaa_aecs_cleanup_fixed(void); @@ -136,9 +117,6 @@ struct iaa_compression_mode { int ll_table_size; u32 *d_table; int d_table_size; - u32 *header_table; - int header_table_size; - u16 gen_decomp_table_flags; iaa_dev_comp_init_fn_t init; iaa_dev_comp_free_fn_t free; }; @@ -148,9 +126,6 @@ int add_iaa_compression_mode(const char *name, int ll_table_size, const u32 *d_table, int d_table_size, - const u8 *header_table, - int header_table_size, - u16 gen_decomp_table_flags, iaa_dev_comp_init_fn_t init, iaa_dev_comp_free_fn_t free); diff --git a/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c b/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c index 45cf5d74f0fb..19d9a333ac49 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c @@ -78,7 +78,6 @@ int iaa_aecs_init_fixed(void) sizeof(fixed_ll_sym), fixed_d_sym, sizeof(fixed_d_sym), - NULL, 0, 0, init_fixed_mode, NULL); if (!ret) pr_debug("IAA fixed compression mode initialized\n"); diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index dfd3baf0a8d8..39a5fc905c4d 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -258,16 +258,14 @@ static void free_iaa_compression_mode(struct iaa_compression_mode *mode) kfree(mode->name); kfree(mode->ll_table); kfree(mode->d_table); - kfree(mode->header_table); kfree(mode); } /* - * IAA Compression modes are defined by an ll_table, a d_table, and an - * optional header_table. These tables are typically generated and - * captured using statistics collected from running actual - * compress/decompress workloads. + * IAA Compression modes are defined by an ll_table and a d_table. + * These tables are typically generated and captured using statistics + * collected from running actual compress/decompress workloads. * * A module or other kernel code can add and remove compression modes * with a given name using the exported @add_iaa_compression_mode() @@ -315,9 +313,6 @@ EXPORT_SYMBOL_GPL(remove_iaa_compression_mode); * @ll_table_size: The ll table size in bytes * @d_table: The d table * @d_table_size: The d table size in bytes - * @header_table: Optional header table - * @header_table_size: Optional header table size in bytes - * @gen_decomp_table_flags: Otional flags used to generate the decomp table * @init: Optional callback function to init the compression mode data * @free: Optional callback function to free the compression mode data * @@ -330,9 +325,6 @@ int add_iaa_compression_mode(const char *name, int ll_table_size, const u32 *d_table, int d_table_size, - const u8 *header_table, - int header_table_size, - u16 gen_decomp_table_flags, iaa_dev_comp_init_fn_t init, iaa_dev_comp_free_fn_t free) { @@ -370,16 +362,6 @@ int add_iaa_compression_mode(const char *name, mode->d_table_size = d_table_size; } - if (header_table) { - mode->header_table = kzalloc(header_table_size, GFP_KERNEL); - if (!mode->header_table) - goto free; - memcpy(mode->header_table, header_table, header_table_size); - mode->header_table_size = header_table_size; - } - - mode->gen_decomp_table_flags = gen_decomp_table_flags; - mode->init = init; mode->free = free; @@ -420,10 +402,6 @@ static void free_device_compression_mode(struct iaa_device *iaa_device, if (device_mode->aecs_comp_table) dma_free_coherent(dev, size, device_mode->aecs_comp_table, device_mode->aecs_comp_table_dma_addr); - if (device_mode->aecs_decomp_table) - dma_free_coherent(dev, size, device_mode->aecs_decomp_table, - device_mode->aecs_decomp_table_dma_addr); - kfree(device_mode); } @@ -440,73 +418,6 @@ static int check_completion(struct device *dev, bool compress, bool only_once); -static int decompress_header(struct iaa_device_compression_mode *device_mode, - struct iaa_compression_mode *mode, - struct idxd_wq *wq) -{ - dma_addr_t src_addr, src2_addr; - struct idxd_desc *idxd_desc; - struct iax_hw_desc *desc; - struct device *dev; - int ret = 0; - - idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK); - if (IS_ERR(idxd_desc)) - return PTR_ERR(idxd_desc); - - desc = idxd_desc->iax_hw; - - dev = &wq->idxd->pdev->dev; - - src_addr = dma_map_single(dev, (void *)mode->header_table, - mode->header_table_size, DMA_TO_DEVICE); - dev_dbg(dev, "%s: mode->name %s, src_addr %llx, dev %p, src %p, slen %d\n", - __func__, mode->name, src_addr, dev, - mode->header_table, mode->header_table_size); - if (unlikely(dma_mapping_error(dev, src_addr))) { - dev_dbg(dev, "dma_map_single err, exiting\n"); - ret = -ENOMEM; - return ret; - } - - desc->flags = IAX_AECS_GEN_FLAG; - desc->opcode = IAX_OPCODE_DECOMPRESS; - - desc->src1_addr = (u64)src_addr; - desc->src1_size = mode->header_table_size; - - src2_addr = device_mode->aecs_decomp_table_dma_addr; - desc->src2_addr = (u64)src2_addr; - desc->src2_size = 1088; - dev_dbg(dev, "%s: mode->name %s, src2_addr %llx, dev %p, src2_size %d\n", - __func__, mode->name, desc->src2_addr, dev, desc->src2_size); - desc->max_dst_size = 0; // suppressed output - - desc->decompr_flags = mode->gen_decomp_table_flags; - - desc->priv = 0; - - desc->completion_addr = idxd_desc->compl_dma; - - ret = idxd_submit_desc(wq, idxd_desc); - if (ret) { - pr_err("%s: submit_desc failed ret=0x%x\n", __func__, ret); - goto out; - } - - ret = check_completion(dev, idxd_desc->iax_completion, false, false); - if (ret) - dev_dbg(dev, "%s: mode->name %s check_completion failed ret=%d\n", - __func__, mode->name, ret); - else - dev_dbg(dev, "%s: mode->name %s succeeded\n", __func__, - mode->name); -out: - dma_unmap_single(dev, src_addr, 1088, DMA_TO_DEVICE); - - return ret; -} - static int init_device_compression_mode(struct iaa_device *iaa_device, struct iaa_compression_mode *mode, int idx, struct idxd_wq *wq) @@ -529,24 +440,11 @@ static int init_device_compression_mode(struct iaa_device *iaa_device, if (!device_mode->aecs_comp_table) goto free; - device_mode->aecs_decomp_table = dma_alloc_coherent(dev, size, - &device_mode->aecs_decomp_table_dma_addr, GFP_KERNEL); - if (!device_mode->aecs_decomp_table) - goto free; - /* Add Huffman table to aecs */ memset(device_mode->aecs_comp_table, 0, sizeof(*device_mode->aecs_comp_table)); memcpy(device_mode->aecs_comp_table->ll_sym, mode->ll_table, mode->ll_table_size); memcpy(device_mode->aecs_comp_table->d_sym, mode->d_table, mode->d_table_size); - if (mode->header_table) { - ret = decompress_header(device_mode, mode, wq); - if (ret) { - pr_debug("iaa header decompression failed: ret=%d\n", ret); - goto free; - } - } - if (mode->init) { ret = mode->init(device_mode); if (ret) From cc342dba0d39f226f4a5e26194404c3785481470 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Tue, 9 Jan 2024 10:19:14 +0800 Subject: [PATCH 062/814] crypto: iaa - Remove unnecessary debugfs_create_dir() error check in iaa_crypto_debugfs_init() This patch removes the debugfs_create_dir() error checking in iaa_crypto_debugfs_init(). Because the debugfs_create_dir() is developed in a way that the caller can safely handle the errors that occur during the creation of DebugFS nodes. Signed-off-by: Minjie Du Acked-by: Tom Zanussi Signed-off-by: Herbert Xu --- drivers/crypto/intel/iaa/iaa_crypto_stats.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.c b/drivers/crypto/intel/iaa/iaa_crypto_stats.c index 2e3b7b73af20..cbf87d0effe3 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_stats.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.c @@ -275,8 +275,6 @@ int __init iaa_crypto_debugfs_init(void) return -ENODEV; iaa_crypto_debugfs_root = debugfs_create_dir("iaa_crypto", NULL); - if (!iaa_crypto_debugfs_root) - return -ENOMEM; debugfs_create_u64("max_comp_delay_ns", 0644, iaa_crypto_debugfs_root, &max_comp_delay_ns); From 8413fe3e7fdfb412baa9e31b3f1d2eaf6d21a373 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Fri, 12 Jan 2024 18:25:45 +0800 Subject: [PATCH 063/814] crypto: hisilicon/qm - support get device state Support get device current state. The value 0 indicates that the device is busy, and the value 1 indicates that the device is idle. When the device is in suspended, 1 is returned. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- Documentation/ABI/testing/debugfs-hisi-hpre | 7 +++++ Documentation/ABI/testing/debugfs-hisi-sec | 7 +++++ Documentation/ABI/testing/debugfs-hisi-zip | 7 +++++ drivers/crypto/hisilicon/debugfs.c | 29 +++++++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre index 8e8de49c5cc6..6ed9258605c7 100644 --- a/Documentation/ABI/testing/debugfs-hisi-hpre +++ b/Documentation/ABI/testing/debugfs-hisi-hpre @@ -111,6 +111,13 @@ Description: QM debug registers(regs) read hardware register value. This node is used to show the change of the qm register values. This node can be help users to check the change of register values. +What: /sys/kernel/debug/hisi_hpre//qm/qm_state +Date: Jan 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the state of the device. + 0: busy, 1: idle. + Only available for PF, and take no other effect on HPRE. + What: /sys/kernel/debug/hisi_hpre//hpre_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec index deeefe2c735e..403f5de96318 100644 --- a/Documentation/ABI/testing/debugfs-hisi-sec +++ b/Documentation/ABI/testing/debugfs-hisi-sec @@ -91,6 +91,13 @@ Description: QM debug registers(regs) read hardware register value. This node is used to show the change of the qm register values. This node can be help users to check the change of register values. +What: /sys/kernel/debug/hisi_sec2//qm/qm_state +Date: Jan 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the state of the device. + 0: busy, 1: idle. + Only available for PF, and take no other effect on SEC. + What: /sys/kernel/debug/hisi_sec2//sec_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip index 593714afaed2..2394e6a3cfe2 100644 --- a/Documentation/ABI/testing/debugfs-hisi-zip +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -104,6 +104,13 @@ Description: QM debug registers(regs) read hardware register value. This node is used to show the change of the qm registers value. This node can be help users to check the change of register values. +What: /sys/kernel/debug/hisi_zip//qm/qm_state +Date: Jan 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the state of the device. + 0: busy, 1: idle. + Only available for PF, and take no other effect on ZIP. + What: /sys/kernel/debug/hisi_zip//zip_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 80ed4b2d209c..615c8e18d8b0 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -24,6 +24,8 @@ #define QM_DFX_QN_SHIFT 16 #define QM_DFX_CNT_CLR_CE 0x100118 #define QM_DBG_WRITE_LEN 1024 +#define QM_IN_IDLE_ST_REG 0x1040e4 +#define QM_IN_IDLE_STATE 0x1 static const char * const qm_debug_file_name[] = { [CURRENT_QM] = "current_qm", @@ -1001,6 +1003,30 @@ static int qm_diff_regs_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(qm_diff_regs); +static int qm_state_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + u32 val; + int ret; + + /* If device is in suspended, directly return the idle state. */ + ret = hisi_qm_get_dfx_access(qm); + if (!ret) { + val = readl(qm->io_base + QM_IN_IDLE_ST_REG); + hisi_qm_put_dfx_access(qm); + } else if (ret == -EAGAIN) { + val = QM_IN_IDLE_STATE; + } else { + return ret; + } + + seq_printf(s, "%u\n", val); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(qm_state); + static ssize_t qm_status_read(struct file *filp, char __user *buffer, size_t count, loff_t *pos) { @@ -1072,6 +1098,9 @@ void hisi_qm_debug_init(struct hisi_qm *qm) /* only show this in PF */ if (qm->fun_type == QM_HW_PF) { + debugfs_create_file("qm_state", 0444, qm->debug.qm_d, + qm, &qm_state_fops); + qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM); for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++) qm_create_debugfs_file(qm, qm->debug.qm_d, i); From 8db78dd6cca25f558676b31c31a84771bfa5b51d Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Fri, 12 Jan 2024 18:25:46 +0800 Subject: [PATCH 064/814] crypto: hisilicon/qm - dump important registers values before resetting Read the values of some device registers before the device is reset, these values help analyze the cause of the device exception. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/debugfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 615c8e18d8b0..06e67eda409f 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -83,6 +83,30 @@ static const struct debugfs_reg32 qm_dfx_regs[] = { {"QM_DFX_FF_ST5 ", 0x1040dc}, {"QM_DFX_FF_ST6 ", 0x1040e0}, {"QM_IN_IDLE_ST ", 0x1040e4}, + {"QM_CACHE_CTL ", 0x100050}, + {"QM_TIMEOUT_CFG ", 0x100070}, + {"QM_DB_TIMEOUT_CFG ", 0x100074}, + {"QM_FLR_PENDING_TIME_CFG ", 0x100078}, + {"QM_ARUSR_MCFG1 ", 0x100088}, + {"QM_AWUSR_MCFG1 ", 0x100098}, + {"QM_AXI_M_CFG_ENABLE ", 0x1000B0}, + {"QM_RAS_CE_THRESHOLD ", 0x1000F8}, + {"QM_AXI_TIMEOUT_CTRL ", 0x100120}, + {"QM_AXI_TIMEOUT_STATUS ", 0x100124}, + {"QM_CQE_AGGR_TIMEOUT_CTRL ", 0x100144}, + {"ACC_RAS_MSI_INT_SEL ", 0x1040fc}, + {"QM_CQE_OUT ", 0x104100}, + {"QM_EQE_OUT ", 0x104104}, + {"QM_AEQE_OUT ", 0x104108}, + {"QM_DB_INFO0 ", 0x104180}, + {"QM_DB_INFO1 ", 0x104184}, + {"QM_AM_CTRL_GLOBAL ", 0x300000}, + {"QM_AM_CURR_PORT_STS ", 0x300100}, + {"QM_AM_CURR_TRANS_RETURN ", 0x300150}, + {"QM_AM_CURR_RD_MAX_TXID ", 0x300154}, + {"QM_AM_CURR_WR_MAX_TXID ", 0x300158}, + {"QM_AM_ALARM_RRESP ", 0x300180}, + {"QM_AM_ALARM_BRESP ", 0x300184}, }; static const struct debugfs_reg32 qm_vf_dfx_regs[] = { From 1bfde2c572b93e28a8f10212367aa0d5a8164c6a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Jan 2024 10:43:02 +0000 Subject: [PATCH 065/814] crypto: pcbc - remove redundant assignment to nbytes The assignment to nbytes is redundant, the while loop needs to just refer to the value in walk.nbytes and the value of nbytes is being re-assigned inside the loop on both paths of the following if-statement. Remove redundant assignment. Cleans up clang scan build warning: warning: Although the value stored to 'nbytes' is used in the enclosing expression, the value is never actually read from 'nbytes' [deadcode.DeadStores] Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- crypto/pcbc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/pcbc.c b/crypto/pcbc.c index 7030f59e46b6..ab469ba50c13 100644 --- a/crypto/pcbc.c +++ b/crypto/pcbc.c @@ -71,7 +71,7 @@ static int crypto_pcbc_encrypt(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, false); - while ((nbytes = walk.nbytes)) { + while (walk.nbytes) { if (walk.src.virt.addr == walk.dst.virt.addr) nbytes = crypto_pcbc_encrypt_inplace(req, &walk, cipher); @@ -138,7 +138,7 @@ static int crypto_pcbc_decrypt(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, false); - while ((nbytes = walk.nbytes)) { + while (walk.nbytes) { if (walk.src.virt.addr == walk.dst.virt.addr) nbytes = crypto_pcbc_decrypt_inplace(req, &walk, cipher); From f18483c987e16a96d9d04247da4050775d097132 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 18 Jan 2024 12:07:45 +0000 Subject: [PATCH 066/814] crypto: asymmetric_keys - remove redundant pointer secs The pointer secs is being assigned a value however secs is never read afterwards. The pointer secs is redundant and can be removed. Cleans up clang scan build warning: warning: Although the value stored to 'secs' is used in the enclosing expression, the value is never actually read from 'secs' [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Jarkko Sakkinen Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/verify_pefile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index f440767bd727..2863984b6700 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c @@ -28,7 +28,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen, const struct pe32plus_opt_hdr *pe64; const struct data_directory *ddir; const struct data_dirent *dde; - const struct section_header *secs, *sec; + const struct section_header *sec; size_t cursor, datalen = pelen; kenter(""); @@ -110,7 +110,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen, ctx->n_sections = pe->sections; if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec)) return -ELIBBAD; - ctx->secs = secs = pebuf + cursor; + ctx->secs = pebuf + cursor; return 0; } From f722002441a1395d3e073f9fb5b6f1ab33ca9d66 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:30 +0100 Subject: [PATCH 067/814] crypto: arm64/aes-ccm - Revert "Rewrite skcipher walker loop" This reverts commit 57ead1bf1c54, which updated the CCM code to only rely on walk.nbytes to check for failures returned from the skcipher walk API, mostly for the common good rather than to fix a particular problem in the code. This change introduces a problem of its own: the skcipher walk is started with the 'atomic' argument set to false, which means that the skcipher walk API is permitted to sleep. Subsequently, it invokes skcipher_walk_done() with preemption disabled on the final iteration of the loop. This appears to work by accident, but it is arguably a bad example, and providing a better example was the point of the original patch. Given that future changes to the CCM code will rely on the original behavior of entering the loop even for zero sized inputs, let's just revert this change entirely, and proceed from there. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-glue.c | 57 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index 25cd3808ecbe..c4f14415f5f0 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -161,39 +161,43 @@ static int ccm_encrypt(struct aead_request *req) memcpy(buf, req->iv, AES_BLOCK_SIZE); err = skcipher_walk_aead_encrypt(&walk, req, false); + if (unlikely(err)) + return err; kernel_neon_begin(); if (req->assoclen) ccm_calculate_auth_mac(req, mac); - while (walk.nbytes) { + do { u32 tail = walk.nbytes % AES_BLOCK_SIZE; - bool final = walk.nbytes == walk.total; - if (final) + if (walk.nbytes == walk.total) tail = 0; ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes - tail, ctx->key_enc, num_rounds(ctx), mac, walk.iv); - if (!final) - kernel_neon_end(); - err = skcipher_walk_done(&walk, tail); - if (!final) - kernel_neon_begin(); - } + if (walk.nbytes == walk.total) + ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); - ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); + kernel_neon_end(); - kernel_neon_end(); + if (walk.nbytes) { + err = skcipher_walk_done(&walk, tail); + if (unlikely(err)) + return err; + if (unlikely(walk.nbytes)) + kernel_neon_begin(); + } + } while (walk.nbytes); /* copy authtag to end of dst */ scatterwalk_map_and_copy(mac, req->dst, req->assoclen + req->cryptlen, crypto_aead_authsize(aead), 1); - return err; + return 0; } static int ccm_decrypt(struct aead_request *req) @@ -215,36 +219,37 @@ static int ccm_decrypt(struct aead_request *req) memcpy(buf, req->iv, AES_BLOCK_SIZE); err = skcipher_walk_aead_decrypt(&walk, req, false); + if (unlikely(err)) + return err; kernel_neon_begin(); if (req->assoclen) ccm_calculate_auth_mac(req, mac); - while (walk.nbytes) { + do { u32 tail = walk.nbytes % AES_BLOCK_SIZE; - bool final = walk.nbytes == walk.total; - if (final) + if (walk.nbytes == walk.total) tail = 0; ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes - tail, ctx->key_enc, num_rounds(ctx), mac, walk.iv); - if (!final) - kernel_neon_end(); - err = skcipher_walk_done(&walk, tail); - if (!final) - kernel_neon_begin(); - } + if (walk.nbytes == walk.total) + ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); - ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); + kernel_neon_end(); - kernel_neon_end(); - - if (unlikely(err)) - return err; + if (walk.nbytes) { + err = skcipher_walk_done(&walk, tail); + if (unlikely(err)) + return err; + if (unlikely(walk.nbytes)) + kernel_neon_begin(); + } + } while (walk.nbytes); /* compare calculated auth tag with the stored one */ scatterwalk_map_and_copy(buf, req->src, From 88c6d50f649b2805bbdfe0b616892f93db47e4fa Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:31 +0100 Subject: [PATCH 068/814] crypto: arm64/aes-ccm - Keep NEON enabled during skcipher walk Now that kernel mode NEON no longer disables preemption, we no longer have to take care to disable and re-enable use of the NEON when calling into the skcipher walk API. So just keep it enabled until done. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-glue.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index c4f14415f5f0..b177ebea7d09 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -182,17 +182,16 @@ static int ccm_encrypt(struct aead_request *req) if (walk.nbytes == walk.total) ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); - kernel_neon_end(); - if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); - if (unlikely(err)) - return err; - if (unlikely(walk.nbytes)) - kernel_neon_begin(); } } while (walk.nbytes); + kernel_neon_end(); + + if (unlikely(err)) + return err; + /* copy authtag to end of dst */ scatterwalk_map_and_copy(mac, req->dst, req->assoclen + req->cryptlen, crypto_aead_authsize(aead), 1); @@ -240,17 +239,16 @@ static int ccm_decrypt(struct aead_request *req) if (walk.nbytes == walk.total) ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); - kernel_neon_end(); - if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); - if (unlikely(err)) - return err; - if (unlikely(walk.nbytes)) - kernel_neon_begin(); } } while (walk.nbytes); + kernel_neon_end(); + + if (unlikely(err)) + return err; + /* compare calculated auth tag with the stored one */ scatterwalk_map_and_copy(buf, req->src, req->assoclen + req->cryptlen - authsize, From 97c4c10dafcd0d8c19bf01743df4b75dbdc484d7 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:32 +0100 Subject: [PATCH 069/814] crypto: arm64/aes-ccm - Pass short inputs via stack buffer In preparation for optimizing the CCM core asm code using permutation vectors and overlapping loads and stores, ensure that inputs shorter than the size of a AES block are passed via a buffer on the stack, in a way that positions the data at the end of a 16 byte buffer. This removes the need for the asm code to reason about a rare corner case where the tail of the data cannot be read/written using a single NEON load/store instruction. While at it, tweak the copyright header and authorship to bring it up to date. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-glue.c | 57 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index b177ebea7d09..4710e59075f5 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * aes-ccm-glue.c - AES-CCM transform for ARMv8 with Crypto Extensions + * aes-ce-ccm-glue.c - AES-CCM transform for ARMv8 with Crypto Extensions * - * Copyright (C) 2013 - 2017 Linaro Ltd + * Copyright (C) 2013 - 2017 Linaro Ltd. + * Copyright (C) 2024 Google LLC + * + * Author: Ard Biesheuvel */ #include @@ -149,7 +152,7 @@ static int ccm_encrypt(struct aead_request *req) struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead); struct skcipher_walk walk; u8 __aligned(8) mac[AES_BLOCK_SIZE]; - u8 buf[AES_BLOCK_SIZE]; + u8 orig_iv[AES_BLOCK_SIZE]; u32 len = req->cryptlen; int err; @@ -158,7 +161,7 @@ static int ccm_encrypt(struct aead_request *req) return err; /* preserve the original iv for the final round */ - memcpy(buf, req->iv, AES_BLOCK_SIZE); + memcpy(orig_iv, req->iv, AES_BLOCK_SIZE); err = skcipher_walk_aead_encrypt(&walk, req, false); if (unlikely(err)) @@ -171,16 +174,26 @@ static int ccm_encrypt(struct aead_request *req) do { u32 tail = walk.nbytes % AES_BLOCK_SIZE; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 buf[AES_BLOCK_SIZE]; if (walk.nbytes == walk.total) tail = 0; - ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - walk.nbytes - tail, ctx->key_enc, - num_rounds(ctx), mac, walk.iv); + if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) + src = dst = memcpy(&buf[sizeof(buf) - walk.nbytes], + src, walk.nbytes); + + ce_aes_ccm_encrypt(dst, src, walk.nbytes - tail, + ctx->key_enc, num_rounds(ctx), + mac, walk.iv); + + if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) + memcpy(walk.dst.virt.addr, dst, walk.nbytes); if (walk.nbytes == walk.total) - ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); + ce_aes_ccm_final(mac, orig_iv, ctx->key_enc, num_rounds(ctx)); if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); @@ -206,7 +219,7 @@ static int ccm_decrypt(struct aead_request *req) unsigned int authsize = crypto_aead_authsize(aead); struct skcipher_walk walk; u8 __aligned(8) mac[AES_BLOCK_SIZE]; - u8 buf[AES_BLOCK_SIZE]; + u8 orig_iv[AES_BLOCK_SIZE]; u32 len = req->cryptlen - authsize; int err; @@ -215,7 +228,7 @@ static int ccm_decrypt(struct aead_request *req) return err; /* preserve the original iv for the final round */ - memcpy(buf, req->iv, AES_BLOCK_SIZE); + memcpy(orig_iv, req->iv, AES_BLOCK_SIZE); err = skcipher_walk_aead_decrypt(&walk, req, false); if (unlikely(err)) @@ -228,16 +241,26 @@ static int ccm_decrypt(struct aead_request *req) do { u32 tail = walk.nbytes % AES_BLOCK_SIZE; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 buf[AES_BLOCK_SIZE]; if (walk.nbytes == walk.total) tail = 0; - ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - walk.nbytes - tail, ctx->key_enc, - num_rounds(ctx), mac, walk.iv); + if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) + src = dst = memcpy(&buf[sizeof(buf) - walk.nbytes], + src, walk.nbytes); + + ce_aes_ccm_decrypt(dst, src, walk.nbytes - tail, + ctx->key_enc, num_rounds(ctx), + mac, walk.iv); + + if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) + memcpy(walk.dst.virt.addr, dst, walk.nbytes); if (walk.nbytes == walk.total) - ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); + ce_aes_ccm_final(mac, orig_iv, ctx->key_enc, num_rounds(ctx)); if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); @@ -250,11 +273,11 @@ static int ccm_decrypt(struct aead_request *req) return err; /* compare calculated auth tag with the stored one */ - scatterwalk_map_and_copy(buf, req->src, + scatterwalk_map_and_copy(orig_iv, req->src, req->assoclen + req->cryptlen - authsize, authsize, 0); - if (crypto_memneq(mac, buf, authsize)) + if (crypto_memneq(mac, orig_iv, authsize)) return -EBADMSG; return 0; } @@ -293,6 +316,6 @@ module_init(aes_mod_init); module_exit(aes_mod_exit); MODULE_DESCRIPTION("Synchronous AES in CCM mode using ARMv8 Crypto Extensions"); -MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("ccm(aes)"); From c131098d6d9c5d0a580456f527dedefaf61acb7b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:33 +0100 Subject: [PATCH 070/814] crypto: arm64/aes-ccm - Replace bytewise tail handling with NEON permute Implement the CCM tail handling using a single sequence that uses permute vectors and overlapping loads and stores, rather than going over the tail byte by byte in a loop, and using scalar operations. This is more efficient, even though the measured speedup is only around 1-2% on the CPUs I have tried. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-core.S | 59 +++++++++++++++++++---------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-core.S b/arch/arm64/crypto/aes-ce-ccm-core.S index b03f7f71f893..b21a9b759ab2 100644 --- a/arch/arm64/crypto/aes-ce-ccm-core.S +++ b/arch/arm64/crypto/aes-ce-ccm-core.S @@ -1,8 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * aesce-ccm-core.S - AES-CCM transform for ARMv8 with Crypto Extensions + * aes-ce-ccm-core.S - AES-CCM transform for ARMv8 with Crypto Extensions * - * Copyright (C) 2013 - 2017 Linaro Ltd + * Copyright (C) 2013 - 2017 Linaro Ltd. + * Copyright (C) 2024 Google LLC + * + * Author: Ard Biesheuvel */ #include @@ -168,13 +171,13 @@ CPU_LE( rev x8, x8 ) /* keep swabbed ctr in reg */ ld1 {v2.16b}, [x1], #16 /* load next input block */ .if \enc == 1 eor v2.16b, v2.16b, v5.16b /* final round enc+mac */ - eor v1.16b, v1.16b, v2.16b /* xor with crypted ctr */ + eor v6.16b, v1.16b, v2.16b /* xor with crypted ctr */ .else eor v2.16b, v2.16b, v1.16b /* xor with crypted ctr */ - eor v1.16b, v2.16b, v5.16b /* final round enc */ + eor v6.16b, v2.16b, v5.16b /* final round enc */ .endif eor v0.16b, v0.16b, v2.16b /* xor mac with pt ^ rk[last] */ - st1 {v1.16b}, [x0], #16 /* write output block */ + st1 {v6.16b}, [x0], #16 /* write output block */ bne 0b CPU_LE( rev x8, x8 ) st1 {v0.16b}, [x5] /* store mac */ @@ -183,25 +186,31 @@ CPU_LE( rev x8, x8 ) 6: eor v0.16b, v0.16b, v5.16b /* final round mac */ eor v1.16b, v1.16b, v5.16b /* final round enc */ - st1 {v0.16b}, [x5] /* store mac */ - add w2, w2, #16 /* process partial tail block */ -7: ldrb w9, [x1], #1 /* get 1 byte of input */ - umov w6, v1.b[0] /* get top crypted ctr byte */ - umov w7, v0.b[0] /* get top mac byte */ + + add x1, x1, w2, sxtw /* rewind the input pointer (w2 < 0) */ + add x0, x0, w2, sxtw /* rewind the output pointer */ + + adr_l x8, .Lpermute /* load permute vectors */ + add x9, x8, w2, sxtw + sub x8, x8, w2, sxtw + ld1 {v7.16b-v8.16b}, [x9] + ld1 {v9.16b}, [x8] + + ld1 {v2.16b}, [x1] /* load a full block of input */ + tbl v1.16b, {v1.16b}, v7.16b /* move keystream to end of register */ .if \enc == 1 - eor w7, w7, w9 - eor w9, w9, w6 + tbl v7.16b, {v2.16b}, v9.16b /* copy plaintext to start of v7 */ + eor v2.16b, v2.16b, v1.16b /* encrypt partial input block */ .else - eor w9, w9, w6 - eor w7, w7, w9 + eor v2.16b, v2.16b, v1.16b /* decrypt partial input block */ + tbl v7.16b, {v2.16b}, v9.16b /* copy plaintext to start of v7 */ .endif - strb w9, [x0], #1 /* store out byte */ - strb w7, [x5], #1 /* store mac byte */ - subs w2, w2, #1 - beq 5b - ext v0.16b, v0.16b, v0.16b, #1 /* shift out mac byte */ - ext v1.16b, v1.16b, v1.16b, #1 /* shift out ctr byte */ - b 7b + eor v0.16b, v0.16b, v7.16b /* fold plaintext into mac */ + tbx v2.16b, {v6.16b}, v8.16b /* insert output from previous iteration */ + + st1 {v0.16b}, [x5] /* store mac */ + st1 {v2.16b}, [x0] /* store output block */ + ret .endm /* @@ -219,3 +228,11 @@ SYM_FUNC_END(ce_aes_ccm_encrypt) SYM_FUNC_START(ce_aes_ccm_decrypt) aes_ccm_do_crypt 0 SYM_FUNC_END(ce_aes_ccm_decrypt) + + .section ".rodata", "a" + .align 6 + .fill 15, 1, 0xff +.Lpermute: + .byte 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 + .byte 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf + .fill 15, 1, 0xff From 948ffc66e595e56c6ebf672db38d59c8a9efc108 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:34 +0100 Subject: [PATCH 071/814] crypto: arm64/aes-ccm - Reuse existing MAC update for AAD input CCM combines the counter (CTR) encryption mode with a MAC based on the same block cipher. This MAC construction is a bit clunky: it invokes the block cipher in a way that cannot be parallelized, resulting in poor CPU pipeline efficiency. The arm64 CCM code mitigates this by interleaving the encryption and MAC at the AES round level, resulting in a substantial speedup. But this approach does not apply to the additional authenticated data (AAD) which is not encrypted. This means the special asm routine dealing with the AAD is not any better than the MAC update routine used by the arm64 AES block encryption driver, so let's reuse that, and drop the special AES-CCM version. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/Kconfig | 1 + arch/arm64/crypto/aes-ce-ccm-core.S | 71 ----------------------------- arch/arm64/crypto/aes-ce-ccm-glue.c | 49 ++++++++++++++++---- arch/arm64/crypto/aes-glue.c | 1 + 4 files changed, 43 insertions(+), 79 deletions(-) diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index eb7b423ba463..e7d9bd8e4709 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -268,6 +268,7 @@ config CRYPTO_AES_ARM64_CE_CCM depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_ALGAPI select CRYPTO_AES_ARM64_CE + select CRYPTO_AES_ARM64_CE_BLK select CRYPTO_AEAD select CRYPTO_LIB_AES help diff --git a/arch/arm64/crypto/aes-ce-ccm-core.S b/arch/arm64/crypto/aes-ce-ccm-core.S index b21a9b759ab2..0132872bd780 100644 --- a/arch/arm64/crypto/aes-ce-ccm-core.S +++ b/arch/arm64/crypto/aes-ce-ccm-core.S @@ -14,77 +14,6 @@ .text .arch armv8-a+crypto - /* - * u32 ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes, - * u32 macp, u8 const rk[], u32 rounds); - */ -SYM_FUNC_START(ce_aes_ccm_auth_data) - ld1 {v0.16b}, [x0] /* load mac */ - cbz w3, 1f - sub w3, w3, #16 - eor v1.16b, v1.16b, v1.16b -0: ldrb w7, [x1], #1 /* get 1 byte of input */ - subs w2, w2, #1 - add w3, w3, #1 - ins v1.b[0], w7 - ext v1.16b, v1.16b, v1.16b, #1 /* rotate in the input bytes */ - beq 8f /* out of input? */ - cbnz w3, 0b - eor v0.16b, v0.16b, v1.16b -1: ld1 {v3.4s}, [x4] /* load first round key */ - prfm pldl1strm, [x1] - cmp w5, #12 /* which key size? */ - add x6, x4, #16 - sub w7, w5, #2 /* modified # of rounds */ - bmi 2f - bne 5f - mov v5.16b, v3.16b - b 4f -2: mov v4.16b, v3.16b - ld1 {v5.4s}, [x6], #16 /* load 2nd round key */ -3: aese v0.16b, v4.16b - aesmc v0.16b, v0.16b -4: ld1 {v3.4s}, [x6], #16 /* load next round key */ - aese v0.16b, v5.16b - aesmc v0.16b, v0.16b -5: ld1 {v4.4s}, [x6], #16 /* load next round key */ - subs w7, w7, #3 - aese v0.16b, v3.16b - aesmc v0.16b, v0.16b - ld1 {v5.4s}, [x6], #16 /* load next round key */ - bpl 3b - aese v0.16b, v4.16b - subs w2, w2, #16 /* last data? */ - eor v0.16b, v0.16b, v5.16b /* final round */ - bmi 6f - ld1 {v1.16b}, [x1], #16 /* load next input block */ - eor v0.16b, v0.16b, v1.16b /* xor with mac */ - bne 1b -6: st1 {v0.16b}, [x0] /* store mac */ - beq 10f - adds w2, w2, #16 - beq 10f - mov w3, w2 -7: ldrb w7, [x1], #1 - umov w6, v0.b[0] - eor w6, w6, w7 - strb w6, [x0], #1 - subs w2, w2, #1 - beq 10f - ext v0.16b, v0.16b, v0.16b, #1 /* rotate out the mac bytes */ - b 7b -8: cbz w3, 91f - mov w7, w3 - add w3, w3, #16 -9: ext v1.16b, v1.16b, v1.16b, #1 - adds w7, w7, #1 - bne 9b -91: eor v0.16b, v0.16b, v1.16b - st1 {v0.16b}, [x0] -10: mov w0, w3 - ret -SYM_FUNC_END(ce_aes_ccm_auth_data) - /* * void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u8 const rk[], * u32 rounds); diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index 4710e59075f5..ed3d79e05112 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -18,6 +18,8 @@ #include "aes-ce-setkey.h" +MODULE_IMPORT_NS(CRYPTO_INTERNAL); + static int num_rounds(struct crypto_aes_ctx *ctx) { /* @@ -30,8 +32,9 @@ static int num_rounds(struct crypto_aes_ctx *ctx) return 6 + ctx->key_length / 4; } -asmlinkage u32 ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes, - u32 macp, u32 const rk[], u32 rounds); +asmlinkage u32 ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds, + int blocks, u8 dg[], int enc_before, + int enc_after); asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, u32 const rk[], u32 rounds, u8 mac[], @@ -97,6 +100,41 @@ static int ccm_init_mac(struct aead_request *req, u8 maciv[], u32 msglen) return 0; } +static u32 ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes, + u32 macp, u32 const rk[], u32 rounds) +{ + int enc_after = (macp + abytes) % AES_BLOCK_SIZE; + + do { + u32 blocks = abytes / AES_BLOCK_SIZE; + + if (macp == AES_BLOCK_SIZE || (!macp && blocks > 0)) { + u32 rem = ce_aes_mac_update(in, rk, rounds, blocks, mac, + macp, enc_after); + u32 adv = (blocks - rem) * AES_BLOCK_SIZE; + + macp = enc_after ? 0 : AES_BLOCK_SIZE; + in += adv; + abytes -= adv; + + if (unlikely(rem)) { + kernel_neon_end(); + kernel_neon_begin(); + macp = 0; + } + } else { + u32 l = min(AES_BLOCK_SIZE - macp, abytes); + + crypto_xor(&mac[macp], in, l); + in += l; + macp += l; + abytes -= l; + } + } while (abytes > 0); + + return macp; +} + static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[]) { struct crypto_aead *aead = crypto_aead_reqtfm(req); @@ -104,7 +142,7 @@ static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[]) struct __packed { __be16 l; __be32 h; u16 len; } ltag; struct scatter_walk walk; u32 len = req->assoclen; - u32 macp = 0; + u32 macp = AES_BLOCK_SIZE; /* prepend the AAD with a length tag */ if (len < 0xff00) { @@ -128,16 +166,11 @@ static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[]) scatterwalk_start(&walk, sg_next(walk.sg)); n = scatterwalk_clamp(&walk, len); } - n = min_t(u32, n, SZ_4K); /* yield NEON at least every 4k */ p = scatterwalk_map(&walk); macp = ce_aes_ccm_auth_data(mac, p, n, macp, ctx->key_enc, num_rounds(ctx)); - if (len / SZ_4K > (len - n) / SZ_4K) { - kernel_neon_end(); - kernel_neon_begin(); - } len -= n; scatterwalk_unmap(p); diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 162787c7aa86..a147e847a5a1 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -1048,6 +1048,7 @@ unregister_ciphers: #ifdef USE_V8_CRYPTO_EXTENSIONS module_cpu_feature_match(AES, aes_init); +EXPORT_SYMBOL_NS(ce_aes_mac_update, CRYPTO_INTERNAL); #else module_init(aes_init); EXPORT_SYMBOL(neon_aes_ecb_encrypt); From 565def1542ab6cbf8a03acb07e612036aa5b5a6b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:35 +0100 Subject: [PATCH 072/814] crypto: arm64/aes-ccm - Cache round keys and unroll AES loops The CCM code as originally written attempted to use as few NEON registers as possible, to avoid having to eagerly preserve/restore the entire NEON register file at every call to kernel_neon_begin/end. At that time, this API took a number of NEON registers as a parameter, and only preserved that many registers. Today, the NEON register file is restored lazily, and the old API is long gone. This means we can use as many NEON registers as we can make meaningful use of, which means in the AES case that we can keep all round keys in registers rather than reloading each of them for each AES block processed. On Cortex-A53, this results in a speedup of more than 50%. (From 4 cycles per byte to 2.6 cycles per byte) Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-core.S | 95 ++++++++++++----------------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-core.S b/arch/arm64/crypto/aes-ce-ccm-core.S index 0132872bd780..0ec59fc4ef3e 100644 --- a/arch/arm64/crypto/aes-ce-ccm-core.S +++ b/arch/arm64/crypto/aes-ce-ccm-core.S @@ -14,40 +14,46 @@ .text .arch armv8-a+crypto + .macro load_round_keys, rk, nr, tmp + sub w\tmp, \nr, #10 + add \tmp, \rk, w\tmp, sxtw #4 + ld1 {v10.4s-v13.4s}, [\rk] + ld1 {v14.4s-v17.4s}, [\tmp], #64 + ld1 {v18.4s-v21.4s}, [\tmp], #64 + ld1 {v3.4s-v5.4s}, [\tmp] + .endm + + .macro dround, va, vb, vk + aese \va\().16b, \vk\().16b + aesmc \va\().16b, \va\().16b + aese \vb\().16b, \vk\().16b + aesmc \vb\().16b, \vb\().16b + .endm + + .macro aes_encrypt, va, vb, nr + tbz \nr, #2, .L\@ + dround \va, \vb, v10 + dround \va, \vb, v11 + tbz \nr, #1, .L\@ + dround \va, \vb, v12 + dround \va, \vb, v13 +.L\@: .irp v, v14, v15, v16, v17, v18, v19, v20, v21, v3 + dround \va, \vb, \v + .endr + aese \va\().16b, v4.16b + aese \vb\().16b, v4.16b + .endm + /* * void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u8 const rk[], * u32 rounds); */ SYM_FUNC_START(ce_aes_ccm_final) - ld1 {v3.4s}, [x2], #16 /* load first round key */ ld1 {v0.16b}, [x0] /* load mac */ - cmp w3, #12 /* which key size? */ - sub w3, w3, #2 /* modified # of rounds */ ld1 {v1.16b}, [x1] /* load 1st ctriv */ - bmi 0f - bne 3f - mov v5.16b, v3.16b - b 2f -0: mov v4.16b, v3.16b -1: ld1 {v5.4s}, [x2], #16 /* load next round key */ - aese v0.16b, v4.16b - aesmc v0.16b, v0.16b - aese v1.16b, v4.16b - aesmc v1.16b, v1.16b -2: ld1 {v3.4s}, [x2], #16 /* load next round key */ - aese v0.16b, v5.16b - aesmc v0.16b, v0.16b - aese v1.16b, v5.16b - aesmc v1.16b, v1.16b -3: ld1 {v4.4s}, [x2], #16 /* load next round key */ - subs w3, w3, #3 - aese v0.16b, v3.16b - aesmc v0.16b, v0.16b - aese v1.16b, v3.16b - aesmc v1.16b, v1.16b - bpl 1b - aese v0.16b, v4.16b - aese v1.16b, v4.16b + + aes_encrypt v0, v1, w3 + /* final round key cancels out */ eor v0.16b, v0.16b, v1.16b /* en-/decrypt the mac */ st1 {v0.16b}, [x0] /* store result */ @@ -55,6 +61,8 @@ SYM_FUNC_START(ce_aes_ccm_final) SYM_FUNC_END(ce_aes_ccm_final) .macro aes_ccm_do_crypt,enc + load_round_keys x3, w4, x10 + cbz x2, 5f ldr x8, [x6, #8] /* load lower ctr */ ld1 {v0.16b}, [x5] /* load mac */ @@ -64,37 +72,10 @@ CPU_LE( rev x8, x8 ) /* keep swabbed ctr in reg */ prfm pldl1strm, [x1] add x8, x8, #1 rev x9, x8 - cmp w4, #12 /* which key size? */ - sub w7, w4, #2 /* get modified # of rounds */ ins v1.d[1], x9 /* no carry in lower ctr */ - ld1 {v3.4s}, [x3] /* load first round key */ - add x10, x3, #16 - bmi 1f - bne 4f - mov v5.16b, v3.16b - b 3f -1: mov v4.16b, v3.16b - ld1 {v5.4s}, [x10], #16 /* load 2nd round key */ -2: /* inner loop: 3 rounds, 2x interleaved */ - aese v0.16b, v4.16b - aesmc v0.16b, v0.16b - aese v1.16b, v4.16b - aesmc v1.16b, v1.16b -3: ld1 {v3.4s}, [x10], #16 /* load next round key */ - aese v0.16b, v5.16b - aesmc v0.16b, v0.16b - aese v1.16b, v5.16b - aesmc v1.16b, v1.16b -4: ld1 {v4.4s}, [x10], #16 /* load next round key */ - subs w7, w7, #3 - aese v0.16b, v3.16b - aesmc v0.16b, v0.16b - aese v1.16b, v3.16b - aesmc v1.16b, v1.16b - ld1 {v5.4s}, [x10], #16 /* load next round key */ - bpl 2b - aese v0.16b, v4.16b - aese v1.16b, v4.16b + + aes_encrypt v0, v1, w4 + subs w2, w2, #16 bmi 6f /* partial block? */ ld1 {v2.16b}, [x1], #16 /* load next input block */ From 715052884929cc29e2d09dbf1d530c6ada306ce8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:36 +0100 Subject: [PATCH 073/814] crypto: arm64/aes-ccm - Merge encrypt and decrypt tail handling The encryption and decryption code paths are mostly identical, except for a small difference where the plaintext input into the MAC is taken from either the input or the output block. We can factor this in quite easily using a vector bit select, and a few additional XORs, without the need for branches. This way, we can use the same tail handling logic on the encrypt and decrypt code paths, allowing further consolidation of the asm helpers in a subsequent patch. (In the main loop, adding just a handful of ALU instructions results in a noticeable performance hit [around 5% on Apple M2], so those routines are kept separate) Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-core.S | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-core.S b/arch/arm64/crypto/aes-ce-ccm-core.S index 0ec59fc4ef3e..bf3a888a5615 100644 --- a/arch/arm64/crypto/aes-ce-ccm-core.S +++ b/arch/arm64/crypto/aes-ce-ccm-core.S @@ -77,7 +77,7 @@ CPU_LE( rev x8, x8 ) /* keep swabbed ctr in reg */ aes_encrypt v0, v1, w4 subs w2, w2, #16 - bmi 6f /* partial block? */ + bmi ce_aes_ccm_crypt_tail ld1 {v2.16b}, [x1], #16 /* load next input block */ .if \enc == 1 eor v2.16b, v2.16b, v5.16b /* final round enc+mac */ @@ -93,8 +93,10 @@ CPU_LE( rev x8, x8 ) st1 {v0.16b}, [x5] /* store mac */ str x8, [x6, #8] /* store lsb end of ctr (BE) */ 5: ret + .endm -6: eor v0.16b, v0.16b, v5.16b /* final round mac */ +SYM_FUNC_START_LOCAL(ce_aes_ccm_crypt_tail) + eor v0.16b, v0.16b, v5.16b /* final round mac */ eor v1.16b, v1.16b, v5.16b /* final round enc */ add x1, x1, w2, sxtw /* rewind the input pointer (w2 < 0) */ @@ -108,20 +110,16 @@ CPU_LE( rev x8, x8 ) ld1 {v2.16b}, [x1] /* load a full block of input */ tbl v1.16b, {v1.16b}, v7.16b /* move keystream to end of register */ - .if \enc == 1 - tbl v7.16b, {v2.16b}, v9.16b /* copy plaintext to start of v7 */ - eor v2.16b, v2.16b, v1.16b /* encrypt partial input block */ - .else - eor v2.16b, v2.16b, v1.16b /* decrypt partial input block */ - tbl v7.16b, {v2.16b}, v9.16b /* copy plaintext to start of v7 */ - .endif - eor v0.16b, v0.16b, v7.16b /* fold plaintext into mac */ - tbx v2.16b, {v6.16b}, v8.16b /* insert output from previous iteration */ + eor v7.16b, v2.16b, v1.16b /* encrypt partial input block */ + bif v2.16b, v7.16b, v22.16b /* select plaintext */ + tbx v7.16b, {v6.16b}, v8.16b /* insert output from previous iteration */ + tbl v2.16b, {v2.16b}, v9.16b /* copy plaintext to start of v2 */ + eor v0.16b, v0.16b, v2.16b /* fold plaintext into mac */ st1 {v0.16b}, [x5] /* store mac */ - st1 {v2.16b}, [x0] /* store output block */ + st1 {v7.16b}, [x0] /* store output block */ ret - .endm +SYM_FUNC_END(ce_aes_ccm_crypt_tail) /* * void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, @@ -132,10 +130,12 @@ CPU_LE( rev x8, x8 ) * u8 ctr[]); */ SYM_FUNC_START(ce_aes_ccm_encrypt) + movi v22.16b, #255 aes_ccm_do_crypt 1 SYM_FUNC_END(ce_aes_ccm_encrypt) SYM_FUNC_START(ce_aes_ccm_decrypt) + movi v22.16b, #0 aes_ccm_do_crypt 0 SYM_FUNC_END(ce_aes_ccm_decrypt) From f691d444f9a9094a5a89bb618495f2bfa9309f32 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 18 Jan 2024 18:06:37 +0100 Subject: [PATCH 074/814] crypto: arm64/aes-ccm - Merge finalization into en/decrypt asm helpers The C glue code already infers whether or not the current iteration is the final one, by comparing walk.nbytes with walk.total. This means we can easily inform the asm helpers of this as well, by conditionally passing a pointer to the original IV, which is used in the finalization of the MAC. This removes the need for a separate call into the asm code to perform the finalization. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce-ccm-core.S | 40 ++++++++++++----------------- arch/arm64/crypto/aes-ce-ccm-glue.c | 27 +++++++++---------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/arch/arm64/crypto/aes-ce-ccm-core.S b/arch/arm64/crypto/aes-ce-ccm-core.S index bf3a888a5615..f2624238fd95 100644 --- a/arch/arm64/crypto/aes-ce-ccm-core.S +++ b/arch/arm64/crypto/aes-ce-ccm-core.S @@ -44,28 +44,12 @@ aese \vb\().16b, v4.16b .endm - /* - * void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u8 const rk[], - * u32 rounds); - */ -SYM_FUNC_START(ce_aes_ccm_final) - ld1 {v0.16b}, [x0] /* load mac */ - ld1 {v1.16b}, [x1] /* load 1st ctriv */ - - aes_encrypt v0, v1, w3 - - /* final round key cancels out */ - eor v0.16b, v0.16b, v1.16b /* en-/decrypt the mac */ - st1 {v0.16b}, [x0] /* store result */ - ret -SYM_FUNC_END(ce_aes_ccm_final) - .macro aes_ccm_do_crypt,enc load_round_keys x3, w4, x10 - cbz x2, 5f - ldr x8, [x6, #8] /* load lower ctr */ ld1 {v0.16b}, [x5] /* load mac */ + cbz x2, ce_aes_ccm_final + ldr x8, [x6, #8] /* load lower ctr */ CPU_LE( rev x8, x8 ) /* keep swabbed ctr in reg */ 0: /* outer loop */ ld1 {v1.8b}, [x6] /* load upper ctr */ @@ -90,9 +74,10 @@ CPU_LE( rev x8, x8 ) /* keep swabbed ctr in reg */ st1 {v6.16b}, [x0], #16 /* write output block */ bne 0b CPU_LE( rev x8, x8 ) - st1 {v0.16b}, [x5] /* store mac */ str x8, [x6, #8] /* store lsb end of ctr (BE) */ -5: ret + cbnz x7, ce_aes_ccm_final + st1 {v0.16b}, [x5] /* store mac */ + ret .endm SYM_FUNC_START_LOCAL(ce_aes_ccm_crypt_tail) @@ -116,18 +101,27 @@ SYM_FUNC_START_LOCAL(ce_aes_ccm_crypt_tail) tbl v2.16b, {v2.16b}, v9.16b /* copy plaintext to start of v2 */ eor v0.16b, v0.16b, v2.16b /* fold plaintext into mac */ - st1 {v0.16b}, [x5] /* store mac */ st1 {v7.16b}, [x0] /* store output block */ + cbz x7, 0f + +SYM_INNER_LABEL(ce_aes_ccm_final, SYM_L_LOCAL) + ld1 {v1.16b}, [x7] /* load 1st ctriv */ + + aes_encrypt v0, v1, w4 + + /* final round key cancels out */ + eor v0.16b, v0.16b, v1.16b /* en-/decrypt the mac */ +0: st1 {v0.16b}, [x5] /* store result */ ret SYM_FUNC_END(ce_aes_ccm_crypt_tail) /* * void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, * u8 const rk[], u32 rounds, u8 mac[], - * u8 ctr[]); + * u8 ctr[], u8 const final_iv[]); * void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes, * u8 const rk[], u32 rounds, u8 mac[], - * u8 ctr[]); + * u8 ctr[], u8 const final_iv[]); */ SYM_FUNC_START(ce_aes_ccm_encrypt) movi v22.16b, #255 diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index ed3d79e05112..ce9b28e3c7d6 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -38,14 +38,11 @@ asmlinkage u32 ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds, asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, u32 const rk[], u32 rounds, u8 mac[], - u8 ctr[]); + u8 ctr[], u8 const final_iv[]); asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes, u32 const rk[], u32 rounds, u8 mac[], - u8 ctr[]); - -asmlinkage void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u32 const rk[], - u32 rounds); + u8 ctr[], u8 const final_iv[]); static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key, unsigned int key_len) @@ -210,9 +207,12 @@ static int ccm_encrypt(struct aead_request *req) const u8 *src = walk.src.virt.addr; u8 *dst = walk.dst.virt.addr; u8 buf[AES_BLOCK_SIZE]; + u8 *final_iv = NULL; - if (walk.nbytes == walk.total) + if (walk.nbytes == walk.total) { tail = 0; + final_iv = orig_iv; + } if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) src = dst = memcpy(&buf[sizeof(buf) - walk.nbytes], @@ -220,14 +220,11 @@ static int ccm_encrypt(struct aead_request *req) ce_aes_ccm_encrypt(dst, src, walk.nbytes - tail, ctx->key_enc, num_rounds(ctx), - mac, walk.iv); + mac, walk.iv, final_iv); if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) memcpy(walk.dst.virt.addr, dst, walk.nbytes); - if (walk.nbytes == walk.total) - ce_aes_ccm_final(mac, orig_iv, ctx->key_enc, num_rounds(ctx)); - if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); } @@ -277,9 +274,12 @@ static int ccm_decrypt(struct aead_request *req) const u8 *src = walk.src.virt.addr; u8 *dst = walk.dst.virt.addr; u8 buf[AES_BLOCK_SIZE]; + u8 *final_iv = NULL; - if (walk.nbytes == walk.total) + if (walk.nbytes == walk.total) { tail = 0; + final_iv = orig_iv; + } if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) src = dst = memcpy(&buf[sizeof(buf) - walk.nbytes], @@ -287,14 +287,11 @@ static int ccm_decrypt(struct aead_request *req) ce_aes_ccm_decrypt(dst, src, walk.nbytes - tail, ctx->key_enc, num_rounds(ctx), - mac, walk.iv); + mac, walk.iv, final_iv); if (unlikely(walk.nbytes < AES_BLOCK_SIZE)) memcpy(walk.dst.virt.addr, dst, walk.nbytes); - if (walk.nbytes == walk.total) - ce_aes_ccm_final(mac, orig_iv, ctx->key_enc, num_rounds(ctx)); - if (walk.nbytes) { err = skcipher_walk_done(&walk, tail); } From 61909cc831750a81c5063ad4bee2ef29f039c987 Mon Sep 17 00:00:00 2001 From: Wenkai Lin Date: Fri, 19 Jan 2024 16:11:07 +0800 Subject: [PATCH 075/814] crypto: hisilicon - Fix smp_processor_id() warnings Switch to raw_smp_processor_id() to prevent a number of warnings from kernel debugging. We do not care about preemption here, as the CPU number is only used as a poor mans load balancing or device selection. If preemption happens during an encrypt/decrypt operation a small performance hit will occur but everything will continue to work, so just ignore it. This commit is similar to e7a9b05ca4 ("crypto: cavium - Fix smp_processor_id() warnings"). [ 7538.874350] BUG: using smp_processor_id() in preemptible [00000000] code: af_alg06/8438 [ 7538.874368] caller is debug_smp_processor_id+0x1c/0x28 [ 7538.874373] CPU: 50 PID: 8438 Comm: af_alg06 Kdump: loaded Not tainted 5.10.0.pc+ #18 [ 7538.874377] Call trace: [ 7538.874387] dump_backtrace+0x0/0x210 [ 7538.874389] show_stack+0x2c/0x38 [ 7538.874392] dump_stack+0x110/0x164 [ 7538.874394] check_preemption_disabled+0xf4/0x108 [ 7538.874396] debug_smp_processor_id+0x1c/0x28 [ 7538.874406] sec_create_qps+0x24/0xe8 [hisi_sec2] [ 7538.874408] sec_ctx_base_init+0x20/0x4d8 [hisi_sec2] [ 7538.874411] sec_aead_ctx_init+0x68/0x180 [hisi_sec2] [ 7538.874413] sec_aead_sha256_ctx_init+0x28/0x38 [hisi_sec2] [ 7538.874421] crypto_aead_init_tfm+0x54/0x68 [ 7538.874423] crypto_create_tfm_node+0x6c/0x110 [ 7538.874424] crypto_alloc_tfm_node+0x74/0x288 [ 7538.874426] crypto_alloc_aead+0x40/0x50 [ 7538.874431] aead_bind+0x50/0xd0 [ 7538.874433] alg_bind+0x94/0x148 [ 7538.874439] __sys_bind+0x98/0x118 [ 7538.874441] __arm64_sys_bind+0x28/0x38 [ 7538.874445] do_el0_svc+0x88/0x258 [ 7538.874447] el0_svc+0x1c/0x28 [ 7538.874449] el0_sync_handler+0x8c/0xb8 [ 7538.874452] el0_sync+0x148/0x180 Signed-off-by: Wenkai Lin Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 2 +- drivers/crypto/hisilicon/sec2/sec_main.c | 2 +- drivers/crypto/hisilicon/zip/zip_main.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 3255b2a070c7..d93aa6630a57 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -440,7 +440,7 @@ MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)"); struct hisi_qp *hpre_create_qp(u8 type) { - int node = cpu_to_node(smp_processor_id()); + int node = cpu_to_node(raw_smp_processor_id()); struct hisi_qp *qp = NULL; int ret; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 7bb99381bbdf..efa957ece23d 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -374,7 +374,7 @@ void sec_destroy_qps(struct hisi_qp **qps, int qp_num) struct hisi_qp **sec_create_qps(void) { - int node = cpu_to_node(smp_processor_id()); + int node = cpu_to_node(raw_smp_processor_id()); u32 ctx_num = ctx_q_num; struct hisi_qp **qps; int ret; diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 479ba8a1d6b5..c065fd867161 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -454,7 +454,7 @@ MODULE_DEVICE_TABLE(pci, hisi_zip_dev_ids); int zip_create_qps(struct hisi_qp **qps, int qp_num, int node) { if (node == NUMA_NO_NODE) - node = cpu_to_node(smp_processor_id()); + node = cpu_to_node(raw_smp_processor_id()); return hisi_qm_alloc_qps_node(&zip_devices, qp_num, 0, node, qps); } From 1dc0c1389d6afe4ef3e1d4054fb837b023ebf472 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sun, 21 Jan 2024 16:34:07 +0100 Subject: [PATCH 076/814] crypto: sun8i-ce - Use kcalloc() instead of kzalloc() As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the purpose specific kcalloc() function instead of the argument size * count in the kzalloc() function. Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/162 Signed-off-by: Erick Archer Reviewed-by: Gustavo A. R. Silva Acked-by: Jernej Skrabec Signed-off-by: Herbert Xu --- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index d358334e5981..ee2a28c906ed 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -362,7 +362,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) digestsize = SHA512_DIGEST_SIZE; /* the padding could be up to two block. */ - buf = kzalloc(bs * 2, GFP_KERNEL | GFP_DMA); + buf = kcalloc(2, bs, GFP_KERNEL | GFP_DMA); if (!buf) { err = -ENOMEM; goto theend; From 4da3bc65d218605557696109e42cfeee666d601f Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sun, 21 Jan 2024 17:40:43 +0100 Subject: [PATCH 077/814] crypto: qat - use kcalloc_node() instead of kzalloc_node() As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the purpose specific kcalloc_node() function instead of the argument count * size in the kzalloc_node() function. Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/162 Signed-off-by: Erick Archer Reviewed-by: Gustavo A. R. Silva Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_isr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c index 3557a0d6dea2..a13d9885d60f 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c @@ -272,7 +272,7 @@ static int adf_isr_alloc_msix_vectors_data(struct adf_accel_dev *accel_dev) if (!accel_dev->pf.vf_info) msix_num_entries += hw_data->num_banks; - irqs = kzalloc_node(msix_num_entries * sizeof(*irqs), + irqs = kcalloc_node(msix_num_entries, sizeof(*irqs), GFP_KERNEL, dev_to_node(&GET_DEV(accel_dev))); if (!irqs) return -ENOMEM; From 8203695ca50b421fe2650d2e9506533b59e13d4c Mon Sep 17 00:00:00 2001 From: Joachim Vandersmissen Date: Sun, 21 Jan 2024 13:45:26 -0600 Subject: [PATCH 078/814] crypto: testmgr - remove unused xts4096 and xts512 algorithms from testmgr.c Commit a93492cae30a ("crypto: ccree - remove data unit size support") removed support for the xts512 and xts4096 algorithms, but left them defined in testmgr.c. This patch removes those definitions. Signed-off-by: Joachim Vandersmissen Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/testmgr.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index c26aeda85787..3dddd288ca02 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -5720,14 +5720,6 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { #endif - .alg = "xts4096(paes)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "xts512(paes)", - .test = alg_test_null, - .fips_allowed = 1, - }, { .alg = "xxhash64", .test = alg_test_hash, .fips_allowed = 1, From 4d314d27130b674a3687135fe94f44a40f107f76 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Sun, 21 Jan 2024 17:57:41 +0100 Subject: [PATCH 079/814] dt-bindings: crypto: ice: Document SC7180 inline crypto engine Document the compatible used for the inline crypto engine found on SC7180. Acked-by: Rob Herring Signed-off-by: David Wronek Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index 09e43157cc71..e91bc7dc6ad3 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -14,6 +14,7 @@ properties: items: - enum: - qcom,sa8775p-inline-crypto-engine + - qcom,sc7180-inline-crypto-engine - qcom,sm8450-inline-crypto-engine - qcom,sm8550-inline-crypto-engine - qcom,sm8650-inline-crypto-engine From d489ec95658392a000dd26fba511eec1900245b0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:42:39 -0800 Subject: [PATCH 080/814] KVM: Harden against unpaired kvm_mmu_notifier_invalidate_range_end() calls When handling the end of an mmu_notifier invalidation, WARN if mn_active_invalidate_count is already 0 do not decrement it further, i.e. avoid causing mn_active_invalidate_count to underflow/wrap. In the worst case scenario, effectively corrupting mn_active_invalidate_count could cause kvm_swap_active_memslots() to hang indefinitely. end() calls are *supposed* to be paired with start(), i.e. underflow can only happen if there is a bug elsewhere in the kernel, but due to lack of lockdep assertions in the mmu_notifier helpers, it's all too easy for a bug to go unnoticed for some time, e.g. see the recently introduced PAGEMAP_SCAN ioctl(). Ideally, mmu_notifiers would incorporate lockdep assertions, but users of mmu_notifiers aren't required to hold any one specific lock, i.e. adding the necessary annotations to make lockdep aware of all locks that are mutally exclusive with mm_take_all_locks() isn't trivial. Link: https://lore.kernel.org/all/000000000000f6d051060c6785bc@google.com Link: https://lore.kernel.org/r/20240110004239.491290-1-seanjc@google.com Signed-off-by: Sean Christopherson --- virt/kvm/kvm_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 10bfc88a69f7..8f03b56dafbd 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -890,7 +890,9 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, /* Pairs with the increment in range_start(). */ spin_lock(&kvm->mn_invalidate_lock); - wake = (--kvm->mn_active_invalidate_count == 0); + if (!WARN_ON_ONCE(!kvm->mn_active_invalidate_count)) + --kvm->mn_active_invalidate_count; + wake = !kvm->mn_active_invalidate_count; spin_unlock(&kvm->mn_invalidate_lock); /* From 955997e880175b00161efb83b1b282849ff412d3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 30 Oct 2023 16:17:28 +0200 Subject: [PATCH 081/814] KVM: x86: Use mutex guards to eliminate __kvm_x86_vendor_init() Use the recently introduced guard(mutex) infrastructure acquire and automatically release vendor_module_lock when the guard goes out of scope. Drop the inner __kvm_x86_vendor_init(), its sole purpose was to simplify releasing vendor_module_lock in error paths. No functional change intended. Signed-off-by: Nikolay Borisov Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20231030141728.1406118-1-nik.borisov@suse.com [sean: rewrite changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 363b1c080205..709844fcd521 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9632,11 +9632,13 @@ static void kvm_x86_check_cpu_compat(void *ret) *(int *)ret = kvm_x86_check_processor_compatibility(); } -static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) +int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) { u64 host_pat; int r, cpu; + guard(mutex)(&vendor_module_lock); + if (kvm_x86_ops.hardware_enable) { pr_err("already loaded vendor module '%s'\n", kvm_x86_ops.name); return -EEXIST; @@ -9766,17 +9768,6 @@ out_free_x86_emulator_cache: kmem_cache_destroy(x86_emulator_cache); return r; } - -int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) -{ - int r; - - mutex_lock(&vendor_module_lock); - r = __kvm_x86_vendor_init(ops); - mutex_unlock(&vendor_module_lock); - - return r; -} EXPORT_SYMBOL_GPL(kvm_x86_vendor_init); void kvm_x86_vendor_exit(void) From a977c8158a42146dcb0f25c5ce8e1122d781b845 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Jan 2024 13:17:22 +0000 Subject: [PATCH 082/814] scsi: 3w-9xxx: Remove snprintf() from sysfs call-backs and replace with sysfs_emit() Since snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion. In the case of sysfs call-backs, new wrappers exist that do just that. Link: https://lwn.net/Articles/69419/ Link: https://github.com/KSPP/linux/issues/105 Cc: Adam Radford Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20240111131732.1815560-2-lee@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-9xxx.c | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index f925f8664c2c..6fb61c88ea11 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -161,28 +161,28 @@ static ssize_t twa_show_stats(struct device *dev, ssize_t len; spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Current pending commands: %4d\n" - "Max pending commands: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->pending_request_count, - tw_dev->max_pending_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); + len = sysfs_emit(buf, "3w-9xxx Driver version: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Current pending commands: %4d\n" + "Max pending commands: %4d\n" + "Last sgl length: %4d\n" + "Max sgl length: %4d\n" + "Last sector count: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "AEN's: %4d\n", + TW_DRIVER_VERSION, + tw_dev->posted_request_count, + tw_dev->max_posted_request_count, + tw_dev->pending_request_count, + tw_dev->max_pending_request_count, + tw_dev->sgl_entries, + tw_dev->max_sgl_entries, + tw_dev->sector_count, + tw_dev->max_sector_count, + tw_dev->num_resets, + tw_dev->aen_count); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); return len; } /* End twa_show_stats() */ From 7eaa48e9e497ecdddfbcd9323520908d6239a498 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Jan 2024 13:17:23 +0000 Subject: [PATCH 083/814] scsi: 3w-sas: Remove snprintf() from sysfs call-backs and replace with sysfs_emit() Since snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion. In the case of sysfs call-backs, new wrappers exist that do just that. Link: https://lwn.net/Articles/69419/ Link: https://github.com/KSPP/linux/issues/105 Cc: Adam Radford Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20240111131732.1815560-3-lee@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-sas.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 9bdb75dfdcd7..caa6713a62a4 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -166,24 +166,24 @@ static ssize_t twl_show_stats(struct device *dev, ssize_t len; spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); + len = sysfs_emit(buf, "3w-sas Driver version: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Last sgl length: %4d\n" + "Max sgl length: %4d\n" + "Last sector count: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "AEN's: %4d\n", + TW_DRIVER_VERSION, + tw_dev->posted_request_count, + tw_dev->max_posted_request_count, + tw_dev->sgl_entries, + tw_dev->max_sgl_entries, + tw_dev->sector_count, + tw_dev->max_sector_count, + tw_dev->num_resets, + tw_dev->aen_count); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); return len; } /* End twl_show_stats() */ From 30cc6aa09eeea5a8ab66d4471f6bdb47dbfa14f9 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Jan 2024 13:17:24 +0000 Subject: [PATCH 084/814] scsi: 3w-xxxx: Remove snprintf() from sysfs call-backs and replace with sysfs_emit() Since snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion. In the case of sysfs call-backs, new wrappers exist that do just that. Link: https://lwn.net/Articles/69419/ Link: https://github.com/KSPP/linux/issues/105 Cc: Adam Radford Cc: Joel Jacobson Cc: de Melo Cc: Andre Hedrick Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20240111131732.1815560-4-lee@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-xxxx.c | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index f39c9ec2e781..2c0fb6da0e60 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -496,28 +496,28 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr, ssize_t len; spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Current pending commands: %4d\n" - "Max pending commands: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->pending_request_count, - tw_dev->max_pending_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); + len = sysfs_emit(buf, "3w-xxxx Driver version: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Current pending commands: %4d\n" + "Max pending commands: %4d\n" + "Last sgl length: %4d\n" + "Max sgl length: %4d\n" + "Last sector count: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "AEN's: %4d\n", + TW_DRIVER_VERSION, + tw_dev->posted_request_count, + tw_dev->max_posted_request_count, + tw_dev->pending_request_count, + tw_dev->max_pending_request_count, + tw_dev->sgl_entries, + tw_dev->max_sgl_entries, + tw_dev->sector_count, + tw_dev->max_sector_count, + tw_dev->num_resets, + tw_dev->aen_count); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); return len; } /* End tw_show_stats() */ From f615c74de38300f2918033b5c44ac829d1fb7794 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Jan 2024 13:17:25 +0000 Subject: [PATCH 085/814] scsi: 53c700: Remove snprintf() from sysfs call-backs and replace with sysfs_emit() Since snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion. In the case of sysfs call-backs, new wrappers exist that do just that. [mkp: removed unrelated whitespace cleanups] Link: https://lwn.net/Articles/69419/ Link: https://github.com/KSPP/linux/issues/105 Cc: Richard Hirst Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20240111131732.1815560-5-lee@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/53c700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 857be0f3ae5b..85439e976143 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -2071,7 +2071,7 @@ NCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char { struct scsi_device *SDp = to_scsi_device(dev); - return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp)); + return sysfs_emit(buf, "%d\n", NCR_700_get_depth(SDp)); } static struct device_attribute NCR_700_active_tags_attr = { From bc978cc18d46dd54160f6c29aaf9475772686dfc Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Jan 2024 13:17:26 +0000 Subject: [PATCH 086/814] scsi: aacraid: aachba: Replace snprintf() with the safer scnprintf() variant There is a general misunderstanding amongst engineers that {v}snprintf() returns the length of the data *actually* encoded into the destination array. However, as per the C99 standard {v}snprintf() really returns the length of the data that *would have been* written if there were enough space for it. This misunderstanding has led to buffer-overruns in the past. It's generally considered safer to use the {v}scnprintf() variants in their place (or even sprintf() in simple cases). So let's do that. Link: https://lwn.net/Articles/69419/ Link: https://github.com/KSPP/linux/issues/105 Cc: Adaptec OEM Raid Solutions Cc: PMC-Sierra, Inc Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20240111131732.1815560-6-lee@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aachba.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 70e1cac1975e..b22857c6f3f4 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1099,7 +1099,7 @@ static void get_container_serial_callback(void *context, struct fib * fibptr) sp[0] = INQD_PDT_DA; sp[1] = scsicmd->cmnd[2]; sp[2] = 0; - sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", + sp[3] = scnprintf(sp+4, sizeof(sp)-4, "%08X", le32_to_cpu(get_serial_reply->uid)); scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp)); @@ -1169,8 +1169,8 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid) /* * This breaks array migration. */ - return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X", - le32_to_cpu(dev->adapter_info.serial[0]), cid); + return scnprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X", + le32_to_cpu(dev->adapter_info.serial[0]), cid); } static inline void set_sense(struct sense_data *sense_data, u8 sense_key, From 1ad717c92925e0d4d794ea04f45a4ba121d2da69 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 16 Jan 2024 12:51:31 +0800 Subject: [PATCH 087/814] scsi: fnic: Convert snprintf() to sysfs_emit() Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/scsi/fnic/fnic_attrs.c:17:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/fnic/fnic_attrs.c:23:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/fnic/fnic_attrs.c:31:8-16: WARNING: please use sysfs_emit No functional change intended CC: Satish Kharat CC: Sesidhar Baddela CC: Karan Tilak Kumar CC: James E.J. Bottomley CC: Martin K. Petersen CC: linux-scsi@vger.kernel.org Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240116045151.3940401-20-lizhijian@fujitsu.com Reviewed-by: Karan Tilak Kumar Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_attrs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/fnic/fnic_attrs.c b/drivers/scsi/fnic/fnic_attrs.c index a61e0c5e6506..0c5e57c7e322 100644 --- a/drivers/scsi/fnic/fnic_attrs.c +++ b/drivers/scsi/fnic/fnic_attrs.c @@ -14,13 +14,13 @@ static ssize_t fnic_show_state(struct device *dev, struct fc_lport *lp = shost_priv(class_to_shost(dev)); struct fnic *fnic = lport_priv(lp); - return snprintf(buf, PAGE_SIZE, "%s\n", fnic_state_str[fnic->state]); + return sysfs_emit(buf, "%s\n", fnic_state_str[fnic->state]); } static ssize_t fnic_show_drv_version(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION); + return sysfs_emit(buf, "%s\n", DRV_VERSION); } static ssize_t fnic_show_link_state(struct device *dev, @@ -28,8 +28,7 @@ static ssize_t fnic_show_link_state(struct device *dev, { struct fc_lport *lp = shost_priv(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%s\n", (lp->link_up) - ? "Link Up" : "Link Down"); + return sysfs_emit(buf, "%s\n", (lp->link_up) ? "Link Up" : "Link Down"); } static DEVICE_ATTR(fnic_state, S_IRUGO, fnic_show_state, NULL); From 29ff822f466e3dad904b14fb978576ff4c39102b Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 16 Jan 2024 12:51:34 +0800 Subject: [PATCH 088/814] scsi: ibmvscsi: Convert snprintf() to sysfs_emit() Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/scsi/ibmvscsi/ibmvfc.c:3483:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi/ibmvfc.c:3493:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi/ibmvfc.c:3503:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi/ibmvfc.c:3513:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi/ibmvfc.c:3522:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi/ibmvfc.c:3530:8-16: WARNING: please use sysfs_emit No functional change intended CC: Tyrel Datwyler CC: Michael Ellerman CC: Nicholas Piggin CC: Christophe Leroy CC: Aneesh Kumar K.V CC: Naveen N. Rao CC: James E.J. Bottomley CC: Martin K. Petersen CC: linux-scsi@vger.kernel.org CC: linuxppc-dev@lists.ozlabs.org Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240116045151.3940401-23-lizhijian@fujitsu.com Acked-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvfc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 46d0b3a0e12f..05b126bfd18b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3482,8 +3482,7 @@ static ssize_t ibmvfc_show_host_partition_name(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.partition_name); + return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.partition_name); } static ssize_t ibmvfc_show_host_device_name(struct device *dev, @@ -3492,8 +3491,7 @@ static ssize_t ibmvfc_show_host_device_name(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.device_name); + return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.device_name); } static ssize_t ibmvfc_show_host_loc_code(struct device *dev, @@ -3502,8 +3500,7 @@ static ssize_t ibmvfc_show_host_loc_code(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.port_loc_code); + return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.port_loc_code); } static ssize_t ibmvfc_show_host_drc_name(struct device *dev, @@ -3512,8 +3509,7 @@ static ssize_t ibmvfc_show_host_drc_name(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.drc_name); + return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.drc_name); } static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, @@ -3521,7 +3517,8 @@ static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, { struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%d\n", be32_to_cpu(vhost->login_buf->resp.version)); + return sysfs_emit(buf, "%d\n", + be32_to_cpu(vhost->login_buf->resp.version)); } static ssize_t ibmvfc_show_host_capabilities(struct device *dev, @@ -3529,7 +3526,8 @@ static ssize_t ibmvfc_show_host_capabilities(struct device *dev, { struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%llx\n", be64_to_cpu(vhost->login_buf->resp.capabilities)); + return sysfs_emit(buf, "%llx\n", + be64_to_cpu(vhost->login_buf->resp.capabilities)); } /** @@ -3550,7 +3548,7 @@ static ssize_t ibmvfc_show_log_level(struct device *dev, int len; spin_lock_irqsave(shost->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->log_level); + len = sysfs_emit(buf, "%d\n", vhost->log_level); spin_unlock_irqrestore(shost->host_lock, flags); return len; } @@ -3589,7 +3587,7 @@ static ssize_t ibmvfc_show_scsi_channels(struct device *dev, int len; spin_lock_irqsave(shost->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "%d\n", scsi->desired_queues); + len = sysfs_emit(buf, "%d\n", scsi->desired_queues); spin_unlock_irqrestore(shost->host_lock, flags); return len; } From 01105c23de4263559919dd44e6ffc557fd261f0f Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 16 Jan 2024 12:51:35 +0800 Subject: [PATCH 089/814] scsi: ibmvscsi_tgt: Convert snprintf() to sysfs_emit() Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c:3619:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c:3625:8-16: WARNING: please use sysfs_emit > ./drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c:3633:8-16: WARNING: please use sysfs_emit No functional change intended CC: Michael Cyr CC: James E.J. Bottomley CC: Martin K. Petersen CC: linux-scsi@vger.kernel.org CC: target-devel@vger.kernel.org Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240116045151.3940401-24-lizhijian@fujitsu.com Acked-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 6b16020b1f59..68b99924ee4f 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -3616,13 +3616,13 @@ static void ibmvscsis_remove(struct vio_dev *vdev) static ssize_t system_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", system_id); + return sysfs_emit(buf, "%s\n", system_id); } static ssize_t partition_number_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%x\n", partition_number); + return sysfs_emit(buf, "%x\n", partition_number); } static ssize_t unit_address_show(struct device *dev, @@ -3630,7 +3630,7 @@ static ssize_t unit_address_show(struct device *dev, { struct scsi_info *vscsi = container_of(dev, struct scsi_info, dev); - return snprintf(buf, PAGE_SIZE, "%x\n", vscsi->dma_dev->unit_address); + return sysfs_emit(buf, "%x\n", vscsi->dma_dev->unit_address); } static int ibmvscsis_get_system_info(void) From 5fbf37e53091057fc53f1046ded8a967464c2ecf Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 16 Jan 2024 12:51:36 +0800 Subject: [PATCH 090/814] scsi: isci: Convert snprintf() to sysfs_emit() Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/scsi/isci/init.c:140:8-16: WARNING: please use sysfs_emit No functional change intended CC: Artur Paszkiewicz CC: James E.J. Bottomley CC: Martin K. Petersen CC: linux-scsi@vger.kernel.org Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240116045151.3940401-25-lizhijian@fujitsu.com Reviewed-by: Artur Paszkiewicz Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 6277162a028b..c582a3932cea 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -137,7 +137,7 @@ static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, c struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha); - return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id); + return sysfs_emit(buf, "%d\n", ihost->id); } static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL); From 8179041f801d085b14441c5c92cf4beb7b429e35 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 16 Jan 2024 12:51:43 +0800 Subject: [PATCH 091/814] scsi: pm8001: Convert snprintf() to sysfs_emit() Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/scsi/pm8001/pm8001_ctl.c:883:8-16: WARNING: please use sysfs_emit No functional change intended CC: Jack Wang CC: James E.J. Bottomley CC: Martin K. Petersen CC: linux-scsi@vger.kernel.org Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240116045151.3940401-32-lizhijian@fujitsu.com Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 5c26a13ffbd2..7b27618fd7b2 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -880,9 +880,9 @@ static ssize_t pm8001_show_update_fw(struct device *cdev, if (pm8001_ha->fw_status != FLASH_IN_PROGRESS) pm8001_ha->fw_status = FLASH_OK; - return snprintf(buf, PAGE_SIZE, "status=%x %s\n", - flash_error_table[i].err_code, - flash_error_table[i].reason); + return sysfs_emit(buf, "status=%x %s\n", + flash_error_table[i].err_code, + flash_error_table[i].reason); } static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP, pm8001_show_update_fw, pm8001_store_update_fw); From 994724e6b3f05fb3b6e4b1e87d7e074b65d47bf9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:02 -0600 Subject: [PATCH 092/814] scsi: core: Allow passthrough to request midlayer retries For passthrough we don't retry any error which we get a check condition for. This results in a lot of callers driving their own retries for all UAs, specific UAs, NOT_READY, specific sense values or any type of failure. This adds the core code to allow passthrough users to specify what errors they want the SCSI midlayer to retry for them. We can then convert users to drop a lot of their sense parsing and retry handling. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-2-michael.christie@oracle.com Reviewed-by: John Garry Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 98 ++++++++++++++++++++++++++++++++++++-- include/scsi/scsi_device.h | 48 +++++++++++++++++++ 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index cf3864f72093..16a33a558842 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -184,6 +184,92 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) __scsi_queue_insert(cmd, reason, true); } +void scsi_failures_reset_retries(struct scsi_failures *failures) +{ + struct scsi_failure *failure; + + failures->total_retries = 0; + + for (failure = failures->failure_definitions; failure->result; + failure++) + failure->retries = 0; +} +EXPORT_SYMBOL_GPL(scsi_failures_reset_retries); + +/** + * scsi_check_passthrough - Determine if passthrough scsi_cmnd needs a retry. + * @scmd: scsi_cmnd to check. + * @failures: scsi_failures struct that lists failures to check for. + * + * Returns -EAGAIN if the caller should retry else 0. + */ +static int scsi_check_passthrough(struct scsi_cmnd *scmd, + struct scsi_failures *failures) +{ + struct scsi_failure *failure; + struct scsi_sense_hdr sshdr; + enum sam_status status; + + if (!failures) + return 0; + + for (failure = failures->failure_definitions; failure->result; + failure++) { + if (failure->result == SCMD_FAILURE_RESULT_ANY) + goto maybe_retry; + + if (host_byte(scmd->result) && + host_byte(scmd->result) == host_byte(failure->result)) + goto maybe_retry; + + status = status_byte(scmd->result); + if (!status) + continue; + + if (failure->result == SCMD_FAILURE_STAT_ANY && + !scsi_status_is_good(scmd->result)) + goto maybe_retry; + + if (status != status_byte(failure->result)) + continue; + + if (status_byte(failure->result) != SAM_STAT_CHECK_CONDITION || + failure->sense == SCMD_FAILURE_SENSE_ANY) + goto maybe_retry; + + if (!scsi_command_normalize_sense(scmd, &sshdr)) + return 0; + + if (failure->sense != sshdr.sense_key) + continue; + + if (failure->asc == SCMD_FAILURE_ASC_ANY) + goto maybe_retry; + + if (failure->asc != sshdr.asc) + continue; + + if (failure->ascq == SCMD_FAILURE_ASCQ_ANY || + failure->ascq == sshdr.ascq) + goto maybe_retry; + } + + return 0; + +maybe_retry: + if (failure->allowed) { + if (failure->allowed == SCMD_FAILURE_NO_LIMIT || + ++failure->retries <= failure->allowed) + return -EAGAIN; + } else { + if (failures->total_allowed == SCMD_FAILURE_NO_LIMIT || + ++failures->total_retries <= failures->total_allowed) + return -EAGAIN; + } + + return 0; +} + /** * scsi_execute_cmd - insert request and wait for the result * @sdev: scsi_device @@ -192,7 +278,7 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * @buffer: data buffer * @bufflen: len of buffer * @timeout: request timeout in HZ - * @retries: number of times to retry request + * @ml_retries: number of times SCSI midlayer will retry request * @args: Optional args. See struct definition for field descriptions * * Returns the scsi_cmnd result field if a command was executed, or a negative @@ -200,7 +286,7 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) */ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, blk_opf_t opf, void *buffer, unsigned int bufflen, - int timeout, int retries, + int timeout, int ml_retries, const struct scsi_exec_args *args) { static const struct scsi_exec_args default_args; @@ -214,6 +300,7 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, args->sense_len != SCSI_SENSE_BUFFERSIZE)) return -EINVAL; +retry: req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags); if (IS_ERR(req)) return PTR_ERR(req); @@ -227,7 +314,7 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, scmd = blk_mq_rq_to_pdu(req); scmd->cmd_len = COMMAND_SIZE(cmd[0]); memcpy(scmd->cmnd, cmd, scmd->cmd_len); - scmd->allowed = retries; + scmd->allowed = ml_retries; scmd->flags |= args->scmd_flags; req->timeout = timeout; req->rq_flags |= RQF_QUIET; @@ -237,6 +324,11 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, */ blk_execute_rq(req, true); + if (scsi_check_passthrough(scmd, args->failures) == -EAGAIN) { + blk_mq_free_request(req); + goto retry; + } + /* * Some devices (USB mass-storage in particular) may transfer * garbage data together with a residue indicating that the data diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 5ec1e71a09de..4dceabb9dbe1 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -489,6 +489,52 @@ extern int scsi_is_sdev_device(const struct device *); extern int scsi_is_target_device(const struct device *); extern void scsi_sanitize_inquiry_string(unsigned char *s, int len); +/* + * scsi_execute_cmd users can set scsi_failure.result to have + * scsi_check_passthrough fail/retry a command. scsi_failure.result can be a + * specific host byte or message code, or SCMD_FAILURE_RESULT_ANY can be used + * to match any host or message code. + */ +#define SCMD_FAILURE_RESULT_ANY 0x7fffffff +/* + * Set scsi_failure.result to SCMD_FAILURE_STAT_ANY to fail/retry any failure + * scsi_status_is_good returns false for. + */ +#define SCMD_FAILURE_STAT_ANY 0xff +/* + * The following can be set to the scsi_failure sense, asc and ascq fields to + * match on any sense, ASC, or ASCQ value. + */ +#define SCMD_FAILURE_SENSE_ANY 0xff +#define SCMD_FAILURE_ASC_ANY 0xff +#define SCMD_FAILURE_ASCQ_ANY 0xff +/* Always retry a matching failure. */ +#define SCMD_FAILURE_NO_LIMIT -1 + +struct scsi_failure { + int result; + u8 sense; + u8 asc; + u8 ascq; + /* + * Number of times scsi_execute_cmd will retry the failure. It does + * not count for the total_allowed. + */ + s8 allowed; + /* Number of times the failure has been retried. */ + s8 retries; +}; + +struct scsi_failures { + /* + * If a scsi_failure does not have a retry limit setup this limit will + * be used. + */ + int total_allowed; + int total_retries; + struct scsi_failure *failure_definitions; +}; + /* Optional arguments to scsi_execute_cmd */ struct scsi_exec_args { unsigned char *sense; /* sense buffer */ @@ -497,12 +543,14 @@ struct scsi_exec_args { blk_mq_req_flags_t req_flags; /* BLK_MQ_REQ flags */ int scmd_flags; /* SCMD flags */ int *resid; /* residual length */ + struct scsi_failures *failures; /* failures to retry */ }; int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, blk_opf_t opf, void *buffer, unsigned int bufflen, int timeout, int retries, const struct scsi_exec_args *args); +void scsi_failures_reset_retries(struct scsi_failures *failures); extern void sdev_disable_disk_events(struct scsi_device *sdev); extern void sdev_enable_disk_events(struct scsi_device *sdev); From 2a1f96f60a4bf28207da653a844ea471840d2b91 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:03 -0600 Subject: [PATCH 093/814] scsi: core: Have midlayer retry scsi_probe_lun() errors This has scsi_probe_lun() ask the SCSI midlayer to retry UAs instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-3-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 46 ++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 44680f65ea14..a2bed0dbf996 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -626,6 +626,7 @@ void scsi_sanitize_inquiry_string(unsigned char *s, int len) } EXPORT_SYMBOL(scsi_sanitize_inquiry_string); + /** * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY * @sdev: scsi_device to probe @@ -647,10 +648,32 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; int pass, count, result, resid; - struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + /* + * not-ready to ready transition [asc/ascq=0x28/0x0] or + * power-on, reset [asc/ascq=0x29/0x0], continue. INQUIRY + * should not yield UNIT_ATTENTION but many buggy devices do + * so anyway. + */ + { + .sense = UNIT_ATTENTION, + .asc = 0x28, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .total_allowed = 3, + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { - .sshdr = &sshdr, .resid = &resid, + .failures = &failures, }; *bflags = 0; @@ -668,6 +691,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, pass, try_inquiry_len)); /* Each pass gets up to three chances to ignore Unit Attention */ + scsi_failures_reset_retries(&failures); + for (count = 0; count < 3; ++count) { memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; @@ -684,22 +709,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, "scsi scan: INQUIRY %s with code 0x%x\n", result ? "failed" : "successful", result)); - if (result > 0) { - /* - * not-ready to ready transition [asc/ascq=0x28/0x0] - * or power-on, reset [asc/ascq=0x29/0x0], continue. - * INQUIRY should not yield UNIT_ATTENTION - * but many buggy devices do so anyway. - */ - if (scsi_status_is_check_condition(result) && - scsi_sense_valid(&sshdr)) { - if ((sshdr.sense_key == UNIT_ATTENTION) && - ((sshdr.asc == 0x28) || - (sshdr.asc == 0x29)) && - (sshdr.ascq == 0)) - continue; - } - } else if (result == 0) { + if (result == 0) { /* * if nothing was transferred, we try * again. It's a workaround for some USB From 987d7d3db0b9b5428c4888ed375cca290667a597 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:04 -0600 Subject: [PATCH 094/814] scsi: core: Retry INQUIRY after timeout Description from: Martin Wilck : The SCSI mid layer doesn't retry commands after DID_TIME_OUT (see scsi_noretry_cmd()). Packet loss in the fabric can cause spurious timeouts during SCSI device probing, causing device probing to fail. This has been observed in FCoE uplink failover tests, for example. This patch fixes the issue by retrying the INQUIRY. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-4-michael.christie@oracle.com Reviewed-by: Christoph Hellwig Reviewed-by: Martin Wilck Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a2bed0dbf996..8ded08f37337 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -665,6 +665,10 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, .asc = 0x29, .result = SAM_STAT_CHECK_CONDITION, }, + { + .allowed = 1, + .result = DID_TIME_OUT << 16, + }, {} }; struct scsi_failures failures = { From 1008f5776fe5c398e1202c93b835943b04de3ec6 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:05 -0600 Subject: [PATCH 095/814] scsi: sd: Use separate buf for START_STOP in sd_spinup_disk() We currently reuse the cmd buffer for the TUR and START_STOP commands which requires us to reset the buffer when retrying. This has us use separate buffers for the 2 commands so we can make them const and I think it makes it easier to handle for retries but does not add too much extra to the stack use. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-5-michael.christie@oracle.com Reviewed-by: Christoph Hellwig Reviewed-by: John Garry Reviewed-by: Martin Wilck Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0833b3e6aa6e..3d85913d373c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2318,14 +2318,16 @@ sd_spinup_disk(struct scsi_disk *sdkp) * Issue command to spin up drive when not ready */ if (!spintime) { + /* Return immediately and start spin cycle */ + const u8 start_cmd[10] = { + [0] = START_STOP, + [1] = 1, + [4] = sdkp->device->start_stop_pwr_cond ? + 0x11 : 1, + }; + sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); - cmd[0] = START_STOP; - cmd[1] = 1; /* Return immediately */ - memset((void *) &cmd[2], 0, 8); - cmd[4] = 1; /* Start spin cycle */ - if (sdkp->device->start_stop_pwr_cond) - cmd[4] |= 1 << 4; - scsi_execute_cmd(sdkp->device, cmd, + scsi_execute_cmd(sdkp->device, start_cmd, REQ_OP_DRV_IN, NULL, 0, SD_TIMEOUT, sdkp->max_retries, &exec_args); From c1acf38cd11efdc921f7d41107b00c2cb79453fc Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:06 -0600 Subject: [PATCH 096/814] scsi: sd: Have midlayer retry sd_spinup_disk() errors This simplifies sd_spinup_disk() so the SCSI midlayer retries errors for it. Note that we retried every UA except Medium Not Present and also if scsi_status_is_good() returned failed which would happen for all check conditions. In this patch we use SCMD_FAILURE_STAT_ANY which will trigger for the same conditions as when scsi_status_is_good() returns false and there is status. This will cover all CCs including UAs so there is no explicit failures array entry for UAs except for Medium Not Present which we don't want to retry. There is one behavior change where we no longer retry when scsi_execute_cmd() returns < 0, but we should be ok. We don't need to retry for failures like the queue being removed, and for the case where there are no tags/reqs the block layer waits/retries for us. For possible memory allocation failures from blk_rq_map_kern() we use GFP_NOIO, so retrying will probably not help. We do not handle the outside loop's retries because we want to sleep between tries and we don't support that yet. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-6-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 77 +++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3d85913d373c..cb240015bde5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2235,55 +2235,68 @@ static int sd_done(struct scsi_cmnd *SCpnt) static void sd_spinup_disk(struct scsi_disk *sdkp) { - unsigned char cmd[10]; + static const u8 cmd[10] = { TEST_UNIT_READY }; unsigned long spintime_expire = 0; - int retries, spintime; + int spintime, sense_valid = 0; unsigned int the_result; struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + /* Do not retry Medium Not Present */ + { + .sense = UNIT_ATTENTION, + .asc = 0x3A, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = NOT_READY, + .asc = 0x3A, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Retry when scsi_status_is_good would return false 3 times */ + { + .result = SCMD_FAILURE_STAT_ANY, + .allowed = 3, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; - int sense_valid = 0; spintime = 0; /* Spin up drives, as required. Only do this at boot time */ /* Spinup needs to be done for module loads too. */ do { - retries = 0; + bool media_was_present = sdkp->media_present; - do { - bool media_was_present = sdkp->media_present; + scsi_failures_reset_retries(&failures); - cmd[0] = TEST_UNIT_READY; - memset((void *) &cmd[1], 0, 9); + the_result = scsi_execute_cmd(sdkp->device, cmd, REQ_OP_DRV_IN, + NULL, 0, SD_TIMEOUT, + sdkp->max_retries, &exec_args); - the_result = scsi_execute_cmd(sdkp->device, cmd, - REQ_OP_DRV_IN, NULL, 0, - SD_TIMEOUT, - sdkp->max_retries, - &exec_args); - if (the_result > 0) { - /* - * If the drive has indicated to us that it - * doesn't have any media in it, don't bother - * with any more polling. - */ - if (media_not_present(sdkp, &sshdr)) { - if (media_was_present) - sd_printk(KERN_NOTICE, sdkp, - "Media removed, stopped polling\n"); - return; - } - - sense_valid = scsi_sense_valid(&sshdr); + if (the_result > 0) { + /* + * If the drive has indicated to us that it doesn't + * have any media in it, don't bother with any more + * polling. + */ + if (media_not_present(sdkp, &sshdr)) { + if (media_was_present) + sd_printk(KERN_NOTICE, sdkp, + "Media removed, stopped polling\n"); + return; } - retries++; - } while (retries < 3 && - (!scsi_status_is_good(the_result) || - (scsi_status_is_check_condition(the_result) && - sense_valid && sshdr.sense_key == UNIT_ATTENTION))); + sense_valid = scsi_sense_valid(&sshdr); + } if (!scsi_status_is_check_condition(the_result)) { /* no sense, TUR either succeeded or failed From fabe3ee92e180726edf7c7509dc625410a88084b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:07 -0600 Subject: [PATCH 097/814] scsi: device_handler: hp_sw: Have midlayer retry scsi_execute_cmd() errors This has hp_sw have the SCSI midlayer retry scsi_execute_cmd() errors instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-7-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 49 ++++++++++++++------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 944ea4e0cc45..b6eaf49dfb00 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -46,9 +46,6 @@ static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h, int ret = SCSI_DH_IO; switch (sshdr->sense_key) { - case UNIT_ATTENTION: - ret = SCSI_DH_IMM_RETRY; - break; case NOT_READY: if (sshdr->asc == 0x04 && sshdr->ascq == 2) { /* @@ -85,11 +82,24 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) int ret, res; blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SCMD_FAILURE_NO_LIMIT, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; -retry: res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT, HP_SW_RETRIES, &exec_args); if (res > 0 && scsi_sense_valid(&sshdr)) { @@ -104,9 +114,6 @@ retry: ret = SCSI_DH_IO; } - if (ret == SCSI_DH_IMM_RETRY) - goto retry; - return ret; } @@ -122,14 +129,31 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h) struct scsi_sense_hdr sshdr; struct scsi_device *sdev = h->sdev; int res, rc; - int retry_cnt = HP_SW_RETRIES; blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; + struct scsi_failure failure_defs[] = { + { + /* + * LUN not ready - manual intervention required + * + * Switch-over in progress, retry. + */ + .sense = NOT_READY, + .asc = 0x04, + .ascq = 0x03, + .allowed = HP_SW_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; -retry: res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT, HP_SW_RETRIES, &exec_args); if (!res) { @@ -144,13 +168,6 @@ retry: switch (sshdr.sense_key) { case NOT_READY: if (sshdr.asc == 0x04 && sshdr.ascq == 3) { - /* - * LUN not ready - manual intervention required - * - * Switch-over in progress, retry. - */ - if (--retry_cnt) - goto retry; rc = SCSI_DH_RETRY; break; } From f316ff46a0ffeada53da7e046bf67b0f3246d4b3 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:08 -0600 Subject: [PATCH 098/814] scsi: device_handler: rdac: Have midlayer retry send_mode_select() errors This has rdac have the SCSI midlayer retry errors instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-8-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_rdac.c | 84 ++++++++++++---------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 1ac2ae17e8be..f8a09e3eba58 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -485,43 +485,17 @@ static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) static int mode_select_handle_sense(struct scsi_device *sdev, struct scsi_sense_hdr *sense_hdr) { - int err = SCSI_DH_IO; struct rdac_dh_data *h = sdev->handler_data; if (!scsi_sense_valid(sense_hdr)) - goto done; - - switch (sense_hdr->sense_key) { - case NO_SENSE: - case ABORTED_COMMAND: - case UNIT_ATTENTION: - err = SCSI_DH_RETRY; - break; - case NOT_READY: - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) - /* LUN Not Ready and is in the Process of Becoming - * Ready - */ - err = SCSI_DH_RETRY; - break; - case ILLEGAL_REQUEST: - if (sense_hdr->asc == 0x91 && sense_hdr->ascq == 0x36) - /* - * Command Lock contention - */ - err = SCSI_DH_IMM_RETRY; - break; - default: - break; - } + return SCSI_DH_IO; RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " "MODE_SELECT returned with sense %02x/%02x/%02x", (char *) h->ctlr->array_name, h->ctlr->index, sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq); -done: - return err; + return SCSI_DH_IO; } static void send_mode_select(struct work_struct *work) @@ -530,7 +504,7 @@ static void send_mode_select(struct work_struct *work) container_of(work, struct rdac_controller, ms_work); struct scsi_device *sdev = ctlr->ms_sdev; struct rdac_dh_data *h = sdev->handler_data; - int rc, err, retry_cnt = RDAC_RETRY_COUNT; + int rc, err; struct rdac_queue_data *tmp, *qdata; LIST_HEAD(list); unsigned char cdb[MAX_COMMAND_SIZE]; @@ -538,8 +512,49 @@ static void send_mode_select(struct work_struct *work) unsigned int data_size; blk_opf_t opf = REQ_OP_DRV_OUT | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; + struct scsi_failure failure_defs[] = { + { + .sense = NO_SENSE, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = ABORTED_COMMAND, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* LUN Not Ready and is in the Process of Becoming Ready */ + { + .sense = NOT_READY, + .asc = 0x04, + .ascq = 0x01, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Command Lock contention */ + { + .sense = ILLEGAL_REQUEST, + .asc = 0x91, + .ascq = 0x36, + .allowed = SCMD_FAILURE_NO_LIMIT, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .total_allowed = RDAC_RETRY_COUNT, + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; spin_lock(&ctlr->ms_lock); @@ -548,15 +563,12 @@ static void send_mode_select(struct work_struct *work) ctlr->ms_sdev = NULL; spin_unlock(&ctlr->ms_lock); - retry: memset(cdb, 0, sizeof(cdb)); data_size = rdac_failover_get(ctlr, &list, cdb); - RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " - "%s MODE_SELECT command", - (char *) h->ctlr->array_name, h->ctlr->index, - (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, queueing MODE_SELECT command", + (char *)h->ctlr->array_name, h->ctlr->index); rc = scsi_execute_cmd(sdev, cdb, opf, &h->ctlr->mode_select, data_size, RDAC_TIMEOUT * HZ, RDAC_RETRIES, &exec_args); @@ -570,10 +582,6 @@ static void send_mode_select(struct work_struct *work) err = SCSI_DH_IO; } else { err = mode_select_handle_sense(sdev, &sshdr); - if (err == SCSI_DH_RETRY && retry_cnt--) - goto retry; - if (err == SCSI_DH_IMM_RETRY) - goto retry; } list_for_each_entry_safe(qdata, tmp, &list, entry) { From 5dbf10473642f822de62038a70addb54756b0109 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:09 -0600 Subject: [PATCH 099/814] scsi: spi: Have midlayer retry spi_execute() UAs This has spi_execute() have the SCSI midlayer retry UAs instead of driving them. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-9-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_spi.c | 35 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index f668c1c0a98f..64852e6df3e3 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -108,29 +108,30 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd, enum req_op op, void *buffer, unsigned int bufflen, struct scsi_sense_hdr *sshdr) { - int i, result; - struct scsi_sense_hdr sshdr_tmp; blk_opf_t opf = op | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = DV_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { + /* bypass the SDEV_QUIESCE state with BLK_MQ_REQ_PM */ .req_flags = BLK_MQ_REQ_PM, - .sshdr = sshdr ? : &sshdr_tmp, + .sshdr = sshdr, + .failures = &failures, }; - sshdr = exec_args.sshdr; - - for(i = 0; i < DV_RETRIES; i++) { - /* - * The purpose of the RQF_PM flag below is to bypass the - * SDEV_QUIESCE state. - */ - result = scsi_execute_cmd(sdev, cmd, opf, buffer, bufflen, - DV_TIMEOUT, 1, &exec_args); - if (result < 0 || !scsi_sense_valid(sshdr) || - sshdr->sense_key != UNIT_ATTENTION) - break; - } - return result; + return scsi_execute_cmd(sdev, cmd, opf, buffer, bufflen, DV_TIMEOUT, 1, + &exec_args); } static struct { From 183053203d4532431bfdbddc04dd9306a03164a5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:10 -0600 Subject: [PATCH 100/814] scsi: sd: Have midlayer retry sd_sync_cache() errors This has sd_sync_cache() have the SCSI midlayer retry errors instead of driving them itself. There is one behavior change where we no longer retry when scsi_execute_cmd() returns < 0, but we should be ok. We don't need to retry for failures like the queue being removed, and for the case where there are no tags/reqs the block layer waits/retries for us. For possible memory allocation failures from blk_rq_map_kern() we use GFP_NOIO, so retrying will probably not help. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-10-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index cb240015bde5..c2068d83c812 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1645,36 +1645,35 @@ out: static int sd_sync_cache(struct scsi_disk *sdkp) { - int retries, res; + int res; struct scsi_device *sdp = sdkp->device; const int timeout = sdp->request_queue->rq_timeout * SD_FLUSH_TIMEOUT_MULTIPLIER; + /* Leave the rest of the command zero to indicate flush everything. */ + const unsigned char cmd[16] = { sdp->use_16_for_sync ? + SYNCHRONIZE_CACHE_16 : SYNCHRONIZE_CACHE }; struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + { + .allowed = 3, + .result = SCMD_FAILURE_RESULT_ANY, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .req_flags = BLK_MQ_REQ_PM, .sshdr = &sshdr, + .failures = &failures, }; if (!scsi_device_online(sdp)) return -ENODEV; - for (retries = 3; retries > 0; --retries) { - unsigned char cmd[16] = { 0 }; - - if (sdp->use_16_for_sync) - cmd[0] = SYNCHRONIZE_CACHE_16; - else - cmd[0] = SYNCHRONIZE_CACHE; - /* - * Leave the rest of the command zero to indicate - * flush everything. - */ - res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0, - timeout, sdkp->max_retries, &exec_args); - if (res == 0) - break; - } - + res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0, timeout, + sdkp->max_retries, &exec_args); if (res) { sd_print_result(sdkp, "Synchronize Cache(10) failed", res); From 11a26723210e91476b15f3d4f5def88609d04880 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:11 -0600 Subject: [PATCH 101/814] scsi: ch: Remove unit_attention unit_attention is not used so remove it. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-11-michael.christie@oracle.com Reviewed-by: Christoph Hellwig Reviewed-by: John Garry Reviewed-by: Martin Wilck Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 2b864061e073..9d7fa097ae9e 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -113,7 +113,6 @@ typedef struct { struct scsi_device **dt; /* ptrs to data transfer elements */ u_int firsts[CH_TYPES]; u_int counts[CH_TYPES]; - u_int unit_attention; u_int voltags; struct mutex lock; } scsi_changer; @@ -208,7 +207,6 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, switch(sshdr.sense_key) { case UNIT_ATTENTION: - ch->unit_attention = 1; if (retries++ < 3) goto retry; break; From e11f35c46ebd746049a3d84dc68e7e8681aa26e8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:12 -0600 Subject: [PATCH 102/814] scsi: ch: Have midlayer retry ch_do_scsi() UAs This has ch_do_scsi() have the SCSI midlayer retry UAs instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-12-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 9d7fa097ae9e..1befcd5b2a0f 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -185,17 +185,29 @@ static int ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, void *buffer, unsigned int buflength, enum req_op op) { - int errno, retries = 0, timeout, result; + int errno = 0, timeout, result; struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = 3, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) ? timeout_init : timeout_move; - retry: - errno = 0; result = scsi_execute_cmd(ch->device, cmd, op, buffer, buflength, timeout * HZ, MAX_RETRIES, &exec_args); if (result < 0) @@ -204,13 +216,6 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, if (debug) scsi_print_sense_hdr(ch->device, ch->name, &sshdr); errno = ch_find_errno(&sshdr); - - switch(sshdr.sense_key) { - case UNIT_ATTENTION: - if (retries++ < 3) - goto retry; - break; - } } return errno; } From 21bdff48e12bf674208e0575a03ca89d663f1a3c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:13 -0600 Subject: [PATCH 103/814] scsi: core: Have midlayer retry scsi_mode_sense() UAs This has scsi_mode_sense() have the SCSI midlayer retry UAs instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-13-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 16a33a558842..8a79e4f36636 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2262,11 +2262,25 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, int subpage, unsigned char cmd[12]; int use_10_for_ms; int header_length; - int result, retry_count = retries; + int result; struct scsi_sense_hdr my_sshdr; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = retries, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { /* caller might not be interested in sense, but we need it */ .sshdr = sshdr ? : &my_sshdr, + .failures = &failures, }; memset(data, 0, sizeof(*data)); @@ -2328,12 +2342,6 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, int subpage, goto retry; } } - if (scsi_status_is_check_condition(result) && - sshdr->sense_key == UNIT_ATTENTION && - retry_count) { - retry_count--; - goto retry; - } } return -EIO; } From 8d24677ebb9e79201801cedefc5127655d5e8c3f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:14 -0600 Subject: [PATCH 104/814] scsi: core: Have SCSI midlayer retry scsi_report_lun_scan() errors This has scsi_report_lun_scan() have the SCSI midlayer retry errors instead of driving them itself. There is one behavior change where we no longer retry when scsi_execute_cmd() returns < 0, but we should be ok. We don't need to retry for failures like the queue being removed, and for the case where there are no tags/reqs the block layer waits/retries for us. For possible memory allocation failures from blk_rq_map_kern() we use GFP_NOIO, so retrying will probably not help. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-14-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 55 +++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 8ded08f37337..70c0319be34c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1416,14 +1416,34 @@ static int scsi_report_lun_scan(struct scsi_target *starget, blist_flags_t bflag unsigned int length; u64 lun; unsigned int num_luns; - unsigned int retries; int result; struct scsi_lun *lunp, *lun_data; - struct scsi_sense_hdr sshdr; struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Fail all CCs except the UA above */ + { + .sense = SCMD_FAILURE_SENSE_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Retry any other errors not listed above */ + { + .result = SCMD_FAILURE_RESULT_ANY, + }, + {} + }; + struct scsi_failures failures = { + .total_allowed = 3, + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { - .sshdr = &sshdr, + .failures = &failures, }; int ret = 0; @@ -1494,29 +1514,18 @@ retry: * should come through as a check condition, and will not generate * a retry. */ - for (retries = 0; retries < 3; retries++) { - SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, - "scsi scan: Sending REPORT LUNS to (try %d)\n", - retries)); + scsi_failures_reset_retries(&failures); - result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, - lun_data, length, - SCSI_REPORT_LUNS_TIMEOUT, 3, - &exec_args); + SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, + "scsi scan: Sending REPORT LUNS\n")); - SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, - "scsi scan: REPORT LUNS" - " %s (try %d) result 0x%x\n", - result ? "failed" : "successful", - retries, result)); - if (result == 0) - break; - else if (scsi_sense_valid(&sshdr)) { - if (sshdr.sense_key != UNIT_ATTENTION) - break; - } - } + result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, lun_data, + length, SCSI_REPORT_LUNS_TIMEOUT, 3, + &exec_args); + SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, + "scsi scan: REPORT LUNS %s result 0x%x\n", + result ? "failed" : "successful", result)); if (result) { /* * The device probably does not support a REPORT LUN command From eea6ef3792e34bd9476bef2fad074a8ce24915ec Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:15 -0600 Subject: [PATCH 105/814] scsi: sd: Have pr commands retry UAs It's common to get a UA when doing PR commands. It could be due to a target restarting, transport level relogin or other PR commands like a release causing it. The upper layers don't get the sense and in some cases have no idea if it's a SCSI device, so this has the sd layer retry. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-15-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c2068d83c812..4196f722c3f6 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1800,8 +1800,22 @@ static int sd_pr_in_command(struct block_device *bdev, u8 sa, struct scsi_device *sdev = sdkp->device; struct scsi_sense_hdr sshdr; u8 cmd[10] = { PERSISTENT_RESERVE_IN, sa }; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = 5, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; int result; @@ -1888,8 +1902,22 @@ static int sd_pr_out_command(struct block_device *bdev, u8 sa, u64 key, struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); struct scsi_device *sdev = sdkp->device; struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = 5, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; int result; u8 cmd[16] = { 0, }; From 0f11328f2f46618c8c4734041fdb2aacfa99b802 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:16 -0600 Subject: [PATCH 106/814] scsi: sd: Have midlayer retry read_capacity_10() errors This has read_capacity_10() have the SCSI midlayer retry errors instead of driving them itself. There are 2 behavior changes with this patch: 1. There is one behavior change where we no longer retry when scsi_execute_cmd() returns < 0, but we should be ok. We don't need to retry for failures like the queue being removed, and for the case where there are no tags/reqs since the block layer waits/retries for us. For possible memory allocation failures from blk_rq_map_kern() we use GFP_NOIO, so retrying will probably not help. 2. For the specific UAs we checked for and retried, we would get READ_CAPACITY_RETRIES_ON_RESET retries plus whatever retries were left from the main loop's retries. Each UA now gets READ_CAPACITY_RETRIES_ON_RESET retries, and the other errors get up to 3 retries. This is most likely ok, because READ_CAPACITY_RETRIES_ON_RESET is already 10 and is not based on anything specific like a spec or device, so the extra 3 we got from the main loop was probably just an accident and is not going to help. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-16-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 62 +++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4196f722c3f6..49159dcd638d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2588,42 +2588,58 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, unsigned char *buffer) { - unsigned char cmd[16]; + static const u8 cmd[10] = { READ_CAPACITY }; struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + /* Do not retry Medium Not Present */ + { + .sense = UNIT_ATTENTION, + .asc = 0x3A, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = NOT_READY, + .asc = 0x3A, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Device reset might occur several times so retry a lot */ + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .allowed = READ_CAPACITY_RETRIES_ON_RESET, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Any other error not listed above retry 3 times */ + { + .result = SCMD_FAILURE_RESULT_ANY, + .allowed = 3, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, + .failures = &failures, }; int sense_valid = 0; int the_result; - int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET; sector_t lba; unsigned sector_size; - do { - cmd[0] = READ_CAPACITY; - memset(&cmd[1], 0, 9); - memset(buffer, 0, 8); + memset(buffer, 0, 8); - the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer, - 8, SD_TIMEOUT, sdkp->max_retries, - &exec_args); + the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer, + 8, SD_TIMEOUT, sdkp->max_retries, + &exec_args); + + if (the_result > 0) { + sense_valid = scsi_sense_valid(&sshdr); if (media_not_present(sdkp, &sshdr)) return -ENODEV; - - if (the_result > 0) { - sense_valid = scsi_sense_valid(&sshdr); - if (sense_valid && - sshdr.sense_key == UNIT_ATTENTION && - sshdr.asc == 0x29 && sshdr.ascq == 0x00) - /* Device reset might occur several times, - * give it one more chance */ - if (--reset_retries > 0) - continue; - } - retries--; - - } while (the_result && retries); + } if (the_result) { sd_print_result(sdkp, "Read Capacity(10) failed", the_result); From 3a7b4579328ec741d909066d648ca6be139f7bb6 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:17 -0600 Subject: [PATCH 107/814] scsi: ses: Have midlayer retry scsi_execute_cmd() errors This has ses have the SCSI midlayer retry scsi_execute_cmd() errors instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-17-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ses.c | 66 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index d7d0c35c58b8..0f2c87cc95e6 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -87,19 +87,32 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code, 0 }; unsigned char recv_page_code; - unsigned int retries = SES_RETRIES; - struct scsi_sense_hdr sshdr; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SES_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = NOT_READY, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SES_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { - .sshdr = &sshdr, + .failures = &failures, }; - do { - ret = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, bufflen, - SES_TIMEOUT, 1, &exec_args); - } while (ret > 0 && --retries && scsi_sense_valid(&sshdr) && - (sshdr.sense_key == NOT_READY || - (sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29))); - + ret = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, bufflen, + SES_TIMEOUT, 1, &exec_args); if (unlikely(ret)) return ret; @@ -131,19 +144,32 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code, bufflen & 0xff, 0 }; - struct scsi_sense_hdr sshdr; - unsigned int retries = SES_RETRIES; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SES_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = NOT_READY, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SES_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args exec_args = { - .sshdr = &sshdr, + .failures = &failures, }; - do { - result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, buf, - bufflen, SES_TIMEOUT, 1, &exec_args); - } while (result > 0 && --retries && scsi_sense_valid(&sshdr) && - (sshdr.sense_key == NOT_READY || - (sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29))); - + result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, buf, bufflen, + SES_TIMEOUT, 1, &exec_args); if (result) sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", result); From b72f2d149e24747ff686c21b44e04762fc9d3a2f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:18 -0600 Subject: [PATCH 108/814] scsi: sr: Have midlayer retry get_sectorsize() errors This has get_sectorsize() have the SCSI midlayer retry errors instead of driving them itself. There is one behavior change where we no longer retry when scsi_execute_cmd() returns < 0, but we should be ok. We don't need to retry for failures like the queue being removed, and for the case where there are no tags/reqs the block layer waits/retries for us. For possible memory allocation failures from blk_rq_map_kern() we use GFP_NOIO, so retrying will probably not help. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-18-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sr.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d093dd187b2f..268b3a40891e 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -717,27 +717,29 @@ fail: static void get_sectorsize(struct scsi_cd *cd) { - unsigned char cmd[10]; - unsigned char buffer[8]; - int the_result, retries = 3; + static const u8 cmd[10] = { READ_CAPACITY }; + unsigned char buffer[8] = { }; + int the_result; int sector_size; struct request_queue *queue; + struct scsi_failure failure_defs[] = { + { + .result = SCMD_FAILURE_RESULT_ANY, + .allowed = 3, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; + const struct scsi_exec_args exec_args = { + .failures = &failures, + }; - do { - cmd[0] = READ_CAPACITY; - memset((void *) &cmd[1], 0, 9); - memset(buffer, 0, sizeof(buffer)); - - /* Do the command and wait.. */ - the_result = scsi_execute_cmd(cd->device, cmd, REQ_OP_DRV_IN, - buffer, sizeof(buffer), - SR_TIMEOUT, MAX_RETRIES, NULL); - - retries--; - - } while (the_result && retries); - - + /* Do the command and wait.. */ + the_result = scsi_execute_cmd(cd->device, cmd, REQ_OP_DRV_IN, buffer, + sizeof(buffer), SR_TIMEOUT, MAX_RETRIES, + &exec_args); if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ From b8c3a7bac9b6cddeeb7cb82f3372310ecabf83ef Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:19 -0600 Subject: [PATCH 109/814] scsi: ufs: Have midlayer retry start stop errors This has the SCSI midlayer retry errors instead of driving them itself. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-19-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 029d017fc1b6..5cd9509e0c31 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9475,7 +9475,17 @@ static int ufshcd_execute_start_stop(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) { const unsigned char cdb[6] = { START_STOP, 0, 0, 0, pwr_mode << 4, 0 }; + struct scsi_failure failure_defs[] = { + { + .allowed = 2, + .result = SCMD_FAILURE_RESULT_ANY, + }, + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; const struct scsi_exec_args args = { + .failures = &failures, .sshdr = sshdr, .req_flags = BLK_MQ_REQ_PM, .scmd_flags = SCMD_FAIL_IF_RECOVERING, @@ -9501,7 +9511,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, struct scsi_sense_hdr sshdr; struct scsi_device *sdp; unsigned long flags; - int ret, retries; + int ret; spin_lock_irqsave(hba->host->host_lock, flags); sdp = hba->ufs_device_wlun; @@ -9527,15 +9537,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, * callbacks hence set the RQF_PM flag so that it doesn't resume the * already suspended childs. */ - for (retries = 3; retries > 0; --retries) { - ret = ufshcd_execute_start_stop(sdp, pwr_mode, &sshdr); - /* - * scsi_execute() only returns a negative value if the request - * queue is dying. - */ - if (ret <= 0) - break; - } + ret = ufshcd_execute_start_stop(sdp, pwr_mode, &sshdr); if (ret) { sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", From 25a1f7a0a1fe6fa69a5370fbb5cc6dcf3726d81e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 22 Jan 2024 18:22:20 -0600 Subject: [PATCH 110/814] scsi: core: Add kunit tests for scsi_check_passthrough() Add some kunit tests for scsi_check_passthrough() so we can easily make sure we are hitting the cases for which it's difficult to replicate in hardware or even scsi_debug. Signed-off-by: Mike Christie Link: https://lore.kernel.org/r/20240123002220.129141-20-michael.christie@oracle.com Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 9 + drivers/scsi/scsi_lib.c | 4 + drivers/scsi/scsi_lib_test.c | 330 +++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/scsi/scsi_lib_test.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index addac7fbe37b..e20af95a912b 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -67,6 +67,15 @@ config SCSI_PROC_FS If unsure say Y. +config SCSI_LIB_KUNIT_TEST + tristate "KUnit tests for SCSI Mid Layer's scsi_lib" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Run SCSI Mid Layer's KUnit tests for scsi_lib. + + If unsure say N. + comment "SCSI support type (disk, tape, CD-ROM)" depends on SCSI diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 8a79e4f36636..c726f2025c59 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3434,3 +3434,7 @@ void scsi_build_sense(struct scsi_cmnd *scmd, int desc, u8 key, u8 asc, u8 ascq) scmd->result = SAM_STAT_CHECK_CONDITION; } EXPORT_SYMBOL_GPL(scsi_build_sense); + +#ifdef CONFIG_SCSI_KUNIT_TEST +#include "scsi_lib_test.c" +#endif diff --git a/drivers/scsi/scsi_lib_test.c b/drivers/scsi/scsi_lib_test.c new file mode 100644 index 000000000000..99834426a100 --- /dev/null +++ b/drivers/scsi/scsi_lib_test.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for scsi_lib.c. + * + * Copyright (C) 2023, Oracle Corporation + */ +#include + +#include +#include +#include + +#define SCSI_LIB_TEST_MAX_ALLOWED 3 +#define SCSI_LIB_TEST_TOTAL_MAX_ALLOWED 5 + +static void scsi_lib_test_multiple_sense(struct kunit *test) +{ + struct scsi_failure multiple_sense_failure_defs[] = { + { + .sense = DATA_PROTECT, + .asc = 0x1, + .ascq = 0x1, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = UNIT_ATTENTION, + .asc = 0x11, + .ascq = 0x0, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = NOT_READY, + .asc = 0x11, + .ascq = 0x22, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = ABORTED_COMMAND, + .asc = 0x11, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = HARDWARE_ERROR, + .asc = SCMD_FAILURE_ASC_ANY, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = ILLEGAL_REQUEST, + .asc = 0x91, + .ascq = 0x36, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = multiple_sense_failure_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + int i; + + /* Match end of array */ + scsi_build_sense(&sc, 0, ILLEGAL_REQUEST, 0x91, 0x36); + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); + /* Basic match in array */ + scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x11, 0x0); + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); + /* No matching sense entry */ + scsi_build_sense(&sc, 0, MISCOMPARE, 0x11, 0x11); + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + /* Match using SCMD_FAILURE_ASCQ_ANY */ + scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x11, 0x22); + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); + /* Fail to match */ + scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x22, 0x22); + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + /* Match using SCMD_FAILURE_ASC_ANY */ + scsi_build_sense(&sc, 0, HARDWARE_ERROR, 0x11, 0x22); + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); + /* No matching status entry */ + sc.result = SAM_STAT_RESERVATION_CONFLICT; + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + + /* Test hitting allowed limit */ + scsi_build_sense(&sc, 0, NOT_READY, 0x11, 0x22); + for (i = 0; i < SCSI_LIB_TEST_MAX_ALLOWED; i++) + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, + &failures)); + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + + /* reset retries so we can retest */ + failures.failure_definitions = multiple_sense_failure_defs; + scsi_failures_reset_retries(&failures); + + /* Test no retries allowed */ + scsi_build_sense(&sc, 0, DATA_PROTECT, 0x1, 0x1); + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_any_sense(struct kunit *test) +{ + struct scsi_failure any_sense_failure_defs[] = { + { + .result = SCMD_FAILURE_SENSE_ANY, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = any_sense_failure_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + + /* Match using SCMD_FAILURE_SENSE_ANY */ + failures.failure_definitions = any_sense_failure_defs; + scsi_build_sense(&sc, 0, MEDIUM_ERROR, 0x11, 0x22); + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_host(struct kunit *test) +{ + struct scsi_failure retryable_host_failure_defs[] = { + { + .result = DID_TRANSPORT_DISRUPTED << 16, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + }, + { + .result = DID_TIME_OUT << 16, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = retryable_host_failure_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + + /* No matching host byte entry */ + failures.failure_definitions = retryable_host_failure_defs; + sc.result = DID_NO_CONNECT << 16; + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + /* Matching host byte entry */ + sc.result = DID_TIME_OUT << 16; + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_any_failure(struct kunit *test) +{ + struct scsi_failure any_failure_defs[] = { + { + .result = SCMD_FAILURE_RESULT_ANY, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = any_failure_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + + /* Match SCMD_FAILURE_RESULT_ANY */ + failures.failure_definitions = any_failure_defs; + sc.result = DID_TRANSPORT_FAILFAST << 16; + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_any_status(struct kunit *test) +{ + struct scsi_failure any_status_failure_defs[] = { + { + .result = SCMD_FAILURE_STAT_ANY, + .allowed = SCSI_LIB_TEST_MAX_ALLOWED, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = any_status_failure_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + + /* Test any status handling */ + failures.failure_definitions = any_status_failure_defs; + sc.result = SAM_STAT_RESERVATION_CONFLICT; + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_total_allowed(struct kunit *test) +{ + struct scsi_failure total_allowed_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Fail all CCs except the UA above */ + { + .sense = SCMD_FAILURE_SENSE_ANY, + .result = SAM_STAT_CHECK_CONDITION, + }, + /* Retry any other errors not listed above */ + { + .result = SCMD_FAILURE_RESULT_ANY, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = total_allowed_defs, + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + int i; + + /* Test total_allowed */ + failures.failure_definitions = total_allowed_defs; + scsi_failures_reset_retries(&failures); + failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; + + scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0); + for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++) + /* Retry since we under the total_allowed limit */ + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, + &failures)); + sc.result = DID_TIME_OUT << 16; + /* We have now hit the total_allowed limit so no more retries */ + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_mixed_total(struct kunit *test) +{ + struct scsi_failure mixed_total_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = 0x28, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .result = SAM_STAT_CHECK_CONDITION, + }, + { + .allowed = 1, + .result = DID_TIME_OUT << 16, + }, + {} + }; + u8 sense[SCSI_SENSE_BUFFERSIZE] = {}; + struct scsi_failures failures = { + .failure_definitions = mixed_total_defs, + }; + struct scsi_cmnd sc = { + .sense_buffer = sense, + }; + int i; + + /* + * Test total_allowed when there is a mix of per failure allowed + * and total_allowed limits. + */ + failures.failure_definitions = mixed_total_defs; + scsi_failures_reset_retries(&failures); + failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; + + scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0); + for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++) + /* Retry since we under the total_allowed limit */ + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, + &failures)); + /* Do not retry since we are now over total_allowed limit */ + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); + + scsi_failures_reset_retries(&failures); + scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0); + for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++) + /* Retry since we under the total_allowed limit */ + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, + &failures)); + sc.result = DID_TIME_OUT << 16; + /* Retry because this failure has a per failure limit */ + KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures)); + scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x29, 0x0); + /* total_allowed is now hit so no more retries */ + KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures)); +} + +static void scsi_lib_test_check_passthough(struct kunit *test) +{ + scsi_lib_test_multiple_sense(test); + scsi_lib_test_any_sense(test); + scsi_lib_test_host(test); + scsi_lib_test_any_failure(test); + scsi_lib_test_any_status(test); + scsi_lib_test_total_allowed(test); + scsi_lib_test_mixed_total(test); +} + +static struct kunit_case scsi_lib_test_cases[] = { + KUNIT_CASE(scsi_lib_test_check_passthough), + {} +}; + +static struct kunit_suite scsi_lib_test_suite = { + .name = "scsi_lib", + .test_cases = scsi_lib_test_cases, +}; + +kunit_test_suite(scsi_lib_test_suite); From 06e34728827cb47026e80db22304d03ee83c73a8 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 28 Dec 2023 13:42:36 +0800 Subject: [PATCH 111/814] phy: qcom: qmp-pcie: Update PCIe1 PHY settings for SM8550 Align PCIe1 PHY settings with SM8550 latest PCIe PHY Hardware Programming Guide. Signed-off-by: Can Guo Signed-off-by: Qiang Yu Tested-by: Neil Armstrong # on SM8550-HDK Link: https://lore.kernel.org/r/1703742157-69840-2-git-send-email-quic_qianyu@quicinc.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 16 +++++++++++----- .../phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h | 2 ++ drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h | 1 + .../qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h | 2 ++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 3ba302a7285c..bdfdbcde55bf 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -1967,10 +1967,9 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_serdes_tbl[] = { static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_ln_shrd_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_Q_EN_RATES, 0xe), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x0d), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0x12), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), @@ -1987,6 +1986,7 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_ln_shrd_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE, 0x5b), }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_tx_tbl[] = { @@ -1999,13 +1999,15 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_tx_tbl[] = { }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x7c), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_TX_ADPT_CTRL, 0x10), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), @@ -2027,11 +2029,13 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x78), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_20_VGA_CAL_CNTRL1, 0x00), }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G12S1_TXDEEMPH_M6DB, 0x17), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G3S2_PRE_GAIN, 0x2e), - QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL, 0x25), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_RX_SIGDET_LVL, 0xcc), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG4, 0x00), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG5, 0x22), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG1, 0x04), @@ -2042,6 +2046,8 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS, 0x00), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_RXEQEVAL_TIME, 0x27), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG5, 0x02), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN, 0x2e), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1, 0x03), diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h index e3eb08776339..dfcecf31a606 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h @@ -12,6 +12,8 @@ #define QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE 0x01c #define QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS 0x090 #define QPHY_PCIE_V6_20_PCS_EQ_CONFIG1 0x0a0 +#define QPHY_PCIE_V6_20_PCS_G3_RXEQEVAL_TIME 0x0f0 +#define QPHY_PCIE_V6_20_PCS_G4_RXEQEVAL_TIME 0x0f4 #define QPHY_PCIE_V6_20_PCS_EQ_CONFIG5 0x108 #define QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN 0x15c #define QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1 0x17c diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h index 9c3f1e4950e6..4d9615cc0383 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h @@ -7,6 +7,7 @@ #define QCOM_PHY_QMP_PCS_V6_20_H_ /* Only for QMP V6_20 PHY - USB/PCIe PCS registers */ +#define QPHY_V6_20_PCS_G12S1_TXDEEMPH_M6DB 0x170 #define QPHY_V6_20_PCS_G3S2_PRE_GAIN 0x178 #define QPHY_V6_20_PCS_RX_SIGDET_LVL 0x190 #define QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL 0x1b8 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h index 6ed5339fd2ea..7bac5d5c6c34 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h @@ -23,6 +23,8 @@ #define QSERDES_V6_20_RX_DFE_1 0xac #define QSERDES_V6_20_RX_DFE_2 0xb0 #define QSERDES_V6_20_RX_DFE_3 0xb4 +#define QSERDES_V6_20_RX_TX_ADPT_CTRL 0xd4 +#define QSERDES_V6_20_VGA_CAL_CNTRL1 0xe0 #define QSERDES_V6_20_RX_VGA_CAL_MAN_VAL 0xe8 #define QSERDES_V6_20_RX_GM_CAL 0x10c #define QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4 0x120 From 80082fc89edde66fe61ab85d23ea27b245fe73cb Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 28 Dec 2023 13:42:37 +0800 Subject: [PATCH 112/814] phy: qcom: qmp-pcie: Update PCIe0 PHY settings for SM8550 Align PCIe0 PHY settings with SM8550 latest PCIe PHY Hardware Programming Guide. Signed-off-by: Qiang Yu Tested-by: Neil Armstrong # on SM8550-HDK Link: https://lore.kernel.org/r/1703742157-69840-3-git-send-email-quic_qianyu@quicinc.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 4 +++- drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index bdfdbcde55bf..af14af878d3e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -1891,7 +1891,7 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH2, 0x5b), QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH3, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH4, 0x89), - QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FO_GAIN, 0x09), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_GAIN, 0x05), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH1, 0x08), @@ -1911,6 +1911,8 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1, 0x1e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME, 0x27), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h index 91e70002eb47..0ca79333d942 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h @@ -7,6 +7,8 @@ #define QCOM_PHY_QMP_PCS_PCIE_V6_H_ /* Only for QMP V6 PHY - PCIE have different offsets than V5 */ +#define QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1 0xa4 +#define QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME 0xf4 #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2 0x0c #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4 0x14 #define QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20 From 982f92d5eea4e22e7c445ff5f508de1b63d8baba Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:35 +0200 Subject: [PATCH 113/814] phy: qcom: qmp-usb-legacy: drop single-lane support All PHYs supported by usb-legacy have two lanes. Drop support for single-lane configuration. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad DYbcio Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-1-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- .../phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c index cf466f6df94d..2f8891bc3da8 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -507,8 +507,6 @@ struct qmp_usb_legacy_offsets { /* 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 */ @@ -621,8 +619,6 @@ static const char * const qmp_phy_vreg_l[] = { }; 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, @@ -641,8 +637,6 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { }; 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, @@ -661,8 +655,6 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { }; 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, @@ -684,8 +676,6 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { }; 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, @@ -707,8 +697,6 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { }; 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, @@ -874,10 +862,8 @@ static int qmp_usb_legacy_power_on(struct phy *phy) 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_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); @@ -1231,20 +1217,15 @@ static int qmp_usb_legacy_parse_dt_legacy(struct qmp_usb *qmp, struct device_nod 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->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); - } + 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); if (IS_ERR(qmp->pcs_misc)) { dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); qmp->pcs_misc = NULL; From d3e7e79ccbaa643c264e3e626e05d2eeeba7399f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:36 +0200 Subject: [PATCH 114/814] phy: qcom: qmp-usb-legacy: drop qmp_usb_legacy_iomap All PHYs supported by qmp-usb-legacy driver don't have issues with the PCS region. Replace qmp_usb_legacy_iomap() with devm_of_iomap(). Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-2-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c index 2f8891bc3da8..5d7bb4f58af8 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -1166,27 +1166,11 @@ static int phy_pipe_clk_register(struct qmp_usb *qmp, struct device_node *np) 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)) @@ -1210,7 +1194,7 @@ static int qmp_usb_legacy_parse_dt_legacy(struct qmp_usb *qmp, struct device_nod if (IS_ERR(qmp->rx)) return PTR_ERR(qmp->rx); - qmp->pcs = qmp_usb_legacy_iomap(dev, np, 2, exclusive); + qmp->pcs = devm_of_iomap(dev, np, 2, NULL); if (IS_ERR(qmp->pcs)) return PTR_ERR(qmp->pcs); From 53d7776ea765ffd79f3ccfe627c2de3a0c7c2265 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:37 +0200 Subject: [PATCH 115/814] phy: qcom: qmp: move common functions to common header Move common init tables code to the common header phy-qcom-qmp-common.h. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-3-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 80 ++++--------------- drivers/phy/qualcomm/phy-qcom-qmp-common.h | 59 ++++++++++++++ .../phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 60 ++------------ drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 78 ++++-------------- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 65 +++------------ drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 62 ++------------ drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 64 ++------------- 7 files changed, 120 insertions(+), 348 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-common.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 1ad10110dd25..f6e9471da51a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -25,6 +25,8 @@ #include +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-usb-v4.h" @@ -72,30 +74,6 @@ #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 */ @@ -2031,55 +2009,29 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), }; -static void qmp_combo_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_combo_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_combo_configure_lane(base, tbl, num, 0xff); -} - static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *serdes = qmp->dp_serdes; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - qmp_combo_configure(serdes, cfg->dp_serdes_tbl, cfg->dp_serdes_tbl_num); + qmp_configure(serdes, cfg->dp_serdes_tbl, cfg->dp_serdes_tbl_num); switch (dp_opts->link_rate) { case 1620: - qmp_combo_configure(serdes, cfg->serdes_tbl_rbr, + qmp_configure(serdes, cfg->serdes_tbl_rbr, cfg->serdes_tbl_rbr_num); break; case 2700: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr, + qmp_configure(serdes, cfg->serdes_tbl_hbr, cfg->serdes_tbl_hbr_num); break; case 5400: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr2, + qmp_configure(serdes, cfg->serdes_tbl_hbr2, cfg->serdes_tbl_hbr2_num); break; case 8100: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr3, + qmp_configure(serdes, cfg->serdes_tbl_hbr3, cfg->serdes_tbl_hbr3_num); break; default: @@ -2681,8 +2633,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) qmp_combo_dp_serdes_init(qmp); - qmp_combo_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); - qmp_combo_configure_lane(tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); + qmp_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); + qmp_configure_lane(tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); /* Configure special DP tx tunings */ cfg->configure_dp_tx(qmp); @@ -2724,7 +2676,7 @@ static int qmp_combo_usb_power_on(struct phy *phy) unsigned int val; int ret; - qmp_combo_configure(serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); + qmp_configure(serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); ret = clk_prepare_enable(qmp->pipe_clk); if (ret) { @@ -2733,16 +2685,16 @@ static int qmp_combo_usb_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_combo_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_combo_configure_lane(tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_combo_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_combo_configure_lane(rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + qmp_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure_lane(rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - qmp_combo_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (pcs_usb) - qmp_combo_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); + qmp_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(10, 20); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-common.h b/drivers/phy/qualcomm/phy-qcom-qmp-common.h new file mode 100644 index 000000000000..799384210509 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-common.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_COMMON_H_ +#define QCOM_PHY_QMP_COMMON_H_ + +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, \ + } + +static inline void qmp_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 inline void qmp_configure(void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num) +{ + qmp_configure_lane(base, tbl, num, 0xff); +} + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index ab61a9c73b18..07c6f20a49d4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -19,6 +19,8 @@ #include #include +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" /* QPHY_SW_RESET bit */ @@ -39,30 +41,6 @@ #define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MAX 20 -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 { /* Common block control registers */ @@ -307,32 +285,6 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { .regs = pciephy_regs_layout, }; -static void qmp_pcie_msm8996_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_pcie_msm8996_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_pcie_msm8996_configure_lane(base, tbl, num, 0xff); -} - static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; @@ -344,7 +296,7 @@ static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy) unsigned int val; int ret; - qmp_pcie_msm8996_configure(serdes, serdes_tbl, serdes_tbl_num); + qmp_configure(serdes, serdes_tbl, serdes_tbl_num); qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET); qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL], @@ -487,9 +439,9 @@ static int qmp_pcie_msm8996_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_pcie_msm8996_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_pcie_msm8996_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_pcie_msm8996_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); /* * Pull out PHY from POWER DOWN state. diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index af14af878d3e..a4c8b6e9a7df 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -22,6 +22,8 @@ #include #include +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-pcie-v4.h" @@ -46,30 +48,6 @@ #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 */ @@ -3365,32 +3343,6 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x2_pciephy_cfg = { .has_nocsr_reset = true, }; -static void qmp_pcie_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_pcie_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_pcie_configure_lane(base, tbl, num, 0xff); -} - static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -3402,11 +3354,11 @@ static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_ tx4 = qmp->port_b + offs->tx2; rx4 = qmp->port_b + offs->rx2; - qmp_pcie_configure_lane(tx3, tbls->tx, tbls->tx_num, 1); - qmp_pcie_configure_lane(rx3, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(tx3, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(rx3, tbls->rx, tbls->rx_num, 1); - qmp_pcie_configure_lane(tx4, tbls->tx, tbls->tx_num, 2); - qmp_pcie_configure_lane(rx4, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(tx4, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(rx4, tbls->rx, tbls->rx_num, 2); } static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) @@ -3424,25 +3376,25 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c if (!tbls) return; - qmp_pcie_configure(serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(serdes, tbls->serdes, tbls->serdes_num); - qmp_pcie_configure_lane(tx, tbls->tx, tbls->tx_num, 1); - qmp_pcie_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(tx, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(rx, tbls->rx, tbls->rx_num, 1); if (cfg->lanes >= 2) { - qmp_pcie_configure_lane(tx2, tbls->tx, tbls->tx_num, 2); - qmp_pcie_configure_lane(rx2, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(tx2, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(rx2, tbls->rx, tbls->rx_num, 2); } - qmp_pcie_configure(pcs, tbls->pcs, tbls->pcs_num); - qmp_pcie_configure(pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num); + qmp_configure(pcs, tbls->pcs, tbls->pcs_num); + qmp_configure(pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num); if (cfg->lanes >= 4 && qmp->tcsr_4ln_config) { - qmp_pcie_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num); + qmp_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num); qmp_pcie_init_port_b(qmp, tbls); } - qmp_pcie_configure(ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num); + qmp_configure(ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num); } static int qmp_pcie_init(struct phy *phy) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 490f4cecf054..01a96c60c913 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -20,6 +20,9 @@ #include #include + +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-ufs-v2.h" #include "phy-qcom-qmp-pcs-ufs-v3.h" @@ -43,30 +46,6 @@ #define NUM_OVERLAY 2 -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 */ @@ -1483,37 +1462,11 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .regs = ufsphy_v6_regs_layout, }; -static void qmp_ufs_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_ufs_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_ufs_configure_lane(base, tbl, num, 0xff); -} - static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls) { void __iomem *serdes = qmp->serdes; - qmp_ufs_configure(serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(serdes, tbls->serdes, tbls->serdes_num); } static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls) @@ -1522,12 +1475,12 @@ static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbl void __iomem *tx = qmp->tx; void __iomem *rx = qmp->rx; - qmp_ufs_configure_lane(tx, tbls->tx, tbls->tx_num, 1); - qmp_ufs_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(tx, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(rx, tbls->rx, tbls->rx_num, 1); if (cfg->lanes >= 2) { - qmp_ufs_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); - qmp_ufs_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); } } @@ -1535,7 +1488,7 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls { void __iomem *pcs = qmp->pcs; - qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num); + qmp_configure(pcs, tbls->pcs, tbls->pcs_num); } static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index e62539ce99a6..a4d2bb3ae605 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -19,6 +19,8 @@ #include #include +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-misc-v4.h" @@ -64,30 +66,6 @@ #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 */ @@ -1631,32 +1609,6 @@ static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { .regs = qmp_v7_usb3phy_regs_layout, }; -static void qmp_usb_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_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_usb_configure_lane(base, tbl, num, 0xff); -} - static int qmp_usb_serdes_init(struct qmp_usb *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1664,7 +1616,7 @@ static int qmp_usb_serdes_init(struct qmp_usb *qmp) const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qmp_usb_configure(serdes, serdes_tbl, serdes_tbl_num); + qmp_configure(serdes, serdes_tbl, serdes_tbl_num); return 0; } @@ -1745,13 +1697,13 @@ static int qmp_usb_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_usb_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_usb_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_usb_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (pcs_usb) - qmp_usb_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); + qmp_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(10, 20); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 02babec76881..2de440f0bf02 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -23,6 +23,8 @@ #include #include +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" @@ -60,30 +62,6 @@ #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 */ @@ -511,32 +489,6 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; -static void qmp_usbc_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_usbc_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_usbc_configure_lane(base, tbl, num, 0xff); -} - static int qmp_usbc_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -609,7 +561,7 @@ static int qmp_usbc_power_on(struct phy *phy) unsigned int val; int ret; - qmp_usbc_configure(qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); + qmp_configure(qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); ret = clk_prepare_enable(qmp->pipe_clk); if (ret) { @@ -618,13 +570,13 @@ static int qmp_usbc_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_usbc_configure_lane(qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_usbc_configure_lane(qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure_lane(qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_usbc_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_usbc_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + qmp_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - qmp_usbc_configure(qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure(qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(10, 20); From ef643d55fdeb30299367e0e15ef47945f60d5a11 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:38 +0200 Subject: [PATCH 116/814] phy: qcom: qmp: split DP PHY registers to separate headers Split the DP PHY register definitions to separate headers, removing them from the global one. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-4-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-edp.c | 3 +- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 10 ++- drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h | 18 ++++ drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h | 21 +++++ drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h | 19 ++++ drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h | 13 +++ drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h | 13 +++ drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h | 62 +++++++++++++ .../phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 2 + drivers/phy/qualcomm/phy-qcom-qmp.h | 88 ------------------- 10 files changed, 159 insertions(+), 90 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 8e5078304646..9818d994c68b 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -21,7 +21,8 @@ #include -#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-qserdes-com-v4.h" /* EDP_PHY registers */ #define DP_PHY_CFG 0x0010 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index f6e9471da51a..bb961094e41a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -33,6 +33,14 @@ #include "phy-qcom-qmp-pcs-usb-v5.h" #include "phy-qcom-qmp-pcs-usb-v6.h" +#include "phy-qcom-qmp-dp-com-v3.h" + +#include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-dp-phy-v3.h" +#include "phy-qcom-qmp-dp-phy-v4.h" +#include "phy-qcom-qmp-dp-phy-v5.h" +#include "phy-qcom-qmp-dp-phy-v6.h" + /* QPHY_SW_RESET bit */ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ @@ -2322,7 +2330,7 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) u32 status; int ret; - writel(0x0f, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_CFG_1); + writel(0x0f, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG_1); qmp_combo_configure_dp_mode(qmp); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h new file mode 100644 index 000000000000..396179ef38b0 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_COM_V3_H_ +#define QCOM_PHY_QMP_DP_COM_V3_H_ + +/* Only for QMP V3 & V4 PHY - DP COM registers */ +#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 +#define QPHY_V3_DP_COM_SW_RESET 0x04 +#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 +#define QPHY_V3_DP_COM_SWI_CTRL 0x0c +#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 +#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 +#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h new file mode 100644 index 000000000000..00a9702abccd --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V3_H_ +#define QCOM_PHY_QMP_DP_PHY_V3_H_ + +/* Only for QMP V3 PHY - DP PHY registers */ +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c +#define QSERDES_V3_DP_PHY_AUX_BIST_CFG 0x050 + +#define QSERDES_V3_DP_PHY_VCO_DIV 0x064 +#define QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL 0x06c +#define QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL 0x088 + +#define QSERDES_V3_DP_PHY_SPARE0 0x0ac +#define QSERDES_V3_DP_PHY_STATUS 0x0c0 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h new file mode 100644 index 000000000000..ed6795e1257c --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V4_H_ +#define QCOM_PHY_QMP_DP_PHY_V4_H_ + +/* Only for QMP V4 PHY - DP PHY registers */ +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 +#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c +#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V4_DP_PHY_STATUS 0x0dc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h new file mode 100644 index 000000000000..f5cfacf9be96 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V5_H_ +#define QCOM_PHY_QMP_DP_PHY_V5_H_ + +/* Only for QMP V5 PHY - DP PHY registers */ +#define QSERDES_V5_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V5_DP_PHY_STATUS 0x0dc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h new file mode 100644 index 000000000000..01a20d3be4b8 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V6_H_ +#define QCOM_PHY_QMP_DP_PHY_V6_H_ + +/* Only for QMP V6 PHY - DP PHY registers */ +#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 +#define QSERDES_V6_DP_PHY_STATUS 0x0e4 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h new file mode 100644 index 000000000000..0ebd405bcaf0 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_H_ +#define QCOM_PHY_QMP_DP_PHY_H_ + +/* QMP PHY - DP PHY registers */ +#define QSERDES_DP_PHY_REVISION_ID0 0x000 +#define QSERDES_DP_PHY_REVISION_ID1 0x004 +#define QSERDES_DP_PHY_REVISION_ID2 0x008 +#define QSERDES_DP_PHY_REVISION_ID3 0x00c +#define QSERDES_DP_PHY_CFG 0x010 +#define QSERDES_DP_PHY_CFG_1 0x014 +#define QSERDES_DP_PHY_PD_CTL 0x018 +#define QSERDES_DP_PHY_MODE 0x01c +#define QSERDES_DP_PHY_AUX_CFG0 0x020 +#define QSERDES_DP_PHY_AUX_CFG1 0x024 +#define QSERDES_DP_PHY_AUX_CFG2 0x028 +#define QSERDES_DP_PHY_AUX_CFG3 0x02c +#define QSERDES_DP_PHY_AUX_CFG4 0x030 +#define QSERDES_DP_PHY_AUX_CFG5 0x034 +#define QSERDES_DP_PHY_AUX_CFG6 0x038 +#define QSERDES_DP_PHY_AUX_CFG7 0x03c +#define QSERDES_DP_PHY_AUX_CFG8 0x040 +#define QSERDES_DP_PHY_AUX_CFG9 0x044 + +/* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */ +# define QSERDES_V3_COM_BIAS_EN 0x0001 +# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 +# define QSERDES_V3_COM_CLKBUF_R_EN 0x0004 +# define QSERDES_V3_COM_CLKBUF_L_EN 0x0008 +# define QSERDES_V3_COM_EN_SYSCLK_TX_SEL 0x0010 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_L 0x0020 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_R 0x0040 + +/* QPHY_TX_TX_EMP_POST1_LVL bits */ +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN 0x0020 + +/* QPHY_TX_TX_DRV_LVL bits */ +# define DP_PHY_TXn_TX_DRV_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_DRV_LVL_MUX_EN 0x0020 + +/* QSERDES_DP_PHY_PD_CTL bits */ +# define DP_PHY_PD_CTL_PWRDN 0x001 +# define DP_PHY_PD_CTL_PSR_PWRDN 0x002 +# define DP_PHY_PD_CTL_AUX_PWRDN 0x004 +# define DP_PHY_PD_CTL_LANE_0_1_PWRDN 0x008 +# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 +# define DP_PHY_PD_CTL_PLL_PWRDN 0x020 +# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 + +/* QPHY_DP_PHY_AUX_INTERRUPT_STATUS bits */ +# define PHY_AUX_STOP_ERR_MASK 0x01 +# define PHY_AUX_DEC_ERR_MASK 0x02 +# define PHY_AUX_SYNC_ERR_MASK 0x04 +# define PHY_AUX_ALIGN_ERR_MASK 0x08 +# define PHY_AUX_REQ_ERR_MASK 0x10 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c index 5d7bb4f58af8..ca220878c630 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -25,6 +25,8 @@ #include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" +#include "phy-qcom-qmp-dp-com-v3.h" + /* QPHY_SW_RESET bit */ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 6923496cbfee..d6a9c9b5ea12 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -50,92 +50,4 @@ #include "phy-qcom-qmp-pcs-v7.h" -/* Only for QMP V3 & V4 PHY - DP COM registers */ -#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 -#define QPHY_V3_DP_COM_SW_RESET 0x04 -#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 -#define QPHY_V3_DP_COM_SWI_CTRL 0x0c -#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 -#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 -#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c - -/* QSERDES V3 COM bits */ -# define QSERDES_V3_COM_BIAS_EN 0x0001 -# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 -# define QSERDES_V3_COM_CLKBUF_R_EN 0x0004 -# define QSERDES_V3_COM_CLKBUF_L_EN 0x0008 -# define QSERDES_V3_COM_EN_SYSCLK_TX_SEL 0x0010 -# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_L 0x0020 -# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_R 0x0040 - -/* QSERDES V3 TX bits */ -# define DP_PHY_TXn_TX_EMP_POST1_LVL_MASK 0x001f -# define DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN 0x0020 -# define DP_PHY_TXn_TX_DRV_LVL_MASK 0x001f -# define DP_PHY_TXn_TX_DRV_LVL_MUX_EN 0x0020 - -/* QMP PHY - DP PHY registers */ -#define QSERDES_DP_PHY_REVISION_ID0 0x000 -#define QSERDES_DP_PHY_REVISION_ID1 0x004 -#define QSERDES_DP_PHY_REVISION_ID2 0x008 -#define QSERDES_DP_PHY_REVISION_ID3 0x00c -#define QSERDES_DP_PHY_CFG 0x010 -#define QSERDES_DP_PHY_PD_CTL 0x018 -# define DP_PHY_PD_CTL_PWRDN 0x001 -# define DP_PHY_PD_CTL_PSR_PWRDN 0x002 -# define DP_PHY_PD_CTL_AUX_PWRDN 0x004 -# define DP_PHY_PD_CTL_LANE_0_1_PWRDN 0x008 -# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 -# define DP_PHY_PD_CTL_PLL_PWRDN 0x020 -# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 -#define QSERDES_DP_PHY_MODE 0x01c -#define QSERDES_DP_PHY_AUX_CFG0 0x020 -#define QSERDES_DP_PHY_AUX_CFG1 0x024 -#define QSERDES_DP_PHY_AUX_CFG2 0x028 -#define QSERDES_DP_PHY_AUX_CFG3 0x02c -#define QSERDES_DP_PHY_AUX_CFG4 0x030 -#define QSERDES_DP_PHY_AUX_CFG5 0x034 -#define QSERDES_DP_PHY_AUX_CFG6 0x038 -#define QSERDES_DP_PHY_AUX_CFG7 0x03c -#define QSERDES_DP_PHY_AUX_CFG8 0x040 -#define QSERDES_DP_PHY_AUX_CFG9 0x044 - -/* Only for QMP V3 PHY - DP PHY registers */ -#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 -# define PHY_AUX_STOP_ERR_MASK 0x01 -# define PHY_AUX_DEC_ERR_MASK 0x02 -# define PHY_AUX_SYNC_ERR_MASK 0x04 -# define PHY_AUX_ALIGN_ERR_MASK 0x08 -# define PHY_AUX_REQ_ERR_MASK 0x10 - -#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c -#define QSERDES_V3_DP_PHY_AUX_BIST_CFG 0x050 - -#define QSERDES_V3_DP_PHY_VCO_DIV 0x064 -#define QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL 0x06c -#define QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL 0x088 - -#define QSERDES_V3_DP_PHY_SPARE0 0x0ac -#define DP_PHY_SPARE0_MASK 0x0f -#define DP_PHY_SPARE0_ORIENTATION_INFO_SHIFT 0x04(0x0004) - -#define QSERDES_V3_DP_PHY_STATUS 0x0c0 - -/* Only for QMP V4 PHY - DP PHY registers */ -#define QSERDES_V4_DP_PHY_CFG_1 0x014 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 -#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 -#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 -#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c -#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 -#define QSERDES_V4_DP_PHY_STATUS 0x0dc - -#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 - #endif From c01e03f97c4ea501fbd7dfe3eb7920a9a855e635 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:39 +0200 Subject: [PATCH 117/814] phy: qcom: qmp: move common bits definitions to common header Move bit definitions for the common headers to the common phy-qcom-qmp.h header. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-5-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 21 ----------- .../phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 10 +----- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 12 ------- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 7 ---- .../phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 21 ----------- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 35 ------------------- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 32 ----------------- drivers/phy/qualcomm/phy-qcom-qmp.h | 25 +++++++++++++ 8 files changed, 26 insertions(+), 137 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index bb961094e41a..b6908a03da58 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -41,16 +41,6 @@ #include "phy-qcom-qmp-dp-phy-v5.h" #include "phy-qcom-qmp-dp-phy-v6.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) @@ -65,17 +55,6 @@ #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 */ - /* QPHY_V3_DP_COM_TYPEC_CTRL register bits */ #define SW_PORTSELECT_VAL BIT(0) #define SW_PORTSELECT_MUX BIT(1) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index 07c6f20a49d4..0442b3120563 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -23,17 +23,9 @@ #include "phy-qcom-qmp.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) /* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) #define PLL_READY_GATE_EN BIT(3) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) + /* QPHY_COM_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index a4c8b6e9a7df..8836bb1ff0cc 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -34,18 +34,6 @@ #include "phy-qcom-qmp-pcs-pcie-v6_20.h" #include "phy-qcom-qmp-pcie-qhp.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) -#define PHYSTATUS_4_20 BIT(7) - #define PHY_INIT_COMPLETE_TIMEOUT 10000 /* set of registers with offsets different per-PHY */ diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 01a96c60c913..38c4a4cc670a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -32,13 +32,6 @@ #include "phy-qcom-qmp-qserdes-txrx-ufs-v6.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_READY_STATUS bit */ #define PCS_READY BIT(0) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c index ca220878c630..6d0ba39c1943 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -27,16 +27,6 @@ #include "phy-qcom-qmp-dp-com-v3.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) @@ -51,17 +41,6 @@ #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 { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index a4d2bb3ae605..6b6994cb77d7 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -29,41 +29,6 @@ #include "phy-qcom-qmp-pcs-usb-v6.h" #include "phy-qcom-qmp-pcs-usb-v7.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 /* set of registers with offsets different per-PHY */ diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 2de440f0bf02..d316a541f628 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -28,38 +28,6 @@ #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.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) - #define PHY_INIT_COMPLETE_TIMEOUT 10000 /* set of registers with offsets different per-PHY */ diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index d6a9c9b5ea12..d10b8f653c4b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -50,4 +50,29 @@ #include "phy-qcom-qmp-pcs-v7.h" +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) +#define REFCLK_DRV_DSBL BIT(1) /* PCIe */ + +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) + +/* QPHY_PCS_STATUS bit */ +#define PHYSTATUS BIT(6) +#define PHYSTATUS_4_20 BIT(7) + +/* 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_PCS_MISC_CLAMP_ENABLE register bits */ +#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ + #endif From fe3ec7600a16649812bf73f058e991429ccc28fb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:40 +0200 Subject: [PATCH 118/814] phy: qcom: qmp-usbc: drop has_pwrdn_delay handling None of the PHYs supported by the USBC driver need power down delay. Drop corresponding flag and code. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-6-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index d316a541f628..5cbc5fd529eb 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -315,9 +315,6 @@ struct qmp_phy_cfg { /* array of registers with different offsets */ const unsigned int *regs; - - /* true, if PHY needs delay after POWER_DOWN */ - bool has_pwrdn_delay; }; struct qmp_usbc { @@ -546,9 +543,6 @@ static int qmp_usbc_power_on(struct phy *phy) qmp_configure(qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); - if (cfg->has_pwrdn_delay) - usleep_range(10, 20); - /* Pull PHY out of reset state */ qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); From df71879bec89541e1cc8886c6d85ca4d5d61b422 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:41 +0200 Subject: [PATCH 119/814] phy: qcom: sgmii-eth: use existing register definitions The Qualcomm SGMII SerDes PHY is a QMP PHY. As such, it uses standard registers for QSERDES COM/RX/TX regions. Use register defines from the existing headers. Cc: Bartosz Golaszewski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-7-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 353 +++++++++------------- 1 file changed, 142 insertions(+), 211 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c index 03dc753f0de1..233f9b70c673 100644 --- a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +++ b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c @@ -11,83 +11,14 @@ #include #include +#include "phy-qcom-qmp-qserdes-com-v5.h" +#include "phy-qcom-qmp-qserdes-txrx-v5.h" + #define QSERDES_QMP_PLL 0x0 -#define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 (QSERDES_QMP_PLL + 0x1ac) -#define QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0 (QSERDES_QMP_PLL + 0x1b0) -#define QSERDES_COM_BIN_VCOCAL_HSCLK_SEL (QSERDES_QMP_PLL + 0x1bc) -#define QSERDES_COM_CORE_CLK_EN (QSERDES_QMP_PLL + 0x174) -#define QSERDES_COM_CORECLK_DIV_MODE0 (QSERDES_QMP_PLL + 0x168) -#define QSERDES_COM_CP_CTRL_MODE0 (QSERDES_QMP_PLL + 0x74) -#define QSERDES_COM_DEC_START_MODE0 (QSERDES_QMP_PLL + 0xbc) -#define QSERDES_COM_DIV_FRAC_START1_MODE0 (QSERDES_QMP_PLL + 0xcc) -#define QSERDES_COM_DIV_FRAC_START2_MODE0 (QSERDES_QMP_PLL + 0xd0) -#define QSERDES_COM_DIV_FRAC_START3_MODE0 (QSERDES_QMP_PLL + 0xd4) -#define QSERDES_COM_HSCLK_HS_SWITCH_SEL (QSERDES_QMP_PLL + 0x15c) -#define QSERDES_COM_HSCLK_SEL (QSERDES_QMP_PLL + 0x158) -#define QSERDES_COM_LOCK_CMP1_MODE0 (QSERDES_QMP_PLL + 0xac) -#define QSERDES_COM_LOCK_CMP2_MODE0 (QSERDES_QMP_PLL + 0xb0) -#define QSERDES_COM_PLL_CCTRL_MODE0 (QSERDES_QMP_PLL + 0x84) -#define QSERDES_COM_PLL_IVCO (QSERDES_QMP_PLL + 0x58) -#define QSERDES_COM_PLL_RCTRL_MODE0 (QSERDES_QMP_PLL + 0x7c) -#define QSERDES_COM_SYSCLK_EN_SEL (QSERDES_QMP_PLL + 0x94) -#define QSERDES_COM_VCO_TUNE1_MODE0 (QSERDES_QMP_PLL + 0x110) -#define QSERDES_COM_VCO_TUNE2_MODE0 (QSERDES_QMP_PLL + 0x114) -#define QSERDES_COM_VCO_TUNE_INITVAL2 (QSERDES_QMP_PLL + 0x124) -#define QSERDES_COM_C_READY_STATUS (QSERDES_QMP_PLL + 0x178) -#define QSERDES_COM_CMN_STATUS (QSERDES_QMP_PLL + 0x140) - #define QSERDES_RX 0x600 -#define QSERDES_RX_UCDR_FO_GAIN (QSERDES_RX + 0x8) -#define QSERDES_RX_UCDR_SO_GAIN (QSERDES_RX + 0x14) -#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN (QSERDES_RX + 0x30) -#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE (QSERDES_RX + 0x34) -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW (QSERDES_RX + 0x3c) -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH (QSERDES_RX + 0x40) -#define QSERDES_RX_UCDR_PI_CONTROLS (QSERDES_RX + 0x44) -#define QSERDES_RX_UCDR_PI_CTRL2 (QSERDES_RX + 0x48) -#define QSERDES_RX_RX_TERM_BW (QSERDES_RX + 0x80) -#define QSERDES_RX_VGA_CAL_CNTRL2 (QSERDES_RX + 0xd8) -#define QSERDES_RX_GM_CAL (QSERDES_RX + 0xdc) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 (QSERDES_RX + 0xe8) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 (QSERDES_RX + 0xec) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 (QSERDES_RX + 0xf0) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 (QSERDES_RX + 0xf4) -#define QSERDES_RX_RX_IDAC_TSETTLE_LOW (QSERDES_RX + 0xf8) -#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH (QSERDES_RX + 0xfc) -#define QSERDES_RX_RX_IDAC_MEASURE_TIME (QSERDES_RX + 0x100) -#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 (QSERDES_RX + 0x110) -#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 (QSERDES_RX + 0x114) -#define QSERDES_RX_SIGDET_CNTRL (QSERDES_RX + 0x11c) -#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL (QSERDES_RX + 0x124) -#define QSERDES_RX_RX_BAND (QSERDES_RX + 0x128) -#define QSERDES_RX_RX_MODE_00_LOW (QSERDES_RX + 0x15c) -#define QSERDES_RX_RX_MODE_00_HIGH (QSERDES_RX + 0x160) -#define QSERDES_RX_RX_MODE_00_HIGH2 (QSERDES_RX + 0x164) -#define QSERDES_RX_RX_MODE_00_HIGH3 (QSERDES_RX + 0x168) -#define QSERDES_RX_RX_MODE_00_HIGH4 (QSERDES_RX + 0x16c) -#define QSERDES_RX_RX_MODE_01_LOW (QSERDES_RX + 0x170) -#define QSERDES_RX_RX_MODE_01_HIGH (QSERDES_RX + 0x174) -#define QSERDES_RX_RX_MODE_01_HIGH2 (QSERDES_RX + 0x178) -#define QSERDES_RX_RX_MODE_01_HIGH3 (QSERDES_RX + 0x17c) -#define QSERDES_RX_RX_MODE_01_HIGH4 (QSERDES_RX + 0x180) -#define QSERDES_RX_RX_MODE_10_LOW (QSERDES_RX + 0x184) -#define QSERDES_RX_RX_MODE_10_HIGH (QSERDES_RX + 0x188) -#define QSERDES_RX_RX_MODE_10_HIGH2 (QSERDES_RX + 0x18c) -#define QSERDES_RX_RX_MODE_10_HIGH3 (QSERDES_RX + 0x190) -#define QSERDES_RX_RX_MODE_10_HIGH4 (QSERDES_RX + 0x194) -#define QSERDES_RX_DCC_CTRL1 (QSERDES_RX + 0x1a8) - #define QSERDES_TX 0x400 -#define QSERDES_TX_TX_BAND (QSERDES_TX + 0x24) -#define QSERDES_TX_SLEW_CNTL (QSERDES_TX + 0x28) -#define QSERDES_TX_RES_CODE_LANE_OFFSET_TX (QSERDES_TX + 0x3c) -#define QSERDES_TX_RES_CODE_LANE_OFFSET_RX (QSERDES_TX + 0x40) -#define QSERDES_TX_LANE_MODE_1 (QSERDES_TX + 0x84) -#define QSERDES_TX_LANE_MODE_3 (QSERDES_TX + 0x8c) -#define QSERDES_TX_RCV_DETECT_LVL_2 (QSERDES_TX + 0xa4) -#define QSERDES_TX_TRAN_DRVR_EMP_EN (QSERDES_TX + 0xc0) +#define QSERDES_PCS 0xc00 -#define QSERDES_PCS 0xC00 #define QSERDES_PCS_PHY_START (QSERDES_PCS + 0x0) #define QSERDES_PCS_POWER_DOWN_CONTROL (QSERDES_PCS + 0x4) #define QSERDES_PCS_SW_RESET (QSERDES_PCS + 0x8) @@ -115,77 +46,77 @@ static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap) regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); - regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F); - regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06); - regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); - regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); - regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x0A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x1A); - regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x82); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03); - regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0x24); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x82); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0x24); - regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02); - regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00); - regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x04); - regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00); - regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x0A); - regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x04); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); - regmap_write(regmap, QSERDES_TX_TX_BAND, 0x05); - regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x09); - regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05); - regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00); - regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12); - regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C); - regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80); - regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x04); - regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08); - regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20); - regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); - regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F); - regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); - regmap_write(regmap, QSERDES_RX_RX_BAND, 0x05); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7); - regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x05); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); @@ -203,77 +134,77 @@ static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap) regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); - regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F); - regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06); - regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); - regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); - regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x41); - regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x7A); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x20); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x01); - regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0xA1); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x41); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x7A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x20); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x01); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0xA1); - regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02); - regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00); - regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x03); - regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00); - regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x05); - regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x03); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x05); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); - regmap_write(regmap, QSERDES_TX_TX_BAND, 0x04); - regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x02); - regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05); - regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00); - regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12); - regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x04); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x02); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C); - regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80); - regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x00); - regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08); - regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20); - regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); - regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F); - regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); - regmap_write(regmap, QSERDES_RX_RX_BAND, 0x18); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0x18); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x0C); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7); - regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x18); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0x18); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x0C); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); @@ -313,7 +244,7 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_COM_C_READY_STATUS, + QSERDES_QMP_PLL + QSERDES_V5_COM_C_READY_STATUS, QSERDES_COM_C_READY)) { dev_err(dev, "QSERDES_COM_C_READY_STATUS timed-out"); return -ETIMEDOUT; @@ -334,7 +265,7 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_COM_CMN_STATUS, + QSERDES_QMP_PLL + QSERDES_V5_COM_CMN_STATUS, QSERDES_COM_C_PLL_LOCKED)) { dev_err(dev, "PLL Lock Status timed-out"); return -ETIMEDOUT; From 25ee21fc97db6cb7f476464e4aa8616652b3be49 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Jan 2024 01:22:42 +0200 Subject: [PATCH 120/814] phy: qcom: sgmii-eth: move PCS registers to separate header Follow the example of the rest of the QMP PHY drivers and move SGMII PCS registers to a separate header file. Cc: Bartosz Golaszewski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240126-phy-qmp-merge-common-v2-8-a463d0b57836@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h | 20 ++++++ drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 64 ++++++++----------- 2 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h new file mode 100644 index 000000000000..4d8c962f5e0f --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_PCS_SGMII_H_ +#define QCOM_PHY_QMP_PCS_SGMII_H_ + +#define QPHY_PCS_PHY_START 0x000 +#define QPHY_PCS_POWER_DOWN_CONTROL 0x004 +#define QPHY_PCS_SW_RESET 0x008 +#define QPHY_PCS_LINE_RESET_TIME 0x00c +#define QPHY_PCS_TX_LARGE_AMP_DRV_LVL 0x020 +#define QPHY_PCS_TX_SMALL_AMP_DRV_LVL 0x028 +#define QPHY_PCS_PCS_READY_STATUS 0x094 +#define QPHY_PCS_TX_MID_TERM_CTRL1 0x0d8 +#define QPHY_PCS_TX_MID_TERM_CTRL2 0x0dc +#define QPHY_PCS_SGMII_MISC_CTRL8 0x118 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c index 233f9b70c673..5b1c82459c12 100644 --- a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +++ b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c @@ -11,6 +11,7 @@ #include #include +#include "phy-qcom-qmp-pcs-sgmii.h" #include "phy-qcom-qmp-qserdes-com-v5.h" #include "phy-qcom-qmp-qserdes-txrx-v5.h" @@ -19,17 +20,6 @@ #define QSERDES_TX 0x400 #define QSERDES_PCS 0xc00 -#define QSERDES_PCS_PHY_START (QSERDES_PCS + 0x0) -#define QSERDES_PCS_POWER_DOWN_CONTROL (QSERDES_PCS + 0x4) -#define QSERDES_PCS_SW_RESET (QSERDES_PCS + 0x8) -#define QSERDES_PCS_LINE_RESET_TIME (QSERDES_PCS + 0xc) -#define QSERDES_PCS_TX_LARGE_AMP_DRV_LVL (QSERDES_PCS + 0x20) -#define QSERDES_PCS_TX_SMALL_AMP_DRV_LVL (QSERDES_PCS + 0x28) -#define QSERDES_PCS_TX_MID_TERM_CTRL1 (QSERDES_PCS + 0xd8) -#define QSERDES_PCS_TX_MID_TERM_CTRL2 (QSERDES_PCS + 0xdc) -#define QSERDES_PCS_SGMII_MISC_CTRL8 (QSERDES_PCS + 0x118) -#define QSERDES_PCS_PCS_READY_STATUS (QSERDES_PCS + 0x94) - #define QSERDES_COM_C_READY BIT(0) #define QSERDES_PCS_READY BIT(0) #define QSERDES_PCS_SGMIIPHY_READY BIT(7) @@ -43,8 +33,8 @@ struct qcom_dwmac_sgmii_phy_data { static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap) { - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); - regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01); regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); @@ -118,21 +108,21 @@ static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap) regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); - regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); - regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); - regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x0C); - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); - regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); } static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap) { - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); - regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01); regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); @@ -206,15 +196,15 @@ static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap) regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); - regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); - regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); - regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x8C); - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x8C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); - regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); } static inline int @@ -251,14 +241,14 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_PCS_PCS_READY_STATUS, + QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, QSERDES_PCS_READY)) { dev_err(dev, "PCS_READY timed-out"); return -ETIMEDOUT; } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_PCS_PCS_READY_STATUS, + QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, QSERDES_PCS_SGMIIPHY_READY)) { dev_err(dev, "SGMIIPHY_READY timed-out"); return -ETIMEDOUT; @@ -285,11 +275,11 @@ static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy) { struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); - regmap_write(data->regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x01); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); udelay(100); - regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x00); - regmap_write(data->regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); clk_disable_unprepare(data->refclk); From 517fd647359a0c635314cd23082e46b402f2f046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 23 Jan 2024 07:08:04 +0100 Subject: [PATCH 121/814] dt-bindings: interrupt-controller: convert MediaTek sysirq to the json-schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps validating DTS files. Signed-off-by: Rafał Miłecki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240123060804.32254-1-zajec5@gmail.com Signed-off-by: Rob Herring --- .../mediatek,mt6577-sysirq.yaml | 85 +++++++++++++++++++ .../interrupt-controller/mediatek,sysirq.txt | 44 ---------- 2 files changed, 85 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mediatek,mt6577-sysirq.yaml delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,mt6577-sysirq.yaml b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mt6577-sysirq.yaml new file mode 100644 index 000000000000..e1a379c052e4 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mt6577-sysirq.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mt6577-sysirq.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek sysirq + +description: + MediaTek SOCs sysirq support controllable irq inverter for each GIC SPI + interrupt. + +maintainers: + - Matthias Brugger + +properties: + compatible: + oneOf: + - const: mediatek,mt6577-sysirq + - items: + - enum: + - mediatek,mt2701-sysirq + - mediatek,mt2712-sysirq + - mediatek,mt6580-sysirq + - mediatek,mt6582-sysirq + - mediatek,mt6589-sysirq + - mediatek,mt6592-sysirq + - mediatek,mt6755-sysirq + - mediatek,mt6765-sysirq + - mediatek,mt6779-sysirq + - mediatek,mt6795-sysirq + - mediatek,mt6797-sysirq + - mediatek,mt7622-sysirq + - mediatek,mt7623-sysirq + - mediatek,mt7629-sysirq + - mediatek,mt8127-sysirq + - mediatek,mt8135-sysirq + - mediatek,mt8173-sysirq + - mediatek,mt8183-sysirq + - mediatek,mt8365-sysirq + - mediatek,mt8516-sysirq + - const: mediatek,mt6577-sysirq + + reg: + minItems: 1 + maxItems: 2 + + interrupt-controller: true + + "#interrupt-cells": + $ref: "arm,gic.yaml#/properties/#interrupt-cells" + +required: + - reg + - interrupt-controller + - "#interrupt-cells" + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + - if: + properties: + compatible: + contains: + const: mediatek,mt6797-sysirq + then: + properties: + reg: + minItems: 2 + else: + properties: + reg: + maxItems: 1 + +unevaluatedProperties: false + +examples: + - | + interrupt-controller@10200620 { + compatible = "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq"; + reg = <0x10220620 0x20>, + <0x10220690 0x10>; + interrupt-parent = <&gic>; + interrupt-controller; + #interrupt-cells = <3>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt deleted file mode 100644 index 3ffc60184e44..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt +++ /dev/null @@ -1,44 +0,0 @@ -MediaTek sysirq - -MediaTek SOCs sysirq support controllable irq inverter for each GIC SPI -interrupt. - -Required properties: -- compatible: should be - "mediatek,mt8516-sysirq", "mediatek,mt6577-sysirq": for MT8516 - "mediatek,mt8183-sysirq", "mediatek,mt6577-sysirq": for MT8183 - "mediatek,mt8173-sysirq", "mediatek,mt6577-sysirq": for MT8173 - "mediatek,mt8135-sysirq", "mediatek,mt6577-sysirq": for MT8135 - "mediatek,mt8127-sysirq", "mediatek,mt6577-sysirq": for MT8127 - "mediatek,mt7622-sysirq", "mediatek,mt6577-sysirq": for MT7622 - "mediatek,mt7623-sysirq", "mediatek,mt6577-sysirq": for MT7623 - "mediatek,mt7629-sysirq", "mediatek,mt6577-sysirq": for MT7629 - "mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795 - "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797 - "mediatek,mt6779-sysirq", "mediatek,mt6577-sysirq": for MT6779 - "mediatek,mt6765-sysirq", "mediatek,mt6577-sysirq": for MT6765 - "mediatek,mt6755-sysirq", "mediatek,mt6577-sysirq": for MT6755 - "mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq": for MT6592 - "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq": for MT6589 - "mediatek,mt6582-sysirq", "mediatek,mt6577-sysirq": for MT6582 - "mediatek,mt6580-sysirq", "mediatek,mt6577-sysirq": for MT6580 - "mediatek,mt6577-sysirq": for MT6577 - "mediatek,mt2712-sysirq", "mediatek,mt6577-sysirq": for MT2712 - "mediatek,mt2701-sysirq", "mediatek,mt6577-sysirq": for MT2701 - "mediatek,mt8365-sysirq", "mediatek,mt6577-sysirq": for MT8365 -- interrupt-controller : Identifies the node as an interrupt controller -- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt. -- reg: Physical base address of the intpol registers and length of memory - mapped region. Could be multiple bases here. Ex: mt6797 needs 2 reg, others - need 1. - -Example: - sysirq: intpol-controller@10200620 { - compatible = "mediatek,mt6797-sysirq", - "mediatek,mt6577-sysirq"; - interrupt-controller; - #interrupt-cells = <3>; - interrupt-parent = <&gic>; - reg = <0 0x10220620 0 0x20>, - <0 0x10220690 0 0x10>; - }; From 9c81ef43576e1721c442424abac48717da5e6266 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 29 Jan 2024 10:16:35 +0100 Subject: [PATCH 122/814] dt-bindings: input: document Goodix Berlin Touchscreen IC Document the Goodix GT9916 wich is part of the "Berlin" serie of Touchscreen controllers IC from Goodix. Reviewed-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240129-topic-goodix-berlin-upstream-initial-v15-1-6f7d096c0a0a@linaro.org Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/goodix,gt9916.yaml | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml b/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml new file mode 100644 index 000000000000..d90f045ac06c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/goodix,gt9916.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Goodix Berlin series touchscreen controller + +description: The Goodix Berlin series of touchscreen controllers + be connected to either I2C or SPI buses. + +maintainers: + - Neil Armstrong + +allOf: + - $ref: touchscreen.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - goodix,gt9916 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + avdd-supply: + description: Analog power supply regulator on AVDD pin + + vddio-supply: + description: power supply regulator on VDDIO pin + + spi-max-frequency: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-swapped-x-y: true + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - avdd-supply + - touchscreen-size-x + - touchscreen-size-y + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@5d { + compatible = "goodix,gt9916"; + reg = <0x5d>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + avdd-supply = <&ts_avdd>; + touchscreen-size-x = <1024>; + touchscreen-size-y = <768>; + }; + }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + num-cs = <1>; + cs-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; + touchscreen@0 { + compatible = "goodix,gt9916"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + avdd-supply = <&ts_avdd>; + spi-max-frequency = <1000000>; + touchscreen-size-x = <1024>; + touchscreen-size-y = <768>; + }; + }; + +... From 44362279bdd481b1b2aefb15e9fc54a2fcd846c1 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 29 Jan 2024 10:16:36 +0100 Subject: [PATCH 123/814] Input: add core support for Goodix Berlin Touchscreen IC Add initial support for the new Goodix "Berlin" touchscreen ICs. These touchscreen ICs support SPI, I2C and I3C interface, up to 10 finger touch, stylus and gestures events. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. Support for advanced features like: - Firmware & config update - Stylus events - Gestures events - Previous revisions support (BerlinA or BerlinB) is not included in current version. The current support will work with currently flashed firmware and config, and bail out if firmware or config aren't flashed yet. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Reviewed-by: Jeff LaBundy Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240129-topic-goodix-berlin-upstream-initial-v15-2-6f7d096c0a0a@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 3 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin.h | 24 + .../input/touchscreen/goodix_berlin_core.c | 755 ++++++++++++++++++ 4 files changed, 783 insertions(+) create mode 100644 drivers/input/touchscreen/goodix_berlin.h create mode 100644 drivers/input/touchscreen/goodix_berlin_core.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e3e2324547b9..950da599ae1a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -416,6 +416,9 @@ config TOUCHSCREEN_GOODIX To compile this driver as a module, choose M here: the module will be called goodix. +config TOUCHSCREEN_GOODIX_BERLIN_CORE + tristate + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 62bd24f3ac8e..2e2f3e70cd2c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h new file mode 100644 index 000000000000..1fd77eb69c9a --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Goodix Touchscreen Driver + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_berlin_berlin driver. + */ + +#ifndef __GOODIX_BERLIN_H_ +#define __GOODIX_BERLIN_H_ + +#include + +struct device; +struct input_id; +struct regmap; + +int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, + struct regmap *regmap); + +extern const struct dev_pm_ops goodix_berlin_pm_ops; + +#endif diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c new file mode 100644 index 000000000000..e7b41a926ef8 --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_core.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix "Berlin" Touchscreen IC driver + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + * + * This driver is distinct from goodix.c since hardware interface + * is different enough to require a new driver. + * None of the register address or data structure are close enough + * to the previous generations. + * + * Currently the driver only handles Multitouch events with already + * programmed firmware and "config" for "Revision D" Berlin IC. + * + * Support is missing for: + * - ESD Management + * - Firmware update/flashing + * - "Config" update/flashing + * - Stylus Events + * - Gesture Events + * - Support for older revisions (A & B) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "goodix_berlin.h" + +#define GOODIX_BERLIN_MAX_TOUCH 10 + +#define GOODIX_BERLIN_NORMAL_RESET_DELAY_MS 100 + +#define GOODIX_BERLIN_TOUCH_EVENT BIT(7) +#define GOODIX_BERLIN_REQUEST_EVENT BIT(6) +#define GOODIX_BERLIN_TOUCH_COUNT_MASK GENMASK(3, 0) + +#define GOODIX_BERLIN_REQUEST_CODE_RESET 3 + +#define GOODIX_BERLIN_POINT_TYPE_MASK GENMASK(3, 0) +#define GOODIX_BERLIN_POINT_TYPE_STYLUS_HOVER 1 +#define GOODIX_BERLIN_POINT_TYPE_STYLUS 3 + +#define GOODIX_BERLIN_TOUCH_ID_MASK GENMASK(7, 4) + +#define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA +#define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000 +#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR 0x10014 + +#define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K +#define GOODIX_BERLIN_IC_INFO_ADDR 0x10070 + +#define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16) + +struct goodix_berlin_fw_version { + u8 rom_pid[6]; + u8 rom_vid[3]; + u8 rom_vid_reserved; + u8 patch_pid[8]; + u8 patch_vid[4]; + u8 patch_vid_reserved; + u8 sensor_id; + u8 reserved[2]; + __le16 checksum; +}; + +struct goodix_berlin_ic_info_version { + u8 info_customer_id; + u8 info_version_id; + u8 ic_die_id; + u8 ic_version_id; + __le32 config_id; + u8 config_version; + u8 frame_data_customer_id; + u8 frame_data_version_id; + u8 touch_data_customer_id; + u8 touch_data_version_id; + u8 reserved[3]; +} __packed; + +struct goodix_berlin_ic_info_feature { + __le16 freqhop_feature; + __le16 calibration_feature; + __le16 gesture_feature; + __le16 side_touch_feature; + __le16 stylus_feature; +} __packed; + +struct goodix_berlin_ic_info_misc { + __le32 cmd_addr; + __le16 cmd_max_len; + __le32 cmd_reply_addr; + __le16 cmd_reply_len; + __le32 fw_state_addr; + __le16 fw_state_len; + __le32 fw_buffer_addr; + __le16 fw_buffer_max_len; + __le32 frame_data_addr; + __le16 frame_data_head_len; + __le16 fw_attr_len; + __le16 fw_log_len; + u8 pack_max_num; + u8 pack_compress_version; + __le16 stylus_struct_len; + __le16 mutual_struct_len; + __le16 self_struct_len; + __le16 noise_struct_len; + __le32 touch_data_addr; + __le16 touch_data_head_len; + __le16 point_struct_len; + __le16 reserved1; + __le16 reserved2; + __le32 mutual_rawdata_addr; + __le32 mutual_diffdata_addr; + __le32 mutual_refdata_addr; + __le32 self_rawdata_addr; + __le32 self_diffdata_addr; + __le32 self_refdata_addr; + __le32 iq_rawdata_addr; + __le32 iq_refdata_addr; + __le32 im_rawdata_addr; + __le16 im_readata_len; + __le32 noise_rawdata_addr; + __le16 noise_rawdata_len; + __le32 stylus_rawdata_addr; + __le16 stylus_rawdata_len; + __le32 noise_data_addr; + __le32 esd_addr; +} __packed; + +struct goodix_berlin_touch { + u8 status; + u8 reserved; + __le16 x; + __le16 y; + __le16 w; +}; +#define GOODIX_BERLIN_TOUCH_SIZE sizeof(struct goodix_berlin_touch) + +struct goodix_berlin_header { + u8 status; + u8 reserved1; + u8 request_type; + u8 reserved2[3]; + __le16 checksum; +}; +#define GOODIX_BERLIN_HEADER_SIZE sizeof(struct goodix_berlin_header) + +struct goodix_berlin_event { + struct goodix_berlin_header hdr; + /* The data below is u16/__le16 aligned */ + u8 data[GOODIX_BERLIN_TOUCH_SIZE * GOODIX_BERLIN_MAX_TOUCH + + GOODIX_BERLIN_CHECKSUM_SIZE]; +}; + +struct goodix_berlin_core { + struct device *dev; + struct regmap *regmap; + struct regulator *avdd; + struct regulator *iovdd; + struct gpio_desc *reset_gpio; + struct touchscreen_properties props; + struct goodix_berlin_fw_version fw_version; + struct input_dev *input_dev; + int irq; + + /* Runtime parameters extracted from IC_INFO buffer */ + u32 touch_data_addr; + + struct goodix_berlin_event event; +}; + +static bool goodix_berlin_checksum_valid(const u8 *data, int size) +{ + u32 cal_checksum = 0; + u16 r_checksum; + int i; + + if (size < GOODIX_BERLIN_CHECKSUM_SIZE) + return false; + + for (i = 0; i < size - GOODIX_BERLIN_CHECKSUM_SIZE; i++) + cal_checksum += data[i]; + + r_checksum = get_unaligned_le16(&data[i]); + + return (u16)cal_checksum == r_checksum; +} + +static bool goodix_berlin_is_dummy_data(struct goodix_berlin_core *cd, + const u8 *data, int size) +{ + int i; + + /* + * If the device is missing or doesn't respond the buffer + * could be filled with bus default line state, 0x00 or 0xff, + * so declare success the first time we encounter neither. + */ + for (i = 0; i < size; i++) + if (data[i] > 0 && data[i] < 0xff) + return false; + + return true; +} + +static int goodix_berlin_dev_confirm(struct goodix_berlin_core *cd) +{ + u8 tx_buf[8], rx_buf[8]; + int retry = 3; + int error; + + memset(tx_buf, GOODIX_BERLIN_DEV_CONFIRM_VAL, sizeof(tx_buf)); + while (retry--) { + error = regmap_raw_write(cd->regmap, + GOODIX_BERLIN_BOOTOPTION_ADDR, + tx_buf, sizeof(tx_buf)); + if (error) + return error; + + error = regmap_raw_read(cd->regmap, + GOODIX_BERLIN_BOOTOPTION_ADDR, + rx_buf, sizeof(rx_buf)); + if (error) + return error; + + if (!memcmp(tx_buf, rx_buf, sizeof(tx_buf))) + return 0; + + usleep_range(5000, 5100); + } + + dev_err(cd->dev, "device confirm failed, rx_buf: %*ph\n", + (int)sizeof(rx_buf), rx_buf); + + return -EINVAL; +} + +static int goodix_berlin_power_on(struct goodix_berlin_core *cd) +{ + int error; + + error = regulator_enable(cd->iovdd); + if (error) { + dev_err(cd->dev, "Failed to enable iovdd: %d\n", error); + return error; + } + + /* Vendor waits 3ms for IOVDD to settle */ + usleep_range(3000, 3100); + + error = regulator_enable(cd->avdd); + if (error) { + dev_err(cd->dev, "Failed to enable avdd: %d\n", error); + goto err_iovdd_disable; + } + + /* Vendor waits 15ms for IOVDD to settle */ + usleep_range(15000, 15100); + + gpiod_set_value_cansleep(cd->reset_gpio, 0); + + /* Vendor waits 4ms for Firmware to initialize */ + usleep_range(4000, 4100); + + error = goodix_berlin_dev_confirm(cd); + if (error) + goto err_dev_reset; + + /* Vendor waits 100ms for Firmware to fully boot */ + msleep(GOODIX_BERLIN_NORMAL_RESET_DELAY_MS); + + return 0; + +err_dev_reset: + gpiod_set_value_cansleep(cd->reset_gpio, 1); + regulator_disable(cd->avdd); +err_iovdd_disable: + regulator_disable(cd->iovdd); + return error; +} + +static void goodix_berlin_power_off(struct goodix_berlin_core *cd) +{ + gpiod_set_value_cansleep(cd->reset_gpio, 1); + regulator_disable(cd->avdd); + regulator_disable(cd->iovdd); +} + +static int goodix_berlin_read_version(struct goodix_berlin_core *cd) +{ + int error; + + error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_FW_VERSION_INFO_ADDR, + &cd->fw_version, sizeof(cd->fw_version)); + if (error) { + dev_err(cd->dev, "error reading fw version, %d\n", error); + return error; + } + + if (!goodix_berlin_checksum_valid((u8 *)&cd->fw_version, + sizeof(cd->fw_version))) { + dev_err(cd->dev, "invalid fw version: checksum error\n"); + return -EINVAL; + } + + return 0; +} + +/* Only extract necessary data for runtime */ +static int goodix_berlin_parse_ic_info(struct goodix_berlin_core *cd, + const u8 *data, u16 length) +{ + struct goodix_berlin_ic_info_misc *misc; + unsigned int offset = 0; + + offset += sizeof(__le16); /* length */ + offset += sizeof(struct goodix_berlin_ic_info_version); + offset += sizeof(struct goodix_berlin_ic_info_feature); + + /* IC_INFO Parameters, variable width structure */ + offset += 4 * sizeof(u8); /* drv_num, sen_num, button_num, force_num */ + if (offset >= length) + goto invalid_offset; + +#define ADVANCE_LE16_PARAMS() \ + do { \ + u8 param_num = data[offset++]; \ + offset += param_num * sizeof(__le16); \ + if (offset >= length) \ + goto invalid_offset; \ + } while (0) + ADVANCE_LE16_PARAMS(); /* active_scan_rate_num */ + ADVANCE_LE16_PARAMS(); /* mutual_freq_num*/ + ADVANCE_LE16_PARAMS(); /* self_tx_freq_num */ + ADVANCE_LE16_PARAMS(); /* self_rx_freq_num */ + ADVANCE_LE16_PARAMS(); /* stylus_freq_num */ +#undef ADVANCE_LE16_PARAMS + + misc = (struct goodix_berlin_ic_info_misc *)&data[offset]; + cd->touch_data_addr = le32_to_cpu(misc->touch_data_addr); + + return 0; + +invalid_offset: + dev_err(cd->dev, "ic_info length is invalid (offset %d length %d)\n", + offset, length); + return -EINVAL; +} + +static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd) +{ + u8 *afe_data __free(kfree) = NULL; + __le16 length_raw; + u16 length; + int error; + + afe_data = kzalloc(GOODIX_BERLIN_IC_INFO_MAX_LEN, GFP_KERNEL); + if (!afe_data) + return -ENOMEM; + + error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR, + &length_raw, sizeof(length_raw)); + if (error) { + dev_err(cd->dev, "failed get ic info length, %d\n", error); + return error; + } + + length = le16_to_cpu(length_raw); + if (length >= GOODIX_BERLIN_IC_INFO_MAX_LEN) { + dev_err(cd->dev, "invalid ic info length %d\n", length); + return -EINVAL; + } + + error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR, + afe_data, length); + if (error) { + dev_err(cd->dev, "failed get ic info data, %d\n", error); + return error; + } + + /* check whether the data is valid (ex. bus default values) */ + if (goodix_berlin_is_dummy_data(cd, afe_data, length)) { + dev_err(cd->dev, "fw info data invalid\n"); + return -EINVAL; + } + + if (!goodix_berlin_checksum_valid(afe_data, length)) { + dev_err(cd->dev, "fw info checksum error\n"); + return -EINVAL; + } + + error = goodix_berlin_parse_ic_info(cd, afe_data, length); + if (error) + return error; + + /* check some key info */ + if (!cd->touch_data_addr) { + dev_err(cd->dev, "touch_data_addr is null\n"); + return -EINVAL; + } + + return 0; +} + +static int goodix_berlin_get_remaining_contacts(struct goodix_berlin_core *cd, + int n) +{ + size_t offset = 2 * GOODIX_BERLIN_TOUCH_SIZE + + GOODIX_BERLIN_CHECKSUM_SIZE; + u32 addr = cd->touch_data_addr + GOODIX_BERLIN_HEADER_SIZE + offset; + int error; + + error = regmap_raw_read(cd->regmap, addr, + &cd->event.data[offset], + (n - 2) * GOODIX_BERLIN_TOUCH_SIZE); + if (error) { + dev_err_ratelimited(cd->dev, "failed to get touch data, %d\n", + error); + return error; + } + + return 0; +} + +static void goodix_berlin_report_state(struct goodix_berlin_core *cd, int n) +{ + struct goodix_berlin_touch *touch_data = + (struct goodix_berlin_touch *)cd->event.data; + struct goodix_berlin_touch *t; + int i; + u8 type, id; + + for (i = 0; i < n; i++) { + t = &touch_data[i]; + + type = FIELD_GET(GOODIX_BERLIN_POINT_TYPE_MASK, t->status); + if (type == GOODIX_BERLIN_POINT_TYPE_STYLUS || + type == GOODIX_BERLIN_POINT_TYPE_STYLUS_HOVER) { + dev_warn_once(cd->dev, "Stylus event type not handled\n"); + continue; + } + + id = FIELD_GET(GOODIX_BERLIN_TOUCH_ID_MASK, t->status); + if (id >= GOODIX_BERLIN_MAX_TOUCH) { + dev_warn_ratelimited(cd->dev, "invalid finger id %d\n", id); + continue; + } + + input_mt_slot(cd->input_dev, id); + input_mt_report_slot_state(cd->input_dev, MT_TOOL_FINGER, true); + + touchscreen_report_pos(cd->input_dev, &cd->props, + __le16_to_cpu(t->x), __le16_to_cpu(t->y), + true); + input_report_abs(cd->input_dev, ABS_MT_TOUCH_MAJOR, + __le16_to_cpu(t->w)); + } + + input_mt_sync_frame(cd->input_dev); + input_sync(cd->input_dev); +} + +static void goodix_berlin_touch_handler(struct goodix_berlin_core *cd) +{ + u8 touch_num; + int error; + + touch_num = FIELD_GET(GOODIX_BERLIN_TOUCH_COUNT_MASK, + cd->event.hdr.request_type); + if (touch_num > GOODIX_BERLIN_MAX_TOUCH) { + dev_warn(cd->dev, "invalid touch num %d\n", touch_num); + return; + } + + if (touch_num > 2) { + /* read additional contact data if more than 2 touch events */ + error = goodix_berlin_get_remaining_contacts(cd, touch_num); + if (error) + return; + } + + if (touch_num) { + int len = touch_num * GOODIX_BERLIN_TOUCH_SIZE + + GOODIX_BERLIN_CHECKSUM_SIZE; + if (!goodix_berlin_checksum_valid(cd->event.data, len)) { + dev_err(cd->dev, "touch data checksum error: %*ph\n", + len, cd->event.data); + return; + } + } + + goodix_berlin_report_state(cd, touch_num); +} + +static int goodix_berlin_request_handle_reset(struct goodix_berlin_core *cd) +{ + gpiod_set_value_cansleep(cd->reset_gpio, 1); + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cd->reset_gpio, 0); + + msleep(GOODIX_BERLIN_NORMAL_RESET_DELAY_MS); + + return 0; +} + +static irqreturn_t goodix_berlin_irq(int irq, void *data) +{ + struct goodix_berlin_core *cd = data; + int error; + + /* + * First, read buffer with space for 2 touch events: + * - GOODIX_BERLIN_HEADER_SIZE = 8 bytes + * - GOODIX_BERLIN_TOUCH_SIZE * 2 = 16 bytes + * - GOODIX_BERLIN_CHECKLSUM_SIZE = 2 bytes + * For a total of 26 bytes. + * + * If only a single finger is reported, we will read 8 bytes more than + * needed: + * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE) + * - bytes 8-15: Finger 0 Data + * - bytes 24-25: Checksum + * - bytes 18-25: Unused 8 bytes + * + * If 2 fingers are reported, we would have read the exact needed + * amount of data and checksum would be at the end of the buffer: + * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE) + * - bytes 8-15: Finger 0 Bytes 0-7 + * - bytes 16-23: Finger 1 Bytes 0-7 + * - bytes 24-25: Checksum + * + * If more than 2 fingers were reported, the "Checksum" bytes would + * in fact contain part of the next finger data, and then + * goodix_berlin_get_remaining_contacts() would complete the buffer + * with the missing bytes, including the trailing checksum. + * For example, if 3 fingers are reported, then we would do: + * Read 1: + * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE) + * - bytes 8-15: Finger 0 Bytes 0-7 + * - bytes 16-23: Finger 1 Bytes 0-7 + * - bytes 24-25: Finger 2 Bytes 0-1 + * Read 2 (with length of (3 - 2) * 8 = 8 bytes): + * - bytes 26-31: Finger 2 Bytes 2-7 + * - bytes 32-33: Checksum + */ + error = regmap_raw_read(cd->regmap, cd->touch_data_addr, + &cd->event, + GOODIX_BERLIN_HEADER_SIZE + + 2 * GOODIX_BERLIN_TOUCH_SIZE + + GOODIX_BERLIN_CHECKSUM_SIZE); + if (error) { + dev_warn_ratelimited(cd->dev, + "failed get event head data: %d\n", error); + goto out; + } + + if (cd->event.hdr.status == 0) + goto out; + + if (!goodix_berlin_checksum_valid((u8 *)&cd->event.hdr, + GOODIX_BERLIN_HEADER_SIZE)) { + dev_warn_ratelimited(cd->dev, + "touch head checksum error: %*ph\n", + (int)GOODIX_BERLIN_HEADER_SIZE, + &cd->event.hdr); + goto out_clear; + } + + if (cd->event.hdr.status & GOODIX_BERLIN_TOUCH_EVENT) + goodix_berlin_touch_handler(cd); + + if (cd->event.hdr.status & GOODIX_BERLIN_REQUEST_EVENT) { + switch (cd->event.hdr.request_type) { + case GOODIX_BERLIN_REQUEST_CODE_RESET: + if (cd->reset_gpio) + goodix_berlin_request_handle_reset(cd); + break; + + default: + dev_warn(cd->dev, "unsupported request code 0x%x\n", + cd->event.hdr.request_type); + } + } + + +out_clear: + /* Clear up status field */ + regmap_write(cd->regmap, cd->touch_data_addr, 0); + +out: + return IRQ_HANDLED; +} + +static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd, + const struct input_id *id) +{ + struct input_dev *input_dev; + int error; + + input_dev = devm_input_allocate_device(cd->dev); + if (!input_dev) + return -ENOMEM; + + cd->input_dev = input_dev; + input_set_drvdata(input_dev, cd); + + input_dev->name = "Goodix Berlin Capacitive TouchScreen"; + input_dev->phys = "input/ts"; + + input_dev->id = *id; + + input_set_abs_params(cd->input_dev, ABS_MT_POSITION_X, + 0, SZ_64K - 1, 0, 0); + input_set_abs_params(cd->input_dev, ABS_MT_POSITION_Y, + 0, SZ_64K - 1, 0, 0); + input_set_abs_params(cd->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + touchscreen_parse_properties(cd->input_dev, true, &cd->props); + + error = input_mt_init_slots(cd->input_dev, GOODIX_BERLIN_MAX_TOUCH, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + error = input_register_device(cd->input_dev); + if (error) + return error; + + return 0; +} + +static int goodix_berlin_suspend(struct device *dev) +{ + struct goodix_berlin_core *cd = dev_get_drvdata(dev); + + disable_irq(cd->irq); + goodix_berlin_power_off(cd); + + return 0; +} + +static int goodix_berlin_resume(struct device *dev) +{ + struct goodix_berlin_core *cd = dev_get_drvdata(dev); + int error; + + error = goodix_berlin_power_on(cd); + if (error) + return error; + + enable_irq(cd->irq); + + return 0; +} + +EXPORT_GPL_SIMPLE_DEV_PM_OPS(goodix_berlin_pm_ops, + goodix_berlin_suspend, goodix_berlin_resume); + +static void goodix_berlin_power_off_act(void *data) +{ + struct goodix_berlin_core *cd = data; + + goodix_berlin_power_off(cd); +} + +int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, + struct regmap *regmap) +{ + struct goodix_berlin_core *cd; + int error; + + if (irq <= 0) { + dev_err(dev, "Missing interrupt number\n"); + return -EINVAL; + } + + cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + cd->dev = dev; + cd->regmap = regmap; + cd->irq = irq; + + cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(cd->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(cd->reset_gpio), + "Failed to request reset gpio\n"); + + cd->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(cd->avdd)) + return dev_err_probe(dev, PTR_ERR(cd->avdd), + "Failed to request avdd regulator\n"); + + cd->iovdd = devm_regulator_get(dev, "iovdd"); + if (IS_ERR(cd->iovdd)) + return dev_err_probe(dev, PTR_ERR(cd->iovdd), + "Failed to request iovdd regulator\n"); + + error = goodix_berlin_power_on(cd); + if (error) { + dev_err(dev, "failed power on"); + return error; + } + + error = devm_add_action_or_reset(dev, goodix_berlin_power_off_act, cd); + if (error) + return error; + + error = goodix_berlin_read_version(cd); + if (error) { + dev_err(dev, "failed to get version info"); + return error; + } + + error = goodix_berlin_get_ic_info(cd); + if (error) { + dev_err(dev, "invalid ic info, abort"); + return error; + } + + error = goodix_berlin_input_dev_config(cd, id); + if (error) { + dev_err(dev, "failed set input device"); + return error; + } + + error = devm_request_threaded_irq(dev, cd->irq, NULL, goodix_berlin_irq, + IRQF_ONESHOT, "goodix-berlin", cd); + if (error) { + dev_err(dev, "request threaded irq failed: %d\n", error); + return error; + } + + dev_set_drvdata(dev, cd); + + dev_dbg(dev, "Goodix Berlin %s Touchscreen Controller", + cd->fw_version.patch_pid); + + return 0; +} +EXPORT_SYMBOL_GPL(goodix_berlin_probe); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin Core Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong "); From fba09e817c66f9731c71fe7cdd4556f7d989f1cb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 29 Jan 2024 10:16:37 +0100 Subject: [PATCH 124/814] Input: goodix-berlin - add I2C support for Goodix Berlin Touchscreen IC Add initial support for the new Goodix "Berlin" touchscreen ICs over the I2C interface. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Reviewed-by: Jeff LaBundy Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240129-topic-goodix-berlin-upstream-initial-v15-3-6f7d096c0a0a@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 14 ++++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin_i2c.c | 75 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 drivers/input/touchscreen/goodix_berlin_i2c.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 950da599ae1a..cc7b88118158 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -419,6 +419,20 @@ config TOUCHSCREEN_GOODIX config TOUCHSCREEN_GOODIX_BERLIN_CORE tristate +config TOUCHSCREEN_GOODIX_BERLIN_I2C + tristate "Goodix Berlin I2C touchscreen" + depends on I2C + select REGMAP_I2C + select TOUCHSCREEN_GOODIX_BERLIN_CORE + help + Say Y here if you have a Goodix Berlin IC connected to + your system via I2C. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called goodix_berlin_i2c. + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 2e2f3e70cd2c..7ef677cf7a10 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c new file mode 100644 index 000000000000..6ed9aa8088cb --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_i2c.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix Berlin Touchscreen Driver + * + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + */ +#include +#include +#include +#include +#include + +#include "goodix_berlin.h" + +#define I2C_MAX_TRANSFER_SIZE 256 + +static const struct regmap_config goodix_berlin_i2c_regmap_conf = { + .reg_bits = 32, + .val_bits = 8, + .max_raw_read = I2C_MAX_TRANSFER_SIZE, + .max_raw_write = I2C_MAX_TRANSFER_SIZE, +}; + +/* vendor & product left unassigned here, should probably be updated from fw info */ +static const struct input_id goodix_berlin_i2c_input_id = { + .bustype = BUS_I2C, +}; + +static int goodix_berlin_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + int error; + + regmap = devm_regmap_init_i2c(client, &goodix_berlin_i2c_regmap_conf); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + error = goodix_berlin_probe(&client->dev, client->irq, + &goodix_berlin_i2c_input_id, regmap); + if (error) + return error; + + return 0; +} + +static const struct i2c_device_id goodix_berlin_i2c_id[] = { + { "gt9916", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id); + +static const struct of_device_id goodix_berlin_i2c_of_match[] = { + { .compatible = "goodix,gt9916", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match); + +static struct i2c_driver goodix_berlin_i2c_driver = { + .driver = { + .name = "goodix-berlin-i2c", + .of_match_table = goodix_berlin_i2c_of_match, + .pm = pm_sleep_ptr(&goodix_berlin_pm_ops), + }, + .probe = goodix_berlin_i2c_probe, + .id_table = goodix_berlin_i2c_id, +}; +module_i2c_driver(goodix_berlin_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin I2C Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong "); From 3aa182bbc5b657329a8b85fa5303b8af0f461636 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 29 Jan 2024 10:16:38 +0100 Subject: [PATCH 125/814] Input: goodix-berlin - add SPI support for Goodix Berlin Touchscreen IC Add initial support for the new Goodix "Berlin" touchscreen ICs over the SPI interface. The driver doesn't use the regmap_spi code since the SPI messages needs to be prefixed, thus this custom regmap code. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Reviewed-by: Jeff LaBundy Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240129-topic-goodix-berlin-upstream-initial-v15-4-6f7d096c0a0a@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 14 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin_spi.c | 178 ++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 drivers/input/touchscreen/goodix_berlin_spi.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cc7b88118158..c821fe3ee794 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -433,6 +433,20 @@ config TOUCHSCREEN_GOODIX_BERLIN_I2C To compile this driver as a module, choose M here: the module will be called goodix_berlin_i2c. +config TOUCHSCREEN_GOODIX_BERLIN_SPI + tristate "Goodix Berlin SPI touchscreen" + depends on SPI_MASTER + select REGMAP + select TOUCHSCREEN_GOODIX_BERLIN_CORE + help + Say Y here if you have a Goodix Berlin IC connected to + your system via SPI. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called goodix_berlin_spi. + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7ef677cf7a10..a81cb5aa21a5 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c new file mode 100644 index 000000000000..4cc557da048a --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_spi.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix Berlin Touchscreen Driver + * + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + */ +#include +#include +#include +#include +#include +#include + +#include "goodix_berlin.h" + +#define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1 +#define GOODIX_BERLIN_REGISTER_WIDTH 4 +#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3 +#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ + GOODIX_BERLIN_REGISTER_WIDTH + \ + GOODIX_BERLIN_SPI_READ_DUMMY_LEN) +#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ + GOODIX_BERLIN_REGISTER_WIDTH) + +#define GOODIX_BERLIN_SPI_WRITE_FLAG 0xF0 +#define GOODIX_BERLIN_SPI_READ_FLAG 0xF1 + +static int goodix_berlin_spi_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + struct spi_device *spi = context; + struct spi_transfer xfers; + struct spi_message spi_msg; + const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */ + u8 *buf; + int error; + + if (reg_size != GOODIX_BERLIN_REGISTER_WIDTH) + return -EINVAL; + + buf = kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spi_message_init(&spi_msg); + memset(&xfers, 0, sizeof(xfers)); + + /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */ + buf[0] = GOODIX_BERLIN_SPI_READ_FLAG; + put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN); + memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH, + 0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN); + + xfers.tx_buf = buf; + xfers.rx_buf = buf; + xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size; + xfers.cs_change = 0; + spi_message_add_tail(&xfers, &spi_msg); + + error = spi_sync(spi, &spi_msg); + if (error < 0) + dev_err(&spi->dev, "spi transfer error, %d", error); + else + memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size); + + kfree(buf); + return error; +} + +static int goodix_berlin_spi_write(void *context, const void *data, + size_t count) +{ + unsigned int len = count - GOODIX_BERLIN_REGISTER_WIDTH; + struct spi_device *spi = context; + struct spi_transfer xfers; + struct spi_message spi_msg; + const u32 *reg = data; /* reg is stored as native u32 at start of buffer */ + u8 *buf; + int error; + + buf = kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spi_message_init(&spi_msg); + memset(&xfers, 0, sizeof(xfers)); + + buf[0] = GOODIX_BERLIN_SPI_WRITE_FLAG; + put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN); + memcpy(buf + GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN, + data + GOODIX_BERLIN_REGISTER_WIDTH, len); + + xfers.tx_buf = buf; + xfers.len = GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len; + xfers.cs_change = 0; + spi_message_add_tail(&xfers, &spi_msg); + + error = spi_sync(spi, &spi_msg); + if (error < 0) + dev_err(&spi->dev, "spi transfer error, %d", error); + + kfree(buf); + return error; +} + +static const struct regmap_config goodix_berlin_spi_regmap_conf = { + .reg_bits = 32, + .val_bits = 8, + .read = goodix_berlin_spi_read, + .write = goodix_berlin_spi_write, +}; + +/* vendor & product left unassigned here, should probably be updated from fw info */ +static const struct input_id goodix_berlin_spi_input_id = { + .bustype = BUS_SPI, +}; + +static int goodix_berlin_spi_probe(struct spi_device *spi) +{ + struct regmap_config regmap_config; + struct regmap *regmap; + size_t max_size; + int error = 0; + + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + error = spi_setup(spi); + if (error) + return error; + + max_size = spi_max_transfer_size(spi); + + regmap_config = goodix_berlin_spi_regmap_conf; + regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN; + regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN; + + regmap = devm_regmap_init(&spi->dev, NULL, spi, ®map_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + error = goodix_berlin_probe(&spi->dev, spi->irq, + &goodix_berlin_spi_input_id, regmap); + if (error) + return error; + + return 0; +} + +static const struct spi_device_id goodix_berlin_spi_ids[] = { + { "gt9916" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids); + +static const struct of_device_id goodix_berlin_spi_of_match[] = { + { .compatible = "goodix,gt9916", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match); + +static struct spi_driver goodix_berlin_spi_driver = { + .driver = { + .name = "goodix-berlin-spi", + .of_match_table = goodix_berlin_spi_of_match, + .pm = pm_sleep_ptr(&goodix_berlin_pm_ops), + }, + .probe = goodix_berlin_spi_probe, + .id_table = goodix_berlin_spi_ids, +}; +module_spi_driver(goodix_berlin_spi_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin SPI Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong "); From 5eb7fcbdea63fc91685ac0c89ceb42d3becc96d2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:21 -0800 Subject: [PATCH 126/814] KVM: x86/pmu: Always treat Fixed counters as available when supported Treat fixed counters as available when they are supported, i.e. don't silently ignore an enabled fixed counter just because guest CPUID says the associated general purpose architectural event is unavailable. KVM originally treated fixed counters as always available, but that got changed as part of a fix to avoid confusing REF_CPU_CYCLES, which does NOT map to an architectural event, with the actual architectural event used associated with bit 7, TOPDOWN_SLOTS. The commit justified the change with: If the event is marked as unavailable in the Intel guest CPUID 0AH.EBX leaf, we need to avoid any perf_event creation, whether it's a gp or fixed counter. but that justification doesn't mesh with reality. The Intel SDM uses "architectural events" to refer to both general purpose events (the ones with the reverse polarity mask in CPUID.0xA.EBX) and the events for fixed counters, e.g. the SDM makes statements like: Each of the fixed-function PMC can count only one architectural performance event. but the fact that fixed counter 2 (TSC reference cycles) doesn't have an associated general purpose architectural makes trying to apply the mask from CPUID.0xA.EBX impossible. Furthermore, the lack of enumeration for an architectural event in CPUID only means the CPU doesn't officially support the architectural encoding, i.e. it doesn't mean using the architectural encoding _won't_ work, it sipmly means there are no guarantees that it will work as expected. E.g. if KVM is running in a VM that advertises a fixed counters but not the corresponding architectural event encoding, and perf decides to use a general purpose counter instead of a fixed counter, odds are very good that the underlying hardware actually does support the architectrual encoding, and that programming the encoding will count the right thing. In other words, asking perf to count the event will probably work, whereas intentionally doing nothing is obviously guaranteed to fail. Note, at the time of the change, KVM didn't enforce hardware support, i.e. didn't prevent userspace from enumerating support in guest CPUID.0xA.EBX for architectural events that aren't supported in hardware. I.e. silently dropping the fixed counter didn't somehow protection against counting the wrong event, it just enforced guest CPUID. And practically speaking, this issue is almost certainly limited to running KVM on a funky virtual CPU model. No known real hardware has an asymmetric PMU where a fixed counter is supported but the associated architectural event is not. Fixes: a21864486f7e ("KVM: x86/pmu: Fix available_event_types check for REF_CPU_CYCLES event") Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index a6216c874729..8207f8c03585 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -108,11 +108,24 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc) u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8; int i; + /* + * Fixed counters are always available if KVM reaches this point. If a + * fixed counter is unsupported in hardware or guest CPUID, KVM doesn't + * allow the counter's corresponding MSR to be written. KVM does use + * architectural events to program fixed counters, as the interface to + * perf doesn't allow requesting a specific fixed counter, e.g. perf + * may (sadly) back a guest fixed PMC with a general purposed counter. + * But if _hardware_ doesn't support the associated event, KVM simply + * doesn't enumerate support for the fixed counter. + */ + if (pmc_is_fixed(pmc)) + return true; + BUILD_BUG_ON(ARRAY_SIZE(intel_arch_events) != NR_INTEL_ARCH_EVENTS); /* * Disallow events reported as unavailable in guest CPUID. Note, this - * doesn't apply to pseudo-architectural events. + * doesn't apply to pseudo-architectural events (see above). */ for (i = 0; i < NR_REAL_INTEL_ARCH_EVENTS; i++) { if (intel_arch_events[i].eventsel != event_select || From cbbd1aa891398e9ddbdd05bc4e40a988175f22af Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:22 -0800 Subject: [PATCH 127/814] KVM: x86/pmu: Allow programming events that match unsupported arch events Remove KVM's bogus restriction that the guest can't program an event whose encoding matches an unsupported architectural event. The enumeration of an architectural event only says that if a CPU supports an architectural event, then the event can be programmed using the architectural encoding. The enumeration does NOT say anything about the encoding when the CPU doesn't report support the architectural event. Preventing the guest from counting events whose encoding happens to match an architectural event breaks existing functionality whenever Intel adds an architectural encoding that was *ever* used for a CPU that doesn't enumerate support for the architectural event, even if the encoding is for the exact same event! E.g. the architectural encoding for Top-Down Slots is 0x01a4. Broadwell CPUs, which do not support the Top-Down Slots architectural event, 0x01a4 is a valid, model-specific event. Denying guest usage of 0x01a4 if/when KVM adds support for Top-Down slots would break any Broadwell-based guest. Reported-by: Kan Liang Closes: https://lore.kernel.org/all/2004baa6-b494-462c-a11f-8104ea152c6a@linux.intel.com Fixes: a21864486f7e ("KVM: x86/pmu: Fix available_event_types check for REF_CPU_CYCLES event") Reviewed-by: Dapeng Mi Reviewed-by: Jim Mattson Reviewed-by: Kan Liang Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 - arch/x86/kvm/pmu.c | 1 - arch/x86/kvm/pmu.h | 1 - arch/x86/kvm/svm/pmu.c | 6 ---- arch/x86/kvm/vmx/pmu_intel.c | 38 -------------------------- 5 files changed, 47 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index 058bc636356a..d7eebee4450c 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -12,7 +12,6 @@ BUILD_BUG_ON(1) * a NULL definition, for example if "static_call_cond()" will be used * at the call sites. */ -KVM_X86_PMU_OP(hw_event_available) KVM_X86_PMU_OP(pmc_idx_to_pmc) KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) KVM_X86_PMU_OP(msr_idx_to_pmc) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 87cc6c8809ad..30945fea6988 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -441,7 +441,6 @@ 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); } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 7caeb3d8d4fd..87ecf22f5b25 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -19,7 +19,6 @@ #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 struct kvm_pmu_ops { - bool (*hw_event_available)(struct kvm_pmc *pmc); struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx); struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index b6a7ad4d6914..1475d47c821c 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -73,11 +73,6 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, return amd_pmc_idx_to_pmc(pmu, idx); } -static bool amd_hw_event_available(struct kvm_pmc *pmc) -{ - return true; -} - static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -233,7 +228,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu) } struct kvm_pmu_ops amd_pmu_ops __initdata = { - .hw_event_available = amd_hw_event_available, .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = amd_msr_idx_to_pmc, diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 8207f8c03585..1a7d021a6c7b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -101,43 +101,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) } } -static bool intel_hw_event_available(struct kvm_pmc *pmc) -{ - struct kvm_pmu *pmu = pmc_to_pmu(pmc); - u8 event_select = pmc->eventsel & ARCH_PERFMON_EVENTSEL_EVENT; - u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8; - int i; - - /* - * Fixed counters are always available if KVM reaches this point. If a - * fixed counter is unsupported in hardware or guest CPUID, KVM doesn't - * allow the counter's corresponding MSR to be written. KVM does use - * architectural events to program fixed counters, as the interface to - * perf doesn't allow requesting a specific fixed counter, e.g. perf - * may (sadly) back a guest fixed PMC with a general purposed counter. - * But if _hardware_ doesn't support the associated event, KVM simply - * doesn't enumerate support for the fixed counter. - */ - if (pmc_is_fixed(pmc)) - return true; - - BUILD_BUG_ON(ARRAY_SIZE(intel_arch_events) != NR_INTEL_ARCH_EVENTS); - - /* - * Disallow events reported as unavailable in guest CPUID. Note, this - * doesn't apply to pseudo-architectural events (see above). - */ - 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; - - return pmu->available_event_types & BIT(i); - } - - return true; -} - static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -780,7 +743,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) } struct kvm_pmu_ops intel_pmu_ops __initdata = { - .hw_event_available = intel_hw_event_available, .pmc_idx_to_pmc = intel_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = intel_msr_idx_to_pmc, From db9e008a0f37bd31ac3d77d650812612b7c873da Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:23 -0800 Subject: [PATCH 128/814] KVM: x86/pmu: Remove KVM's enumeration of Intel's architectural encodings Drop KVM's enumeration of Intel's architectural event encodings, and instead open code the three encodings (of which only two are real) that KVM uses to emulate fixed counters. Now that KVM doesn't incorrectly enforce the availability of architectural encodings, there is no reason for KVM to ever care about the encodings themselves, at least not in the current format of an array indexed by the encoding's position in CPUID. Opportunistically add a comment to explain why KVM cares about eventsel values for fixed counters. Suggested-by: Jim Mattson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 72 ++++++++++++------------------------ 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 1a7d021a6c7b..f3c44ddc09f8 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -22,52 +22,6 @@ #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[] = { - [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[] = { - [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) { struct kvm_pmc *pmc; @@ -440,8 +394,29 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } +/* + * Map fixed counter events to architectural general purpose event encodings. + * Perf doesn't provide APIs to allow KVM to directly program a fixed counter, + * and so KVM instead programs the architectural event to effectively request + * the fixed counter. Perf isn't guaranteed to use a fixed counter and may + * instead program the encoding into a general purpose counter, e.g. if a + * different perf_event is already utilizing the requested counter, but the end + * result is the same (ignoring the fact that using a general purpose counter + * will likely exacerbate counter contention). + * + * Note, reference cycles is counted using a perf-defined "psuedo-encoding", + * as there is no architectural general purpose encoding for reference cycles. + */ static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu) { + const struct { + u8 eventsel; + u8 unit_mask; + } fixed_pmc_events[] = { + [0] = { 0xc0, 0x00 }, /* Instruction Retired / PERF_COUNT_HW_INSTRUCTIONS. */ + [1] = { 0x3c, 0x00 }, /* CPU Cycles/ PERF_COUNT_HW_CPU_CYCLES. */ + [2] = { 0x00, 0x03 }, /* Reference Cycles / PERF_COUNT_HW_REF_CPU_CYCLES*/ + }; int i; BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_events) != KVM_PMC_MAX_FIXED); @@ -449,10 +424,9 @@ static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu) for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { 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; + pmc->eventsel = (fixed_pmc_events[index].unit_mask << 8) | + fixed_pmc_events[index].eventsel; } } From 61bb2ad795a72a7a75add3ffc257660fd6c7cfea Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:24 -0800 Subject: [PATCH 129/814] KVM: x86/pmu: Setup fixed counters' eventsel during PMU initialization Set the eventsel for all fixed counters during PMU initialization, the eventsel is hardcoded and consumed if and only if the counter is supported, i.e. there is no reason to redo the setup every time the PMU is refreshed. Configuring all KVM-supported fixed counter also eliminates a potential pitfall if/when KVM supports discontiguous fixed counters, in which case configuring only nr_arch_fixed_counters will be insufficient (ignoring the fact that KVM will need many other changes to support discontiguous fixed counters). Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index f3c44ddc09f8..98e92b9ece09 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -407,27 +407,21 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * Note, reference cycles is counted using a perf-defined "psuedo-encoding", * as there is no architectural general purpose encoding for reference cycles. */ -static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu) +static u64 intel_get_fixed_pmc_eventsel(int index) { const struct { - u8 eventsel; + u8 event; u8 unit_mask; } fixed_pmc_events[] = { [0] = { 0xc0, 0x00 }, /* Instruction Retired / PERF_COUNT_HW_INSTRUCTIONS. */ [1] = { 0x3c, 0x00 }, /* CPU Cycles/ PERF_COUNT_HW_CPU_CYCLES. */ [2] = { 0x00, 0x03 }, /* Reference Cycles / PERF_COUNT_HW_REF_CPU_CYCLES*/ }; - int i; BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_events) != KVM_PMC_MAX_FIXED); - for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { - int index = array_index_nospec(i, KVM_PMC_MAX_FIXED); - struct kvm_pmc *pmc = &pmu->fixed_counters[index]; - - pmc->eventsel = (fixed_pmc_events[index].unit_mask << 8) | - fixed_pmc_events[index].eventsel; - } + return (fixed_pmc_events[index].unit_mask << 8) | + fixed_pmc_events[index].event; } static void intel_pmu_refresh(struct kvm_vcpu *vcpu) @@ -493,7 +487,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.bit_width_fixed); pmu->counter_bitmask[KVM_PMC_FIXED] = ((u64)1 << edx.split.bit_width_fixed) - 1; - setup_fixed_pmc_eventsel(pmu); } for (i = 0; i < pmu->nr_arch_fixed_counters; i++) @@ -571,6 +564,7 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) pmu->fixed_counters[i].vcpu = vcpu; pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED; pmu->fixed_counters[i].current_config = 0; + pmu->fixed_counters[i].eventsel = intel_get_fixed_pmc_eventsel(i); } lbr_desc->records.nr = 0; From 7a277c22412cf72cf6376f21c6d826e8f4a44cc3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:25 -0800 Subject: [PATCH 130/814] KVM: x86/pmu: Get eventsel for fixed counters from perf Get the event selectors used to effectively request fixed counters for perf events from perf itself instead of hardcoding them in KVM and hoping that they match the underlying hardware. While fixed counters 0 and 1 use architectural events, as of ffbe4ab0beda ("perf/x86/intel: Extend the ref-cycles event to GP counters") fixed counter 2 (reference TSC cycles) may use a software-defined pseudo-encoding or a real hardware-defined encoding. Reported-by: Kan Liang Closes: https://lkml.kernel.org/r/4281eee7-6423-4ec8-bb18-c6aeee1faf2c%40linux.intel.com Reviewed-by: Kan Liang Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 98e92b9ece09..ec4feaef3d55 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -404,24 +404,28 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * result is the same (ignoring the fact that using a general purpose counter * will likely exacerbate counter contention). * - * Note, reference cycles is counted using a perf-defined "psuedo-encoding", - * as there is no architectural general purpose encoding for reference cycles. + * Forcibly inlined to allow asserting on @index at build time, and there should + * never be more than one user. */ -static u64 intel_get_fixed_pmc_eventsel(int index) +static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index) { - const struct { - u8 event; - u8 unit_mask; - } fixed_pmc_events[] = { - [0] = { 0xc0, 0x00 }, /* Instruction Retired / PERF_COUNT_HW_INSTRUCTIONS. */ - [1] = { 0x3c, 0x00 }, /* CPU Cycles/ PERF_COUNT_HW_CPU_CYCLES. */ - [2] = { 0x00, 0x03 }, /* Reference Cycles / PERF_COUNT_HW_REF_CPU_CYCLES*/ + const enum perf_hw_id fixed_pmc_perf_ids[] = { + [0] = PERF_COUNT_HW_INSTRUCTIONS, + [1] = PERF_COUNT_HW_CPU_CYCLES, + [2] = PERF_COUNT_HW_REF_CPU_CYCLES, }; + u64 eventsel; - BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_events) != KVM_PMC_MAX_FIXED); + BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_PMC_MAX_FIXED); + BUILD_BUG_ON(index >= KVM_PMC_MAX_FIXED); - return (fixed_pmc_events[index].unit_mask << 8) | - fixed_pmc_events[index].event; + /* + * Yell if perf reports support for a fixed counter but perf doesn't + * have a known encoding for the associated general purpose event. + */ + eventsel = perf_get_hw_event_config(fixed_pmc_perf_ids[index]); + WARN_ON_ONCE(!eventsel && index < kvm_pmu_cap.num_counters_fixed); + return eventsel; } static void intel_pmu_refresh(struct kvm_vcpu *vcpu) From ecb490770ad42c7d3dc08f06efe7bf0779990745 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:26 -0800 Subject: [PATCH 131/814] KVM: x86/pmu: Don't ignore bits 31:30 for RDPMC index on AMD Stop stripping bits 31:30 prior to validating/consuming the RDPMC index on AMD. Per the APM's documentation of RDPMC, *values* greater than 27 are reserved. The behavior of upper bits being flags is firmly Intel-only. Fixes: ca724305a2b0 ("KVM: x86/vPMU: Implement AMD vPMU code for KVM") Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/pmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 1475d47c821c..1fafc46f61c9 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -77,8 +77,6 @@ static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - idx &= ~(3u << 30); - return idx < pmu->nr_arch_gp_counters; } @@ -86,7 +84,7 @@ static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { - return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx & ~(3u << 30)); + return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx); } static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) From 7bb7fce13601d2e6818be500ef3ce0b60cd59603 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:27 -0800 Subject: [PATCH 132/814] KVM: x86/pmu: Prioritize VMX interception over #GP on RDPMC due to bad index Apply the pre-intercepts RDPMC validity check only to AMD, and rename all relevant functions to make it as clear as possible that the check is not a standard PMC index check. On Intel, the basic rule is that only invalid opcodes and privilege/permission/mode checks have priority over VM-Exit, i.e. RDPMC with an invalid index should VM-Exit, not #GP. While the SDM doesn't explicitly call out RDPMC, it _does_ explicitly use RDMSR of a non-existent MSR as an example where VM-Exit has priority over #GP, and RDPMC is effectively just a variation of RDMSR. Manually testing on various Intel CPUs confirms this behavior, and the inverted priority was introduced for SVM compatibility, i.e. was not an intentional change for Intel PMUs. On AMD, *all* exceptions on RDPMC have priority over VM-Exit. Check for a NULL kvm_pmu_ops.check_rdpmc_early instead of using a RET0 static call so as to provide a convenient location to document the difference between Intel and AMD, and to again try to make it as obvious as possible that the early check is a one-off thing, not a generic "is this PMC valid?" helper. Fixes: 8061252ee0d2 ("KVM: SVM: Add intercept checks for remaining twobyte instructions") Cc: Jim Mattson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 2 +- arch/x86/kvm/emulate.c | 2 +- arch/x86/kvm/kvm_emulate.h | 2 +- arch/x86/kvm/pmu.c | 16 +++++++++++++--- arch/x86/kvm/pmu.h | 4 ++-- arch/x86/kvm/svm/pmu.c | 9 ++++++--- arch/x86/kvm/vmx/pmu_intel.c | 12 ------------ arch/x86/kvm/x86.c | 9 +++------ 8 files changed, 27 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index d7eebee4450c..f0cd48222133 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -15,7 +15,7 @@ BUILD_BUG_ON(1) KVM_X86_PMU_OP(pmc_idx_to_pmc) KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) KVM_X86_PMU_OP(msr_idx_to_pmc) -KVM_X86_PMU_OP(is_valid_rdpmc_ecx) +KVM_X86_PMU_OP_OPTIONAL(check_rdpmc_early) KVM_X86_PMU_OP(is_valid_msr) KVM_X86_PMU_OP(get_msr) KVM_X86_PMU_OP(set_msr) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e223043ef5b2..695ab5b6055c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3962,7 +3962,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) * protected mode. */ if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || - ctxt->ops->check_pmc(ctxt, rcx)) + ctxt->ops->check_rdpmc_early(ctxt, rcx)) return emulate_gp(ctxt, 0); return X86EMUL_CONTINUE; diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index e6d149825169..4351149484fb 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -208,7 +208,7 @@ struct x86_emulate_ops { int (*set_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data); int (*get_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); - int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc); + int (*check_rdpmc_early)(struct x86_emulate_ctxt *ctxt, u32 pmc); int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata); void (*halt)(struct x86_emulate_ctxt *ctxt); void (*wbinvd)(struct x86_emulate_ctxt *ctxt); diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 30945fea6988..0b0d804ee239 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -524,10 +524,20 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) kvm_pmu_cleanup(vcpu); } -/* check if idx is a valid index to access PMU */ -bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) +int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) { - return static_call(kvm_x86_pmu_is_valid_rdpmc_ecx)(vcpu, idx); + /* + * On Intel, VMX interception has priority over RDPMC exceptions that + * aren't already handled by the emulator, i.e. there are no additional + * check needed for Intel PMUs. + * + * On AMD, _all_ exceptions on RDPMC have priority over SVM intercepts, + * i.e. an invalid PMC results in a #GP, not #VMEXIT. + */ + if (!kvm_pmu_ops.check_rdpmc_early) + return 0; + + return static_call(kvm_x86_pmu_check_rdpmc_early)(vcpu, idx); } bool is_vmware_backdoor_pmc(u32 pmc_idx) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 87ecf22f5b25..51bbb01b21c8 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -23,7 +23,7 @@ struct kvm_pmu_ops { struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr); - bool (*is_valid_rdpmc_ecx)(struct kvm_vcpu *vcpu, unsigned int idx); + int (*check_rdpmc_early)(struct kvm_vcpu *vcpu, unsigned int idx); bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr); int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); @@ -215,7 +215,7 @@ static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc) void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); -bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx); +int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx); bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 1fafc46f61c9..e886300f0f97 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -73,11 +73,14 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, return amd_pmc_idx_to_pmc(pmu, idx); } -static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) +static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - return idx < pmu->nr_arch_gp_counters; + if (idx >= pmu->nr_arch_gp_counters) + return -EINVAL; + + return 0; } /* idx is the ECX register of RDPMC instruction */ @@ -229,7 +232,7 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = { .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = amd_msr_idx_to_pmc, - .is_valid_rdpmc_ecx = amd_is_valid_rdpmc_ecx, + .check_rdpmc_early = amd_check_rdpmc_early, .is_valid_msr = amd_is_valid_msr, .get_msr = amd_pmu_get_msr, .set_msr = amd_pmu_set_msr, diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index ec4feaef3d55..1b1f888ad32b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -55,17 +55,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) } } -static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) -{ - struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - bool fixed = idx & (1u << 30); - - idx &= ~(3u << 30); - - return fixed ? idx < pmu->nr_arch_fixed_counters - : idx < pmu->nr_arch_gp_counters; -} - static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { @@ -718,7 +707,6 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = { .pmc_idx_to_pmc = intel_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = intel_msr_idx_to_pmc, - .is_valid_rdpmc_ecx = intel_is_valid_rdpmc_ecx, .is_valid_msr = intel_is_valid_msr, .get_msr = intel_pmu_get_msr, .set_msr = intel_pmu_set_msr, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 363b1c080205..cbee277254f0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8389,12 +8389,9 @@ static int emulator_get_msr(struct x86_emulate_ctxt *ctxt, return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata); } -static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt, - u32 pmc) +static int emulator_check_rdpmc_early(struct x86_emulate_ctxt *ctxt, u32 pmc) { - if (kvm_pmu_is_valid_rdpmc_ecx(emul_to_vcpu(ctxt), pmc)) - return 0; - return -EINVAL; + return kvm_pmu_check_rdpmc_early(emul_to_vcpu(ctxt), pmc); } static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt, @@ -8526,7 +8523,7 @@ static const struct x86_emulate_ops emulate_ops = { .set_msr_with_filter = emulator_set_msr_with_filter, .get_msr_with_filter = emulator_get_msr_with_filter, .get_msr = emulator_get_msr, - .check_pmc = emulator_check_pmc, + .check_rdpmc_early = emulator_check_rdpmc_early, .read_pmc = emulator_read_pmc, .halt = emulator_halt, .wbinvd = emulator_wbinvd, From d652981db08fe2db185e00ad9cd41871f49807b0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:28 -0800 Subject: [PATCH 133/814] KVM: x86/pmu: Apply "fast" RDPMC only to Intel PMUs Move the handling of "fast" RDPMC instructions, which drop bits 63:32 of the count, to Intel. The "fast" flag, and all modifiers for that matter, are Intel-only and aren't supported by AMD. Opportunistically replace open coded bit crud with proper #defines, and add comments to try and disentangle the flags vs. values mess for non-architectural vs. architectural PMUs. Fixes: ca724305a2b0 ("KVM: x86/vPMU: Implement AMD vPMU code for KVM") Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 3 +-- arch/x86/kvm/vmx/pmu_intel.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 0b0d804ee239..09b0feb975c3 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -576,10 +576,9 @@ static int kvm_pmu_rdpmc_vmware(struct kvm_vcpu *vcpu, unsigned idx, u64 *data) int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data) { - bool fast_mode = idx & (1u << 31); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); struct kvm_pmc *pmc; - u64 mask = fast_mode ? ~0u : ~0ull; + u64 mask = ~0ull; if (!pmu->version) return 1; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 1b1f888ad32b..03bd188b5754 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -20,6 +20,15 @@ #include "nested.h" #include "pmu.h" +/* + * Perf's "BASE" is wildly misleading, architectural PMUs use bits 31:16 of ECX + * to encode the "type" of counter to read, i.e. this is not a "base". And to + * further confuse things, non-architectural PMUs use bit 31 as a flag for + * "fast" reads, whereas the "type" is an explicit value. + */ +#define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE +#define INTEL_RDPMC_FAST BIT(31) + #define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0) static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) @@ -59,11 +68,14 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - bool fixed = idx & (1u << 30); + bool fixed = idx & INTEL_RDPMC_FIXED; struct kvm_pmc *counters; unsigned int num_counters; - idx &= ~(3u << 30); + if (idx & INTEL_RDPMC_FAST) + *mask &= GENMASK_ULL(31, 0); + + idx &= ~(INTEL_RDPMC_FIXED | INTEL_RDPMC_FAST); if (fixed) { counters = pmu->fixed_counters; num_counters = pmu->nr_arch_fixed_counters; From 5728a4a0ea79e2f2e650db4793170900e57359a7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:29 -0800 Subject: [PATCH 134/814] KVM: x86/pmu: Disallow "fast" RDPMC for architectural Intel PMUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inject #GP on RDPMC if the "fast" flag is set for architectural Intel PMUs, i.e. if the PMU version is non-zero. Per Intel's SDM, and confirmed on bare metal, the "fast" flag is supported only for non-architectural PMUs, and is reserved for architectural PMUs. If the processor does not support architectural performance monitoring (CPUID.0AH:EAX[7:0]=0), ECX[30:0] specifies the index of the PMC to be read. Setting ECX[31] selects “fast” read mode if supported. In this mode, RDPMC returns bits 31:0 of the PMC in EAX while clearing EDX to zero. If the processor does support architectural performance monitoring (CPUID.0AH:EAX[7:0] ≠ 0), ECX[31:16] specifies type of PMC while ECX[15:0] specifies the index of the PMC to be read within that type. The following PMC types are currently defined: — General-purpose counters use type 0. The index x (to read IA32_PMCx) must be less than the value enumerated by CPUID.0AH.EAX[15:8] (thus ECX[15:8] must be zero). — Fixed-function counters use type 4000H. The index x (to read IA32_FIXED_CTRx) can be used if either CPUID.0AH.EDX[4:0] > x or CPUID.0AH.ECX[x] = 1 (thus ECX[15:5] must be 0). — Performance metrics use type 2000H. This type can be used only if IA32_PERF_CAPABILITIES.PERF_METRICS_AVAILABLE[bit 15]=1. For this type, the index in ECX[15:0] is implementation specific. Opportunistically WARN if KVM ever actually tries to complete RDPMC for a non-architectural PMU, and drop the non-existent "support" for fast RDPMC, as KVM doesn't support such PMUs, i.e. kvm_pmu_rdpmc() should reject the RDPMC before getting to the Intel code. Fixes: f5132b01386b ("KVM: Expose a version 2 architectural PMU to a guests") Fixes: 67f4d4288c35 ("KVM: x86: rdpmc emulation checks the counter incorrectly") Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 03bd188b5754..5a5dfae6055c 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -27,7 +27,6 @@ * "fast" reads, whereas the "type" is an explicit value. */ #define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE -#define INTEL_RDPMC_FAST BIT(31) #define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0) @@ -72,10 +71,25 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, struct kvm_pmc *counters; unsigned int num_counters; - if (idx & INTEL_RDPMC_FAST) - *mask &= GENMASK_ULL(31, 0); + /* + * The encoding of ECX for RDPMC is different for architectural versus + * non-architecturals PMUs (PMUs with version '0'). For architectural + * PMUs, bits 31:16 specify the PMC type and bits 15:0 specify the PMC + * index. For non-architectural PMUs, bit 31 is a "fast" flag, and + * bits 30:0 specify the PMC index. + * + * Yell and reject attempts to read PMCs for a non-architectural PMU, + * as KVM doesn't support such PMUs. + */ + if (WARN_ON_ONCE(!pmu->version)) + return NULL; - idx &= ~(INTEL_RDPMC_FIXED | INTEL_RDPMC_FAST); + /* + * Fixed PMCs are supported on all architectural PMUs. Note, KVM only + * emulates fixed PMCs for PMU v2+, but the flag itself is still valid, + * i.e. let RDPMC fail due to accessing a non-existent counter. + */ + idx &= ~INTEL_RDPMC_FIXED; if (fixed) { counters = pmu->fixed_counters; num_counters = pmu->nr_arch_fixed_counters; From 7a0fc734c20dd1ad9bc1b8b922b61616f31d3823 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:30 -0800 Subject: [PATCH 135/814] KVM: x86/pmu: Treat "fixed" PMU type in RDPMC as index as a value, not flag Refactor KVM's handling of ECX for RDPMC to treat the FIXED modifier as an explicit value, not a flag (minus one wart). While non-architectural PMUs do use bit 31 as a flag (for "fast" reads), architectural PMUs use the upper half of ECX to encode the type. From the SDM: ECX[31:16] specifies type of PMC while ECX[15:0] specifies the index of the PMC to be read within that type Note, that the known supported types are 4000H and 2000H, i.e. look a lot like flags, doesn't contradict the above statement that ECX[31:16] holds the type, at least not by any sane reading of the SDM. Keep the explicitly clearing of the FIXED "flag", as KVM subtly relies on that behavior to disallow unsupported types while allowing the correct indices for fixed counters. This wart will be cleaned up in short order. Opportunistically grab the per-type bitmask in the if-else blocks to eliminate the one-off usage of the local "fixed" bool. Reported-by: Jim Mattson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 5a5dfae6055c..c37dd3aa056b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -28,6 +28,9 @@ */ #define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE +#define INTEL_RDPMC_TYPE_MASK GENMASK(31, 16) +#define INTEL_RDPMC_INDEX_MASK GENMASK(15, 0) + #define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0) static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) @@ -66,10 +69,11 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { + unsigned int type = idx & INTEL_RDPMC_TYPE_MASK; struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - bool fixed = idx & INTEL_RDPMC_FIXED; struct kvm_pmc *counters; unsigned int num_counters; + u64 bitmask; /* * The encoding of ECX for RDPMC is different for architectural versus @@ -90,16 +94,20 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, * i.e. let RDPMC fail due to accessing a non-existent counter. */ idx &= ~INTEL_RDPMC_FIXED; - if (fixed) { + if (type == INTEL_RDPMC_FIXED) { counters = pmu->fixed_counters; num_counters = pmu->nr_arch_fixed_counters; + bitmask = pmu->counter_bitmask[KVM_PMC_FIXED]; } else { counters = pmu->gp_counters; num_counters = pmu->nr_arch_gp_counters; + bitmask = pmu->counter_bitmask[KVM_PMC_GP]; } + if (idx >= num_counters) return NULL; - *mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP]; + + *mask &= bitmask; return &counters[array_index_nospec(idx, num_counters)]; } From a634c76b2c1a642d11f5d6e1810181daedcbe0ab Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:31 -0800 Subject: [PATCH 136/814] KVM: x86/pmu: Explicitly check for RDPMC of unsupported Intel PMC types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly check for attempts to read unsupported PMC types instead of letting the bounds check fail. Functionally, letting the check fail is ok, but it's unnecessarily subtle and does a poor job of documenting the architectural behavior that KVM is emulating. Reviewed-by: Dapeng Mi  Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-12-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index c37dd3aa056b..b41bdb0a0995 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -26,6 +26,7 @@ * further confuse things, non-architectural PMUs use bit 31 as a flag for * "fast" reads, whereas the "type" is an explicit value. */ +#define INTEL_RDPMC_GP 0 #define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE #define INTEL_RDPMC_TYPE_MASK GENMASK(31, 16) @@ -89,21 +90,29 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, return NULL; /* - * Fixed PMCs are supported on all architectural PMUs. Note, KVM only - * emulates fixed PMCs for PMU v2+, but the flag itself is still valid, - * i.e. let RDPMC fail due to accessing a non-existent counter. + * General Purpose (GP) PMCs are supported on all PMUs, and fixed PMCs + * are supported on all architectural PMUs, i.e. on all virtual PMUs + * supported by KVM. Note, KVM only emulates fixed PMCs for PMU v2+, + * but the type itself is still valid, i.e. let RDPMC fail due to + * accessing a non-existent counter. Reject attempts to read all other + * types, which are unknown/unsupported. */ - idx &= ~INTEL_RDPMC_FIXED; - if (type == INTEL_RDPMC_FIXED) { + switch (type) { + case INTEL_RDPMC_FIXED: counters = pmu->fixed_counters; num_counters = pmu->nr_arch_fixed_counters; bitmask = pmu->counter_bitmask[KVM_PMC_FIXED]; - } else { + break; + case INTEL_RDPMC_GP: counters = pmu->gp_counters; num_counters = pmu->nr_arch_gp_counters; bitmask = pmu->counter_bitmask[KVM_PMC_GP]; + break; + default: + return NULL; } + idx &= INTEL_RDPMC_INDEX_MASK; if (idx >= num_counters) return NULL; From d7e68738e1aae940b54bfc03313e0ef5720e2e71 Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:32 -0800 Subject: [PATCH 137/814] KVM: selftests: Add vcpu_set_cpuid_property() to set properties Add vcpu_set_cpuid_property() helper function for setting properties, and use it instead of open coding an equivalent for MAX_PHY_ADDR. Future vPMU testcases will also need to stuff various CPUID properties. Reviewed-by: Jim Mattson Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-13-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 4 +++- .../testing/selftests/kvm/lib/x86_64/processor.c | 15 ++++++++++++--- .../x86_64/smaller_maxphyaddr_emulation_test.c | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a84863503fcb..932944c4ea01 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -995,7 +995,9 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); } -void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr); +void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_property property, + uint32_t value); void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function); void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index d8288374078e..67eb82a6c754 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -752,12 +752,21 @@ void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid) vcpu_set_cpuid(vcpu); } -void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr) +void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_property property, + uint32_t value) { - struct kvm_cpuid_entry2 *entry = vcpu_get_cpuid_entry(vcpu, 0x80000008); + struct kvm_cpuid_entry2 *entry; + + entry = __vcpu_get_cpuid_entry(vcpu, property.function, property.index); + + (&entry->eax)[property.reg] &= ~GENMASK(property.hi_bit, property.lo_bit); + (&entry->eax)[property.reg] |= value << property.lo_bit; - entry->eax = (entry->eax & ~0xff) | maxphyaddr; vcpu_set_cpuid(vcpu); + + /* Sanity check that @value doesn't exceed the bounds in any way. */ + TEST_ASSERT_EQ(kvm_cpuid_property(vcpu->cpuid, property), value); } void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function) diff --git a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c index 06edf00a97d6..9b89440dff19 100644 --- a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c +++ b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vcpu_set_cpuid_maxphyaddr(vcpu, MAXPHYADDR); + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_MAX_PHY_ADDR, MAXPHYADDR); rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); From ff76d771251003b28aeac2051cfe72384dff232f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:33 -0800 Subject: [PATCH 138/814] KVM: selftests: Drop the "name" param from KVM_X86_PMU_FEATURE() Drop the "name" parameter from KVM_X86_PMU_FEATURE(), it's unused and the name is redundant with the macro, i.e. it's truly useless. Reviewed-by: Jim Mattson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-14-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/x86_64/processor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 932944c4ea01..4f737d3b893c 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -290,7 +290,7 @@ struct kvm_x86_cpu_property { struct kvm_x86_pmu_feature { struct kvm_x86_cpu_feature anti_feature; }; -#define KVM_X86_PMU_FEATURE(name, __bit) \ +#define KVM_X86_PMU_FEATURE(__bit) \ ({ \ struct kvm_x86_pmu_feature feature = { \ .anti_feature = KVM_X86_CPU_FEATURE(0xa, 0, EBX, __bit), \ @@ -299,7 +299,7 @@ struct kvm_x86_pmu_feature { feature; \ }) -#define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED KVM_X86_PMU_FEATURE(BRANCH_INSNS_RETIRED, 5) +#define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED KVM_X86_PMU_FEATURE(5) static inline unsigned int x86_family(unsigned int eax) { From 370d536322896cc9ad59eb8849ad8e1f9e985953 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:34 -0800 Subject: [PATCH 139/814] KVM: selftests: Extend {kvm,this}_pmu_has() to support fixed counters Extend the kvm_x86_pmu_feature framework to allow querying for fixed counters via {kvm,this}_pmu_has(). Like architectural events, checking for a fixed counter annoyingly requires checking multiple CPUID fields, as a fixed counter exists if: FxCtr[i]_is_supported := ECX[i] || (EDX[4:0] > i); Note, KVM currently doesn't actually support exposing fixed counters via the bitmask, but that will hopefully change sooner than later, and Intel's SDM explicitly "recommends" checking both the number of counters and the mask. Rename the intermedate "anti_feature" field to simply 'f' since the fixed counter bitmask (thankfully) doesn't have reversed polarity like the architectural events bitmask. Note, ideally the helpers would use BUILD_BUG_ON() to assert on the incoming register, but the expected usage in PMU tests can't guarantee the inputs are compile-time constants. Opportunistically define macros for all of the known architectural events and fixed counters. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-15-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 4f737d3b893c..92d4f8ecc730 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -282,24 +282,41 @@ struct kvm_x86_cpu_property { * that indicates the feature is _not_ supported, and a property that states * the length of the bit mask of unsupported features. A feature is supported * if the size of the bit mask is larger than the "unavailable" bit, and said - * bit is not set. + * bit is not set. Fixed counters also bizarre enumeration, but inverted from + * arch events for general purpose counters. Fixed counters are supported if a + * feature flag is set **OR** the total number of fixed counters is greater + * than index of the counter. * - * Wrap the "unavailable" feature to simplify checking whether or not a given - * architectural event is supported. + * Wrap the events for general purpose and fixed counters to simplify checking + * whether or not a given architectural event is supported. */ struct kvm_x86_pmu_feature { - struct kvm_x86_cpu_feature anti_feature; + struct kvm_x86_cpu_feature f; }; -#define KVM_X86_PMU_FEATURE(__bit) \ -({ \ - struct kvm_x86_pmu_feature feature = { \ - .anti_feature = KVM_X86_CPU_FEATURE(0xa, 0, EBX, __bit), \ - }; \ - \ - feature; \ +#define KVM_X86_PMU_FEATURE(__reg, __bit) \ +({ \ + struct kvm_x86_pmu_feature feature = { \ + .f = KVM_X86_CPU_FEATURE(0xa, 0, __reg, __bit), \ + }; \ + \ + kvm_static_assert(KVM_CPUID_##__reg == KVM_CPUID_EBX || \ + KVM_CPUID_##__reg == KVM_CPUID_ECX); \ + feature; \ }) -#define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED KVM_X86_PMU_FEATURE(5) +#define X86_PMU_FEATURE_CPU_CYCLES KVM_X86_PMU_FEATURE(EBX, 0) +#define X86_PMU_FEATURE_INSNS_RETIRED KVM_X86_PMU_FEATURE(EBX, 1) +#define X86_PMU_FEATURE_REFERENCE_CYCLES KVM_X86_PMU_FEATURE(EBX, 2) +#define X86_PMU_FEATURE_LLC_REFERENCES KVM_X86_PMU_FEATURE(EBX, 3) +#define X86_PMU_FEATURE_LLC_MISSES KVM_X86_PMU_FEATURE(EBX, 4) +#define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED KVM_X86_PMU_FEATURE(EBX, 5) +#define X86_PMU_FEATURE_BRANCHES_MISPREDICTED KVM_X86_PMU_FEATURE(EBX, 6) +#define X86_PMU_FEATURE_TOPDOWN_SLOTS KVM_X86_PMU_FEATURE(EBX, 7) + +#define X86_PMU_FEATURE_INSNS_RETIRED_FIXED KVM_X86_PMU_FEATURE(ECX, 0) +#define X86_PMU_FEATURE_CPU_CYCLES_FIXED KVM_X86_PMU_FEATURE(ECX, 1) +#define X86_PMU_FEATURE_REFERENCE_TSC_CYCLES_FIXED KVM_X86_PMU_FEATURE(ECX, 2) +#define X86_PMU_FEATURE_TOPDOWN_SLOTS_FIXED KVM_X86_PMU_FEATURE(ECX, 3) static inline unsigned int x86_family(unsigned int eax) { @@ -698,10 +715,16 @@ static __always_inline bool this_cpu_has_p(struct kvm_x86_cpu_property property) static inline bool this_pmu_has(struct kvm_x86_pmu_feature feature) { - uint32_t nr_bits = this_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + uint32_t nr_bits; - return nr_bits > feature.anti_feature.bit && - !this_cpu_has(feature.anti_feature); + if (feature.f.reg == KVM_CPUID_EBX) { + nr_bits = this_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + return nr_bits > feature.f.bit && !this_cpu_has(feature.f); + } + + GUEST_ASSERT(feature.f.reg == KVM_CPUID_ECX); + nr_bits = this_cpu_property(X86_PROPERTY_PMU_NR_FIXED_COUNTERS); + return nr_bits > feature.f.bit || this_cpu_has(feature.f); } static __always_inline uint64_t this_cpu_supported_xcr0(void) @@ -917,10 +940,16 @@ static __always_inline bool kvm_cpu_has_p(struct kvm_x86_cpu_property property) static inline bool kvm_pmu_has(struct kvm_x86_pmu_feature feature) { - uint32_t nr_bits = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + uint32_t nr_bits; - return nr_bits > feature.anti_feature.bit && - !kvm_cpu_has(feature.anti_feature); + if (feature.f.reg == KVM_CPUID_EBX) { + nr_bits = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + return nr_bits > feature.f.bit && !kvm_cpu_has(feature.f); + } + + TEST_ASSERT_EQ(feature.f.reg, KVM_CPUID_ECX); + nr_bits = kvm_cpu_property(X86_PROPERTY_PMU_NR_FIXED_COUNTERS); + return nr_bits > feature.f.bit || kvm_cpu_has(feature.f); } static __always_inline uint64_t kvm_cpu_supported_xcr0(void) From e6faa04970575622243d3a20782dde2d5813772d Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:35 -0800 Subject: [PATCH 140/814] KVM: selftests: Add pmu.h and lib/pmu.c for common PMU assets Add a PMU library for x86 selftests to help eliminate open-coded event encodings, and to reduce the amount of copy+paste between PMU selftests. Use the new common macro definitions in the existing PMU event filter test. Cc: Aaron Lewis Suggested-by: Sean Christopherson Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-16-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/x86_64/pmu.h | 97 ++++++++++++ tools/testing/selftests/kvm/lib/x86_64/pmu.c | 31 ++++ .../kvm/x86_64/pmu_event_filter_test.c | 141 ++++++------------ 4 files changed, 173 insertions(+), 97 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/x86_64/pmu.h create mode 100644 tools/testing/selftests/kvm/lib/x86_64/pmu.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 492e937fab00..0f07ce8bd297 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -36,6 +36,7 @@ LIBKVM_x86_64 += lib/x86_64/apic.c LIBKVM_x86_64 += lib/x86_64/handlers.S LIBKVM_x86_64 += lib/x86_64/hyperv.c LIBKVM_x86_64 += lib/x86_64/memstress.c +LIBKVM_x86_64 += lib/x86_64/pmu.c LIBKVM_x86_64 += lib/x86_64/processor.c LIBKVM_x86_64 += lib/x86_64/svm.c LIBKVM_x86_64 += lib/x86_64/ucall.c diff --git a/tools/testing/selftests/kvm/include/x86_64/pmu.h b/tools/testing/selftests/kvm/include/x86_64/pmu.h new file mode 100644 index 000000000000..3c10c4dc0ae8 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/pmu.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023, Tencent, Inc. + */ +#ifndef SELFTEST_KVM_PMU_H +#define SELFTEST_KVM_PMU_H + +#include + +#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300 + +/* + * Encode an eventsel+umask pair into event-select MSR format. Note, this is + * technically AMD's format, as Intel's format only supports 8 bits for the + * event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing + * in '0' is a nop and won't clobber the CMASK. + */ +#define RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \ + ((eventsel) & 0xff) | \ + ((umask) & 0xff) << 8) + +/* + * These are technically Intel's definitions, but except for CMASK (see above), + * AMD's layout is compatible with Intel's. + */ +#define ARCH_PERFMON_EVENTSEL_EVENT GENMASK_ULL(7, 0) +#define ARCH_PERFMON_EVENTSEL_UMASK GENMASK_ULL(15, 8) +#define ARCH_PERFMON_EVENTSEL_USR BIT_ULL(16) +#define ARCH_PERFMON_EVENTSEL_OS BIT_ULL(17) +#define ARCH_PERFMON_EVENTSEL_EDGE BIT_ULL(18) +#define ARCH_PERFMON_EVENTSEL_PIN_CONTROL BIT_ULL(19) +#define ARCH_PERFMON_EVENTSEL_INT BIT_ULL(20) +#define ARCH_PERFMON_EVENTSEL_ANY BIT_ULL(21) +#define ARCH_PERFMON_EVENTSEL_ENABLE BIT_ULL(22) +#define ARCH_PERFMON_EVENTSEL_INV BIT_ULL(23) +#define ARCH_PERFMON_EVENTSEL_CMASK GENMASK_ULL(31, 24) + +/* RDPMC control flags, Intel only. */ +#define INTEL_RDPMC_METRICS BIT_ULL(29) +#define INTEL_RDPMC_FIXED BIT_ULL(30) +#define INTEL_RDPMC_FAST BIT_ULL(31) + +/* Fixed PMC controls, Intel only. */ +#define FIXED_PMC_GLOBAL_CTRL_ENABLE(_idx) BIT_ULL((32 + (_idx))) + +#define FIXED_PMC_KERNEL BIT_ULL(0) +#define FIXED_PMC_USER BIT_ULL(1) +#define FIXED_PMC_ANYTHREAD BIT_ULL(2) +#define FIXED_PMC_ENABLE_PMI BIT_ULL(3) +#define FIXED_PMC_NR_BITS 4 +#define FIXED_PMC_CTRL(_idx, _val) ((_val) << ((_idx) * FIXED_PMC_NR_BITS)) + +#define PMU_CAP_FW_WRITES BIT_ULL(13) +#define PMU_CAP_LBR_FMT 0x3f + +#define INTEL_ARCH_CPU_CYCLES RAW_EVENT(0x3c, 0x00) +#define INTEL_ARCH_INSTRUCTIONS_RETIRED RAW_EVENT(0xc0, 0x00) +#define INTEL_ARCH_REFERENCE_CYCLES RAW_EVENT(0x3c, 0x01) +#define INTEL_ARCH_LLC_REFERENCES RAW_EVENT(0x2e, 0x4f) +#define INTEL_ARCH_LLC_MISSES RAW_EVENT(0x2e, 0x41) +#define INTEL_ARCH_BRANCHES_RETIRED RAW_EVENT(0xc4, 0x00) +#define INTEL_ARCH_BRANCHES_MISPREDICTED RAW_EVENT(0xc5, 0x00) +#define INTEL_ARCH_TOPDOWN_SLOTS RAW_EVENT(0xa4, 0x01) + +#define AMD_ZEN_CORE_CYCLES RAW_EVENT(0x76, 0x00) +#define AMD_ZEN_INSTRUCTIONS_RETIRED RAW_EVENT(0xc0, 0x00) +#define AMD_ZEN_BRANCHES_RETIRED RAW_EVENT(0xc2, 0x00) +#define AMD_ZEN_BRANCHES_MISPREDICTED RAW_EVENT(0xc3, 0x00) + +/* + * Note! The order and thus the index of the architectural events matters as + * support for each event is enumerated via CPUID using the index of the event. + */ +enum intel_pmu_architectural_events { + INTEL_ARCH_CPU_CYCLES_INDEX, + INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX, + INTEL_ARCH_REFERENCE_CYCLES_INDEX, + INTEL_ARCH_LLC_REFERENCES_INDEX, + INTEL_ARCH_LLC_MISSES_INDEX, + INTEL_ARCH_BRANCHES_RETIRED_INDEX, + INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX, + INTEL_ARCH_TOPDOWN_SLOTS_INDEX, + NR_INTEL_ARCH_EVENTS, +}; + +enum amd_pmu_zen_events { + AMD_ZEN_CORE_CYCLES_INDEX, + AMD_ZEN_INSTRUCTIONS_INDEX, + AMD_ZEN_BRANCHES_INDEX, + AMD_ZEN_BRANCH_MISSES_INDEX, + NR_AMD_ZEN_EVENTS, +}; + +extern const uint64_t intel_pmu_arch_events[]; +extern const uint64_t amd_pmu_zen_events[]; + +#endif /* SELFTEST_KVM_PMU_H */ diff --git a/tools/testing/selftests/kvm/lib/x86_64/pmu.c b/tools/testing/selftests/kvm/lib/x86_64/pmu.c new file mode 100644 index 000000000000..f31f0427c17c --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86_64/pmu.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023, Tencent, Inc. + */ + +#include + +#include + +#include "kvm_util.h" +#include "pmu.h" + +const uint64_t intel_pmu_arch_events[] = { + 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, + INTEL_ARCH_TOPDOWN_SLOTS, +}; +kvm_static_assert(ARRAY_SIZE(intel_pmu_arch_events) == NR_INTEL_ARCH_EVENTS); + +const uint64_t amd_pmu_zen_events[] = { + AMD_ZEN_CORE_CYCLES, + AMD_ZEN_INSTRUCTIONS_RETIRED, + AMD_ZEN_BRANCHES_RETIRED, + AMD_ZEN_BRANCHES_MISPREDICTED, +}; +kvm_static_assert(ARRAY_SIZE(amd_pmu_zen_events) == NR_AMD_ZEN_EVENTS); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 283cc55597a4..7ec9fbed92e0 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -11,72 +11,18 @@ */ #define _GNU_SOURCE /* for program_invocation_short_name */ -#include "test_util.h" + #include "kvm_util.h" +#include "pmu.h" #include "processor.h" - -/* - * In lieu of copying perf_event.h into tools... - */ -#define ARCH_PERFMON_EVENTSEL_OS (1ULL << 17) -#define ARCH_PERFMON_EVENTSEL_ENABLE (1ULL << 22) - -/* End of stuff taken from perf_event.h. */ - -/* Oddly, this isn't in perf_event.h. */ -#define ARCH_PERFMON_BRANCHES_RETIRED 5 +#include "test_util.h" #define NUM_BRANCHES 42 -#define INTEL_PMC_IDX_FIXED 32 - -/* Matches KVM_PMU_EVENT_FILTER_MAX_EVENTS in pmu.c */ -#define MAX_FILTER_EVENTS 300 #define MAX_TEST_EVENTS 10 #define PMU_EVENT_FILTER_INVALID_ACTION (KVM_PMU_EVENT_DENY + 1) #define PMU_EVENT_FILTER_INVALID_FLAGS (KVM_PMU_EVENT_FLAGS_VALID_MASK << 1) -#define PMU_EVENT_FILTER_INVALID_NEVENTS (MAX_FILTER_EVENTS + 1) - -/* - * This is how the event selector and unit mask are stored in an AMD - * core performance event-select register. Intel's format is similar, - * but the event selector is only 8 bits. - */ -#define EVENT(select, umask) ((select & 0xf00UL) << 24 | (select & 0xff) | \ - (umask & 0xff) << 8) - -/* - * "Branch instructions retired", from the Intel SDM, volume 3, - * "Pre-defined Architectural Performance Events." - */ - -#define INTEL_BR_RETIRED EVENT(0xc4, 0) - -/* - * "Retired branch instructions", from Processor Programming Reference - * (PPR) for AMD Family 17h Model 01h, Revision B1 Processors, - * Preliminary Processor Programming Reference (PPR) for AMD Family - * 17h Model 31h, Revision B0 Processors, and Preliminary Processor - * Programming Reference (PPR) for AMD Family 19h Model 01h, Revision - * B1 Processors Volume 1 of 2. - */ - -#define AMD_ZEN_BR_RETIRED EVENT(0xc2, 0) - - -/* - * "Retired instructions", from Processor Programming Reference - * (PPR) for AMD Family 17h Model 01h, Revision B1 Processors, - * Preliminary Processor Programming Reference (PPR) for AMD Family - * 17h Model 31h, Revision B0 Processors, and Preliminary Processor - * Programming Reference (PPR) for AMD Family 19h Model 01h, Revision - * B1 Processors Volume 1 of 2. - * --- and --- - * "Instructions retired", from the Intel SDM, volume 3, - * "Pre-defined Architectural Performance Events." - */ - -#define INST_RETIRED EVENT(0xc0, 0) +#define PMU_EVENT_FILTER_INVALID_NEVENTS (KVM_PMU_EVENT_FILTER_MAX_EVENTS + 1) struct __kvm_pmu_event_filter { __u32 action; @@ -84,26 +30,28 @@ struct __kvm_pmu_event_filter { __u32 fixed_counter_bitmap; __u32 flags; __u32 pad[4]; - __u64 events[MAX_FILTER_EVENTS]; + __u64 events[KVM_PMU_EVENT_FILTER_MAX_EVENTS]; }; /* - * This event list comprises Intel's eight architectural events plus - * AMD's "retired branch instructions" for Zen[123] (and possibly - * other AMD CPUs). + * This event list comprises Intel's known architectural events, plus AMD's + * "retired branch instructions" for Zen1-Zen3 (and* possibly other AMD CPUs). + * Note, AMD and Intel use the same encoding for instructions retired. */ +kvm_static_assert(INTEL_ARCH_INSTRUCTIONS_RETIRED == AMD_ZEN_INSTRUCTIONS_RETIRED); + static const struct __kvm_pmu_event_filter base_event_filter = { .nevents = ARRAY_SIZE(base_event_filter.events), .events = { - EVENT(0x3c, 0), - INST_RETIRED, - EVENT(0x3c, 1), - EVENT(0x2e, 0x4f), - EVENT(0x2e, 0x41), - EVENT(0xc4, 0), - EVENT(0xc5, 0), - EVENT(0xa4, 1), - AMD_ZEN_BR_RETIRED, + 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, + INTEL_ARCH_TOPDOWN_SLOTS, + AMD_ZEN_BRANCHES_RETIRED, }, }; @@ -165,9 +113,9 @@ static void intel_guest_code(void) for (;;) { wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); wrmsr(MSR_P6_EVNTSEL0, ARCH_PERFMON_EVENTSEL_ENABLE | - ARCH_PERFMON_EVENTSEL_OS | INTEL_BR_RETIRED); + ARCH_PERFMON_EVENTSEL_OS | INTEL_ARCH_BRANCHES_RETIRED); wrmsr(MSR_P6_EVNTSEL1, ARCH_PERFMON_EVENTSEL_ENABLE | - ARCH_PERFMON_EVENTSEL_OS | INST_RETIRED); + ARCH_PERFMON_EVENTSEL_OS | INTEL_ARCH_INSTRUCTIONS_RETIRED); wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0x3); run_and_measure_loop(MSR_IA32_PMC0); @@ -189,9 +137,9 @@ static void amd_guest_code(void) for (;;) { wrmsr(MSR_K7_EVNTSEL0, 0); wrmsr(MSR_K7_EVNTSEL0, ARCH_PERFMON_EVENTSEL_ENABLE | - ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_BR_RETIRED); + ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_BRANCHES_RETIRED); wrmsr(MSR_K7_EVNTSEL1, ARCH_PERFMON_EVENTSEL_ENABLE | - ARCH_PERFMON_EVENTSEL_OS | INST_RETIRED); + ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_INSTRUCTIONS_RETIRED); run_and_measure_loop(MSR_K7_PERFCTR0); GUEST_SYNC(0); @@ -312,7 +260,7 @@ static void test_amd_deny_list(struct kvm_vcpu *vcpu) .action = KVM_PMU_EVENT_DENY, .nevents = 1, .events = { - EVENT(0x1C2, 0), + RAW_EVENT(0x1C2, 0), }, }; @@ -347,9 +295,9 @@ static void test_not_member_deny_list(struct kvm_vcpu *vcpu) f.action = KVM_PMU_EVENT_DENY; - remove_event(&f, INST_RETIRED); - remove_event(&f, INTEL_BR_RETIRED); - remove_event(&f, AMD_ZEN_BR_RETIRED); + remove_event(&f, INTEL_ARCH_INSTRUCTIONS_RETIRED); + remove_event(&f, INTEL_ARCH_BRANCHES_RETIRED); + remove_event(&f, AMD_ZEN_BRANCHES_RETIRED); test_with_filter(vcpu, &f); ASSERT_PMC_COUNTING_INSTRUCTIONS(); @@ -361,9 +309,9 @@ static void test_not_member_allow_list(struct kvm_vcpu *vcpu) f.action = KVM_PMU_EVENT_ALLOW; - remove_event(&f, INST_RETIRED); - remove_event(&f, INTEL_BR_RETIRED); - remove_event(&f, AMD_ZEN_BR_RETIRED); + remove_event(&f, INTEL_ARCH_INSTRUCTIONS_RETIRED); + remove_event(&f, INTEL_ARCH_BRANCHES_RETIRED); + remove_event(&f, AMD_ZEN_BRANCHES_RETIRED); test_with_filter(vcpu, &f); ASSERT_PMC_NOT_COUNTING_INSTRUCTIONS(); @@ -452,9 +400,9 @@ static bool use_amd_pmu(void) * - Sapphire Rapids, Ice Lake, Cascade Lake, Skylake. */ #define MEM_INST_RETIRED 0xD0 -#define MEM_INST_RETIRED_LOAD EVENT(MEM_INST_RETIRED, 0x81) -#define MEM_INST_RETIRED_STORE EVENT(MEM_INST_RETIRED, 0x82) -#define MEM_INST_RETIRED_LOAD_STORE EVENT(MEM_INST_RETIRED, 0x83) +#define MEM_INST_RETIRED_LOAD RAW_EVENT(MEM_INST_RETIRED, 0x81) +#define MEM_INST_RETIRED_STORE RAW_EVENT(MEM_INST_RETIRED, 0x82) +#define MEM_INST_RETIRED_LOAD_STORE RAW_EVENT(MEM_INST_RETIRED, 0x83) static bool supports_event_mem_inst_retired(void) { @@ -486,9 +434,9 @@ static bool supports_event_mem_inst_retired(void) * B1 Processors Volume 1 of 2. */ #define LS_DISPATCH 0x29 -#define LS_DISPATCH_LOAD EVENT(LS_DISPATCH, BIT(0)) -#define LS_DISPATCH_STORE EVENT(LS_DISPATCH, BIT(1)) -#define LS_DISPATCH_LOAD_STORE EVENT(LS_DISPATCH, BIT(2)) +#define LS_DISPATCH_LOAD RAW_EVENT(LS_DISPATCH, BIT(0)) +#define LS_DISPATCH_STORE RAW_EVENT(LS_DISPATCH, BIT(1)) +#define LS_DISPATCH_LOAD_STORE RAW_EVENT(LS_DISPATCH, BIT(2)) #define INCLUDE_MASKED_ENTRY(event_select, mask, match) \ KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, false) @@ -729,14 +677,14 @@ static void add_dummy_events(uint64_t *events, int nevents) static void test_masked_events(struct kvm_vcpu *vcpu) { - int nevents = MAX_FILTER_EVENTS - MAX_TEST_EVENTS; - uint64_t events[MAX_FILTER_EVENTS]; + int nevents = KVM_PMU_EVENT_FILTER_MAX_EVENTS - MAX_TEST_EVENTS; + uint64_t events[KVM_PMU_EVENT_FILTER_MAX_EVENTS]; /* Run the test cases against a sparse PMU event filter. */ run_masked_events_tests(vcpu, events, 0); /* Run the test cases against a dense PMU event filter. */ - add_dummy_events(events, MAX_FILTER_EVENTS); + add_dummy_events(events, KVM_PMU_EVENT_FILTER_MAX_EVENTS); run_masked_events_tests(vcpu, events, nevents); } @@ -809,20 +757,19 @@ static void test_filter_ioctl(struct kvm_vcpu *vcpu) TEST_ASSERT(!r, "Masking non-existent fixed counters should be allowed"); } -static void intel_run_fixed_counter_guest_code(uint8_t fixed_ctr_idx) +static void intel_run_fixed_counter_guest_code(uint8_t idx) { for (;;) { wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); - wrmsr(MSR_CORE_PERF_FIXED_CTR0 + fixed_ctr_idx, 0); + wrmsr(MSR_CORE_PERF_FIXED_CTR0 + idx, 0); /* Only OS_EN bit is enabled for fixed counter[idx]. */ - wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, BIT_ULL(4 * fixed_ctr_idx)); - wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, - BIT_ULL(INTEL_PMC_IDX_FIXED + fixed_ctr_idx)); + wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, FIXED_PMC_CTRL(idx, FIXED_PMC_KERNEL)); + wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, FIXED_PMC_GLOBAL_CTRL_ENABLE(idx)); __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES})); wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); - GUEST_SYNC(rdmsr(MSR_CORE_PERF_FIXED_CTR0 + fixed_ctr_idx)); + GUEST_SYNC(rdmsr(MSR_CORE_PERF_FIXED_CTR0 + idx)); } } From 4f1bd6b16074aa5f9a0633a77fc87f471888a588 Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:36 -0800 Subject: [PATCH 141/814] KVM: selftests: Test Intel PMU architectural events on gp counters Add test cases to verify that Intel's Architectural PMU events work as expected when they are available according to guest CPUID. Iterate over a range of sane PMU versions, with and without full-width writes enabled, and over interesting combinations of lengths/masks for the bit vector that enumerates unavailable events. Test up to vPMU version 5, i.e. the current architectural max. KVM only officially supports up to version 2, but the behavior of the counters is backwards compatible, i.e. KVM shouldn't do something completely different for a higher, architecturally-defined vPMU version. Verify KVM behavior against the effective vPMU version, e.g. advertising vPMU 5 when KVM only supports vPMU 2 shouldn't magically unlock vPMU 5 features. According to Intel SDM, the number of architectural events is reported through CPUID.0AH:EAX[31:24] and the architectural event x is supported if EBX[x]=0 && EAX[31:24]>x. Handcode the entirety of the measured section so that the test can precisely assert on the number of instructions and branches retired. Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-17-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/pmu_counters_test.c | 321 ++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/pmu_counters_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 0f07ce8bd297..ce58098d80fd 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -81,6 +81,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test TEST_GEN_PROGS_x86_64 += x86_64/nested_exceptions_test TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test +TEST_GEN_PROGS_x86_64 += x86_64/pmu_counters_test TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test TEST_GEN_PROGS_x86_64 += x86_64/private_mem_conversions_test TEST_GEN_PROGS_x86_64 += x86_64/private_mem_kvm_exits_test diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c new file mode 100644 index 000000000000..5b8687bb4639 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023, Tencent, Inc. + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include + +#include "pmu.h" +#include "processor.h" + +/* Number of LOOP instructions for the guest measurement payload. */ +#define NUM_BRANCHES 10 +/* + * Number of "extra" instructions that will be counted, i.e. the number of + * instructions that are needed to set up the loop and then disabled the + * counter. 2 MOV, 2 XOR, 1 WRMSR. + */ +#define NUM_EXTRA_INSNS 5 +#define NUM_INSNS_RETIRED (NUM_BRANCHES + NUM_EXTRA_INSNS) + +static uint8_t kvm_pmu_version; +static bool kvm_has_perf_caps; + +static struct kvm_vm *pmu_vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, + void *guest_code, + uint8_t pmu_version, + uint64_t perf_capabilities) +{ + struct kvm_vm *vm; + + vm = vm_create_with_one_vcpu(vcpu, guest_code); + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(*vcpu); + + sync_global_to_guest(vm, kvm_pmu_version); + + /* + * Set PERF_CAPABILITIES before PMU version as KVM disallows enabling + * features via PERF_CAPABILITIES if the guest doesn't have a vPMU. + */ + if (kvm_has_perf_caps) + vcpu_set_msr(*vcpu, MSR_IA32_PERF_CAPABILITIES, perf_capabilities); + + vcpu_set_cpuid_property(*vcpu, X86_PROPERTY_PMU_VERSION, pmu_version); + return vm; +} + +static void run_vcpu(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + do { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_PRINTF: + pr_info("%s", uc.buffer); + break; + case UCALL_DONE: + break; + default: + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); + } + } while (uc.cmd != UCALL_DONE); +} + +static uint8_t guest_get_pmu_version(void) +{ + /* + * Return the effective PMU version, i.e. the minimum between what KVM + * supports and what is enumerated to the guest. The host deliberately + * advertises a PMU version to the guest beyond what is actually + * supported by KVM to verify KVM doesn't freak out and do something + * bizarre with an architecturally valid, but unsupported, version. + */ + return min_t(uint8_t, kvm_pmu_version, this_cpu_property(X86_PROPERTY_PMU_VERSION)); +} + +/* + * If an architectural event is supported and guaranteed to generate at least + * one "hit, assert that its count is non-zero. If an event isn't supported or + * the test can't guarantee the associated action will occur, then all bets are + * off regarding the count, i.e. no checks can be done. + * + * Sanity check that in all cases, the event doesn't count when it's disabled, + * and that KVM correctly emulates the write of an arbitrary value. + */ +static void guest_assert_event_count(uint8_t idx, + struct kvm_x86_pmu_feature event, + uint32_t pmc, uint32_t pmc_msr) +{ + uint64_t count; + + count = _rdpmc(pmc); + if (!this_pmu_has(event)) + goto sanity_checks; + + switch (idx) { + case INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX: + GUEST_ASSERT_EQ(count, NUM_INSNS_RETIRED); + break; + case INTEL_ARCH_BRANCHES_RETIRED_INDEX: + GUEST_ASSERT_EQ(count, NUM_BRANCHES); + break; + case INTEL_ARCH_CPU_CYCLES_INDEX: + case INTEL_ARCH_REFERENCE_CYCLES_INDEX: + GUEST_ASSERT_NE(count, 0); + break; + default: + break; + } + +sanity_checks: + __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES})); + GUEST_ASSERT_EQ(_rdpmc(pmc), count); + + wrmsr(pmc_msr, 0xdead); + GUEST_ASSERT_EQ(_rdpmc(pmc), 0xdead); +} + +static void __guest_test_arch_event(uint8_t idx, struct kvm_x86_pmu_feature event, + uint32_t pmc, uint32_t pmc_msr, + uint32_t ctrl_msr, uint64_t ctrl_msr_value) +{ + wrmsr(pmc_msr, 0); + + /* + * Enable and disable the PMC in a monolithic asm blob to ensure that + * the compiler can't insert _any_ code into the measured sequence. + * Note, ECX doesn't need to be clobbered as the input value, @pmc_msr, + * is restored before the end of the sequence. + */ + __asm__ __volatile__("wrmsr\n\t" + "mov $" __stringify(NUM_BRANCHES) ", %%ecx\n\t" + "loop .\n\t" + "mov %%edi, %%ecx\n\t" + "xor %%eax, %%eax\n\t" + "xor %%edx, %%edx\n\t" + "wrmsr\n\t" + :: "a"((uint32_t)ctrl_msr_value), + "d"(ctrl_msr_value >> 32), + "c"(ctrl_msr), "D"(ctrl_msr) + ); + + guest_assert_event_count(idx, event, pmc, pmc_msr); +} + +static void guest_test_arch_event(uint8_t idx) +{ + const struct { + struct kvm_x86_pmu_feature gp_event; + } intel_event_to_feature[] = { + [INTEL_ARCH_CPU_CYCLES_INDEX] = { X86_PMU_FEATURE_CPU_CYCLES }, + [INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX] = { X86_PMU_FEATURE_INSNS_RETIRED }, + [INTEL_ARCH_REFERENCE_CYCLES_INDEX] = { X86_PMU_FEATURE_REFERENCE_CYCLES }, + [INTEL_ARCH_LLC_REFERENCES_INDEX] = { X86_PMU_FEATURE_LLC_REFERENCES }, + [INTEL_ARCH_LLC_MISSES_INDEX] = { X86_PMU_FEATURE_LLC_MISSES }, + [INTEL_ARCH_BRANCHES_RETIRED_INDEX] = { X86_PMU_FEATURE_BRANCH_INSNS_RETIRED }, + [INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX] = { X86_PMU_FEATURE_BRANCHES_MISPREDICTED }, + [INTEL_ARCH_TOPDOWN_SLOTS_INDEX] = { X86_PMU_FEATURE_TOPDOWN_SLOTS }, + }; + + uint32_t nr_gp_counters = this_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS); + uint32_t pmu_version = guest_get_pmu_version(); + /* PERF_GLOBAL_CTRL exists only for Architectural PMU Version 2+. */ + bool guest_has_perf_global_ctrl = pmu_version >= 2; + struct kvm_x86_pmu_feature gp_event; + uint32_t base_pmc_msr; + unsigned int i; + + /* The host side shouldn't invoke this without a guest PMU. */ + GUEST_ASSERT(pmu_version); + + if (this_cpu_has(X86_FEATURE_PDCM) && + rdmsr(MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES) + base_pmc_msr = MSR_IA32_PMC0; + else + base_pmc_msr = MSR_IA32_PERFCTR0; + + gp_event = intel_event_to_feature[idx].gp_event; + GUEST_ASSERT_EQ(idx, gp_event.f.bit); + + GUEST_ASSERT(nr_gp_counters); + + for (i = 0; i < nr_gp_counters; i++) { + uint64_t eventsel = ARCH_PERFMON_EVENTSEL_OS | + ARCH_PERFMON_EVENTSEL_ENABLE | + intel_pmu_arch_events[idx]; + + wrmsr(MSR_P6_EVNTSEL0 + i, 0); + if (guest_has_perf_global_ctrl) + wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, BIT_ULL(i)); + + __guest_test_arch_event(idx, gp_event, i, base_pmc_msr + i, + MSR_P6_EVNTSEL0 + i, eventsel); + } +} + +static void guest_test_arch_events(void) +{ + uint8_t i; + + for (i = 0; i < NR_INTEL_ARCH_EVENTS; i++) + guest_test_arch_event(i); + + GUEST_DONE(); +} + +static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities, + uint8_t length, uint8_t unavailable_mask) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + /* Testing arch events requires a vPMU (there are no negative tests). */ + if (!pmu_version) + return; + + vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_test_arch_events, + pmu_version, perf_capabilities); + + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH, + length); + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_EVENTS_MASK, + unavailable_mask); + + run_vcpu(vcpu); + + kvm_vm_free(vm); +} + +static void test_intel_counters(void) +{ + uint8_t nr_arch_events = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + uint8_t pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION); + unsigned int i; + uint8_t v, j; + uint32_t k; + + const uint64_t perf_caps[] = { + 0, + PMU_CAP_FW_WRITES, + }; + + /* + * Test up to PMU v5, which is the current maximum version defined by + * Intel, i.e. is the last version that is guaranteed to be backwards + * compatible with KVM's existing behavior. + */ + uint8_t max_pmu_version = max_t(typeof(pmu_version), pmu_version, 5); + + /* + * Detect the existence of events that aren't supported by selftests. + * This will (obviously) fail any time the kernel adds support for a + * new event, but it's worth paying that price to keep the test fresh. + */ + TEST_ASSERT(nr_arch_events <= NR_INTEL_ARCH_EVENTS, + "New architectural event(s) detected; please update this test (length = %u, mask = %x)", + nr_arch_events, kvm_cpu_property(X86_PROPERTY_PMU_EVENTS_MASK)); + + /* + * Force iterating over known arch events regardless of whether or not + * KVM/hardware supports a given event. + */ + nr_arch_events = max_t(typeof(nr_arch_events), nr_arch_events, NR_INTEL_ARCH_EVENTS); + + for (v = 0; v <= max_pmu_version; v++) { + for (i = 0; i < ARRAY_SIZE(perf_caps); i++) { + if (!kvm_has_perf_caps && perf_caps[i]) + continue; + + pr_info("Testing arch events, PMU version %u, perf_caps = %lx\n", + v, perf_caps[i]); + /* + * To keep the total runtime reasonable, test every + * possible non-zero, non-reserved bitmap combination + * only with the native PMU version and the full bit + * vector length. + */ + if (v == pmu_version) { + for (k = 1; k < (BIT(nr_arch_events) - 1); k++) + test_arch_events(v, perf_caps[i], nr_arch_events, k); + } + /* + * Test single bits for all PMU version and lengths up + * the number of events +1 (to verify KVM doesn't do + * weird things if the guest length is greater than the + * host length). Explicitly test a mask of '0' and all + * ones i.e. all events being available and unavailable. + */ + for (j = 0; j <= nr_arch_events + 1; j++) { + test_arch_events(v, perf_caps[i], j, 0); + test_arch_events(v, perf_caps[i], j, 0xff); + + for (k = 0; k < nr_arch_events; k++) + test_arch_events(v, perf_caps[i], j, BIT(k)); + } + } + } +} + +int main(int argc, char *argv[]) +{ + TEST_REQUIRE(get_kvm_param_bool("enable_pmu")); + + TEST_REQUIRE(host_cpu_is_intel); + TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION)); + TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0); + + kvm_pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION); + kvm_has_perf_caps = kvm_cpu_has(X86_FEATURE_PDCM); + + test_intel_counters(); + + return 0; +} From 3e26b825f87ddfa610e069ff3f668b942d8642bb Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:37 -0800 Subject: [PATCH 142/814] KVM: selftests: Test Intel PMU architectural events on fixed counters Extend the PMU counters test to validate architectural events using fixed counters. The core logic is largely the same, the biggest difference being that if a fixed counter exists, its associated event is available (the SDM doesn't explicitly state this to be true, but it's KVM's ABI and letting software program a fixed counter that doesn't actually count would be quite bizarre). Note, fixed counters rely on PERF_GLOBAL_CTRL. Reviewed-by: Jim Mattson Reviewed-by: Dapeng Mi Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-18-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 5b8687bb4639..663e8fbe7ff8 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -150,26 +150,46 @@ static void __guest_test_arch_event(uint8_t idx, struct kvm_x86_pmu_feature even guest_assert_event_count(idx, event, pmc, pmc_msr); } +#define X86_PMU_FEATURE_NULL \ +({ \ + struct kvm_x86_pmu_feature feature = {}; \ + \ + feature; \ +}) + +static bool pmu_is_null_feature(struct kvm_x86_pmu_feature event) +{ + return !(*(u64 *)&event); +} + static void guest_test_arch_event(uint8_t idx) { const struct { struct kvm_x86_pmu_feature gp_event; + struct kvm_x86_pmu_feature fixed_event; } intel_event_to_feature[] = { - [INTEL_ARCH_CPU_CYCLES_INDEX] = { X86_PMU_FEATURE_CPU_CYCLES }, - [INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX] = { X86_PMU_FEATURE_INSNS_RETIRED }, - [INTEL_ARCH_REFERENCE_CYCLES_INDEX] = { X86_PMU_FEATURE_REFERENCE_CYCLES }, - [INTEL_ARCH_LLC_REFERENCES_INDEX] = { X86_PMU_FEATURE_LLC_REFERENCES }, - [INTEL_ARCH_LLC_MISSES_INDEX] = { X86_PMU_FEATURE_LLC_MISSES }, - [INTEL_ARCH_BRANCHES_RETIRED_INDEX] = { X86_PMU_FEATURE_BRANCH_INSNS_RETIRED }, - [INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX] = { X86_PMU_FEATURE_BRANCHES_MISPREDICTED }, - [INTEL_ARCH_TOPDOWN_SLOTS_INDEX] = { X86_PMU_FEATURE_TOPDOWN_SLOTS }, + [INTEL_ARCH_CPU_CYCLES_INDEX] = { X86_PMU_FEATURE_CPU_CYCLES, X86_PMU_FEATURE_CPU_CYCLES_FIXED }, + [INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX] = { X86_PMU_FEATURE_INSNS_RETIRED, X86_PMU_FEATURE_INSNS_RETIRED_FIXED }, + /* + * Note, the fixed counter for reference cycles is NOT the same + * as the general purpose architectural event. The fixed counter + * explicitly counts at the same frequency as the TSC, whereas + * the GP event counts at a fixed, but uarch specific, frequency. + * Bundle them here for simplicity. + */ + [INTEL_ARCH_REFERENCE_CYCLES_INDEX] = { X86_PMU_FEATURE_REFERENCE_CYCLES, X86_PMU_FEATURE_REFERENCE_TSC_CYCLES_FIXED }, + [INTEL_ARCH_LLC_REFERENCES_INDEX] = { X86_PMU_FEATURE_LLC_REFERENCES, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_LLC_MISSES_INDEX] = { X86_PMU_FEATURE_LLC_MISSES, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_BRANCHES_RETIRED_INDEX] = { X86_PMU_FEATURE_BRANCH_INSNS_RETIRED, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX] = { X86_PMU_FEATURE_BRANCHES_MISPREDICTED, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_TOPDOWN_SLOTS_INDEX] = { X86_PMU_FEATURE_TOPDOWN_SLOTS, X86_PMU_FEATURE_TOPDOWN_SLOTS_FIXED }, }; uint32_t nr_gp_counters = this_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS); uint32_t pmu_version = guest_get_pmu_version(); /* PERF_GLOBAL_CTRL exists only for Architectural PMU Version 2+. */ bool guest_has_perf_global_ctrl = pmu_version >= 2; - struct kvm_x86_pmu_feature gp_event; + struct kvm_x86_pmu_feature gp_event, fixed_event; uint32_t base_pmc_msr; unsigned int i; @@ -199,6 +219,22 @@ static void guest_test_arch_event(uint8_t idx) __guest_test_arch_event(idx, gp_event, i, base_pmc_msr + i, MSR_P6_EVNTSEL0 + i, eventsel); } + + if (!guest_has_perf_global_ctrl) + return; + + fixed_event = intel_event_to_feature[idx].fixed_event; + if (pmu_is_null_feature(fixed_event) || !this_pmu_has(fixed_event)) + return; + + i = fixed_event.f.bit; + + wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, FIXED_PMC_CTRL(i, FIXED_PMC_KERNEL)); + + __guest_test_arch_event(idx, fixed_event, i | INTEL_RDPMC_FIXED, + MSR_CORE_PERF_FIXED_CTR0 + i, + MSR_CORE_PERF_GLOBAL_CTRL, + FIXED_PMC_GLOBAL_CTRL_ENABLE(i)); } static void guest_test_arch_events(void) From 7137cf751b9b14662adad61e35c236e141430aed Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:38 -0800 Subject: [PATCH 143/814] KVM: selftests: Test consistency of CPUID with num of gp counters Add a test to verify that KVM correctly emulates MSR-based accesses to general purpose counters based on guest CPUID, e.g. that accesses to non-existent counters #GP and accesses to existent counters succeed. Note, for compatibility reasons, KVM does not emulate #GP when MSR_P6_PERFCTR[0|1] is not present (writes should be dropped). Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-19-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 663e8fbe7ff8..863418842ef8 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -270,9 +270,103 @@ static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities, kvm_vm_free(vm); } +/* + * Limit testing to MSRs that are actually defined by Intel (in the SDM). MSRs + * that aren't defined counter MSRs *probably* don't exist, but there's no + * guarantee that currently undefined MSR indices won't be used for something + * other than PMCs in the future. + */ +#define MAX_NR_GP_COUNTERS 8 +#define MAX_NR_FIXED_COUNTERS 3 + +#define GUEST_ASSERT_PMC_MSR_ACCESS(insn, msr, expect_gp, vector) \ +__GUEST_ASSERT(expect_gp ? vector == GP_VECTOR : !vector, \ + "Expected %s on " #insn "(0x%x), got vector %u", \ + expect_gp ? "#GP" : "no fault", msr, vector) \ + +#define GUEST_ASSERT_PMC_VALUE(insn, msr, val, expected) \ + __GUEST_ASSERT(val == expected_val, \ + "Expected " #insn "(0x%x) to yield 0x%lx, got 0x%lx", \ + msr, expected_val, val); + +static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters, + uint8_t nr_counters) +{ + uint8_t i; + + for (i = 0; i < nr_possible_counters; i++) { + /* + * TODO: Test a value that validates full-width writes and the + * width of the counters. + */ + const uint64_t test_val = 0xffff; + const uint32_t msr = base_msr + i; + const bool expect_success = i < nr_counters; + + /* + * KVM drops writes to MSR_P6_PERFCTR[0|1] if the counters are + * unsupported, i.e. doesn't #GP and reads back '0'. + */ + const uint64_t expected_val = expect_success ? test_val : 0; + const bool expect_gp = !expect_success && msr != MSR_P6_PERFCTR0 && + msr != MSR_P6_PERFCTR1; + uint8_t vector; + uint64_t val; + + vector = wrmsr_safe(msr, test_val); + GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector); + + vector = rdmsr_safe(msr, &val); + GUEST_ASSERT_PMC_MSR_ACCESS(RDMSR, msr, expect_gp, vector); + + /* On #GP, the result of RDMSR is undefined. */ + if (!expect_gp) + GUEST_ASSERT_PMC_VALUE(RDMSR, msr, val, expected_val); + + vector = wrmsr_safe(msr, 0); + GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector); + } + GUEST_DONE(); +} + +static void guest_test_gp_counters(void) +{ + uint8_t nr_gp_counters = 0; + uint32_t base_msr; + + if (guest_get_pmu_version()) + nr_gp_counters = this_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS); + + if (this_cpu_has(X86_FEATURE_PDCM) && + rdmsr(MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES) + base_msr = MSR_IA32_PMC0; + else + base_msr = MSR_IA32_PERFCTR0; + + guest_rd_wr_counters(base_msr, MAX_NR_GP_COUNTERS, nr_gp_counters); +} + +static void test_gp_counters(uint8_t pmu_version, uint64_t perf_capabilities, + uint8_t nr_gp_counters) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_test_gp_counters, + pmu_version, perf_capabilities); + + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_NR_GP_COUNTERS, + nr_gp_counters); + + run_vcpu(vcpu); + + kvm_vm_free(vm); +} + static void test_intel_counters(void) { uint8_t nr_arch_events = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + uint8_t nr_gp_counters = kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS); uint8_t pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION); unsigned int i; uint8_t v, j; @@ -336,6 +430,11 @@ static void test_intel_counters(void) for (k = 0; k < nr_arch_events; k++) test_arch_events(v, perf_caps[i], j, BIT(k)); } + + pr_info("Testing GP counters, PMU version %u, perf_caps = %lx\n", + v, perf_caps[i]); + for (j = 0; j <= nr_gp_counters; j++) + test_gp_counters(v, perf_caps[i], j); } } } From c7d7c76ecf78f93b2bd7d40bccabc813c1ed0a49 Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:39 -0800 Subject: [PATCH 144/814] KVM: selftests: Test consistency of CPUID with num of fixed counters Extend the PMU counters test to verify KVM emulation of fixed counters in addition to general purpose counters. Fixed counters add an extra wrinkle in the form of an extra supported bitmask. Thus quoth the SDM: fixed-function performance counter 'i' is supported if ECX[i] || (EDX[4:0] > i) Test that KVM handles a counter being available through either method. Reviewed-by: Dapeng Mi Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Jinrong Liang Co-developed-by: Sean Christopherson Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-20-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 863418842ef8..b07294af71a3 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -290,7 +290,7 @@ __GUEST_ASSERT(expect_gp ? vector == GP_VECTOR : !vector, \ msr, expected_val, val); static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters, - uint8_t nr_counters) + uint8_t nr_counters, uint32_t or_mask) { uint8_t i; @@ -301,7 +301,13 @@ static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters */ const uint64_t test_val = 0xffff; const uint32_t msr = base_msr + i; - const bool expect_success = i < nr_counters; + + /* + * Fixed counters are supported if the counter is less than the + * number of enumerated contiguous counters *or* the counter is + * explicitly enumerated in the supported counters mask. + */ + const bool expect_success = i < nr_counters || (or_mask & BIT(i)); /* * KVM drops writes to MSR_P6_PERFCTR[0|1] if the counters are @@ -343,7 +349,7 @@ static void guest_test_gp_counters(void) else base_msr = MSR_IA32_PERFCTR0; - guest_rd_wr_counters(base_msr, MAX_NR_GP_COUNTERS, nr_gp_counters); + guest_rd_wr_counters(base_msr, MAX_NR_GP_COUNTERS, nr_gp_counters, 0); } static void test_gp_counters(uint8_t pmu_version, uint64_t perf_capabilities, @@ -363,9 +369,50 @@ static void test_gp_counters(uint8_t pmu_version, uint64_t perf_capabilities, kvm_vm_free(vm); } +static void guest_test_fixed_counters(void) +{ + uint64_t supported_bitmask = 0; + uint8_t nr_fixed_counters = 0; + + /* Fixed counters require Architectural vPMU Version 2+. */ + if (guest_get_pmu_version() >= 2) + nr_fixed_counters = this_cpu_property(X86_PROPERTY_PMU_NR_FIXED_COUNTERS); + + /* + * The supported bitmask for fixed counters was introduced in PMU + * version 5. + */ + if (guest_get_pmu_version() >= 5) + supported_bitmask = this_cpu_property(X86_PROPERTY_PMU_FIXED_COUNTERS_BITMASK); + + guest_rd_wr_counters(MSR_CORE_PERF_FIXED_CTR0, MAX_NR_FIXED_COUNTERS, + nr_fixed_counters, supported_bitmask); +} + +static void test_fixed_counters(uint8_t pmu_version, uint64_t perf_capabilities, + uint8_t nr_fixed_counters, + uint32_t supported_bitmask) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_test_fixed_counters, + pmu_version, perf_capabilities); + + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_FIXED_COUNTERS_BITMASK, + supported_bitmask); + vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_NR_FIXED_COUNTERS, + nr_fixed_counters); + + run_vcpu(vcpu); + + kvm_vm_free(vm); +} + static void test_intel_counters(void) { uint8_t nr_arch_events = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH); + uint8_t nr_fixed_counters = kvm_cpu_property(X86_PROPERTY_PMU_NR_FIXED_COUNTERS); uint8_t nr_gp_counters = kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS); uint8_t pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION); unsigned int i; @@ -435,6 +482,13 @@ static void test_intel_counters(void) v, perf_caps[i]); for (j = 0; j <= nr_gp_counters; j++) test_gp_counters(v, perf_caps[i], j); + + pr_info("Testing fixed counters, PMU version %u, perf_caps = %lx\n", + v, perf_caps[i]); + for (j = 0; j <= nr_fixed_counters; j++) { + for (k = 0; k <= (BIT(nr_fixed_counters) - 1); k++) + test_fixed_counters(v, perf_caps[i], j, k); + } } } } From 787071fd02625151b94a2f93a47cdc9a25884633 Mon Sep 17 00:00:00 2001 From: Jinrong Liang Date: Tue, 9 Jan 2024 15:02:40 -0800 Subject: [PATCH 145/814] KVM: selftests: Add functional test for Intel's fixed PMU counters Extend the fixed counters test to verify that supported counters can actually be enabled in the control MSRs, that unsupported counters cannot, and that enabled counters actually count. Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Jinrong Liang [sean: fold into the rd/wr access test, massage changelog] Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-21-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index b07294af71a3..f5dedd112471 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -332,7 +332,6 @@ static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters vector = wrmsr_safe(msr, 0); GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector); } - GUEST_DONE(); } static void guest_test_gp_counters(void) @@ -350,6 +349,7 @@ static void guest_test_gp_counters(void) base_msr = MSR_IA32_PERFCTR0; guest_rd_wr_counters(base_msr, MAX_NR_GP_COUNTERS, nr_gp_counters, 0); + GUEST_DONE(); } static void test_gp_counters(uint8_t pmu_version, uint64_t perf_capabilities, @@ -373,6 +373,7 @@ static void guest_test_fixed_counters(void) { uint64_t supported_bitmask = 0; uint8_t nr_fixed_counters = 0; + uint8_t i; /* Fixed counters require Architectural vPMU Version 2+. */ if (guest_get_pmu_version() >= 2) @@ -387,6 +388,34 @@ static void guest_test_fixed_counters(void) guest_rd_wr_counters(MSR_CORE_PERF_FIXED_CTR0, MAX_NR_FIXED_COUNTERS, nr_fixed_counters, supported_bitmask); + + for (i = 0; i < MAX_NR_FIXED_COUNTERS; i++) { + uint8_t vector; + uint64_t val; + + if (i >= nr_fixed_counters && !(supported_bitmask & BIT_ULL(i))) { + vector = wrmsr_safe(MSR_CORE_PERF_FIXED_CTR_CTRL, + FIXED_PMC_CTRL(i, FIXED_PMC_KERNEL)); + __GUEST_ASSERT(vector == GP_VECTOR, + "Expected #GP for counter %u in FIXED_CTR_CTRL", i); + + vector = wrmsr_safe(MSR_CORE_PERF_GLOBAL_CTRL, + FIXED_PMC_GLOBAL_CTRL_ENABLE(i)); + __GUEST_ASSERT(vector == GP_VECTOR, + "Expected #GP for counter %u in PERF_GLOBAL_CTRL", i); + continue; + } + + wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, 0); + wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, FIXED_PMC_CTRL(i, FIXED_PMC_KERNEL)); + wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, FIXED_PMC_GLOBAL_CTRL_ENABLE(i)); + __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES})); + wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); + val = rdmsr(MSR_CORE_PERF_FIXED_CTR0 + i); + + GUEST_ASSERT_NE(val, 0); + } + GUEST_DONE(); } static void test_fixed_counters(uint8_t pmu_version, uint64_t perf_capabilities, From b55e7adf633a8a13d5ede57b77509ea8fa157a56 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:41 -0800 Subject: [PATCH 146/814] KVM: selftests: Expand PMU counters test to verify LLC events Expand the PMU counters test to verify that LLC references and misses have non-zero counts when the code being executed while the LLC event(s) is active is evicted via CFLUSH{,OPT}. Note, CLFLUSH{,OPT} requires a fence of some kind to ensure the cache lines are flushed before execution continues. Use MFENCE for simplicity (performance is not a concern). Suggested-by: Jim Mattson Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-22-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index f5dedd112471..4c7133ddcda8 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -14,9 +14,9 @@ /* * Number of "extra" instructions that will be counted, i.e. the number of * instructions that are needed to set up the loop and then disabled the - * counter. 2 MOV, 2 XOR, 1 WRMSR. + * counter. 1 CLFLUSH/CLFLUSHOPT/NOP, 1 MFENCE, 2 MOV, 2 XOR, 1 WRMSR. */ -#define NUM_EXTRA_INSNS 5 +#define NUM_EXTRA_INSNS 7 #define NUM_INSNS_RETIRED (NUM_BRANCHES + NUM_EXTRA_INSNS) static uint8_t kvm_pmu_version; @@ -107,6 +107,12 @@ static void guest_assert_event_count(uint8_t idx, case INTEL_ARCH_BRANCHES_RETIRED_INDEX: GUEST_ASSERT_EQ(count, NUM_BRANCHES); break; + case INTEL_ARCH_LLC_REFERENCES_INDEX: + case INTEL_ARCH_LLC_MISSES_INDEX: + if (!this_cpu_has(X86_FEATURE_CLFLUSHOPT) && + !this_cpu_has(X86_FEATURE_CLFLUSH)) + break; + fallthrough; case INTEL_ARCH_CPU_CYCLES_INDEX: case INTEL_ARCH_REFERENCE_CYCLES_INDEX: GUEST_ASSERT_NE(count, 0); @@ -123,29 +129,44 @@ sanity_checks: GUEST_ASSERT_EQ(_rdpmc(pmc), 0xdead); } +/* + * Enable and disable the PMC in a monolithic asm blob to ensure that the + * compiler can't insert _any_ code into the measured sequence. Note, ECX + * doesn't need to be clobbered as the input value, @pmc_msr, is restored + * before the end of the sequence. + * + * If CLFUSH{,OPT} is supported, flush the cacheline containing (at least) the + * start of the loop to force LLC references and misses, i.e. to allow testing + * that those events actually count. + */ +#define GUEST_MEASURE_EVENT(_msr, _value, clflush) \ +do { \ + __asm__ __volatile__("wrmsr\n\t" \ + clflush "\n\t" \ + "mfence\n\t" \ + "1: mov $" __stringify(NUM_BRANCHES) ", %%ecx\n\t" \ + "loop .\n\t" \ + "mov %%edi, %%ecx\n\t" \ + "xor %%eax, %%eax\n\t" \ + "xor %%edx, %%edx\n\t" \ + "wrmsr\n\t" \ + :: "a"((uint32_t)_value), "d"(_value >> 32), \ + "c"(_msr), "D"(_msr) \ + ); \ +} while (0) + static void __guest_test_arch_event(uint8_t idx, struct kvm_x86_pmu_feature event, uint32_t pmc, uint32_t pmc_msr, uint32_t ctrl_msr, uint64_t ctrl_msr_value) { wrmsr(pmc_msr, 0); - /* - * Enable and disable the PMC in a monolithic asm blob to ensure that - * the compiler can't insert _any_ code into the measured sequence. - * Note, ECX doesn't need to be clobbered as the input value, @pmc_msr, - * is restored before the end of the sequence. - */ - __asm__ __volatile__("wrmsr\n\t" - "mov $" __stringify(NUM_BRANCHES) ", %%ecx\n\t" - "loop .\n\t" - "mov %%edi, %%ecx\n\t" - "xor %%eax, %%eax\n\t" - "xor %%edx, %%edx\n\t" - "wrmsr\n\t" - :: "a"((uint32_t)ctrl_msr_value), - "d"(ctrl_msr_value >> 32), - "c"(ctrl_msr), "D"(ctrl_msr) - ); + if (this_cpu_has(X86_FEATURE_CLFLUSHOPT)) + GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "clflushopt 1f"); + else if (this_cpu_has(X86_FEATURE_CLFLUSH)) + GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "clflush 1f"); + else + GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "nop"); guest_assert_event_count(idx, event, pmc, pmc_msr); } From c85e986716b03bccfec2e5a577cc1aab4f172ffd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:42 -0800 Subject: [PATCH 147/814] KVM: selftests: Add a helper to query if the PMU module param is enabled Add a helper to probe KVM's "enable_pmu" param, open coding strings in multiple places is just asking for false negatives and/or runtime errors due to typos. Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-23-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/x86_64/processor.h | 5 +++++ tools/testing/selftests/kvm/x86_64/pmu_counters_test.c | 2 +- tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 2 +- tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 92d4f8ecc730..ee082ae58f40 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1217,6 +1217,11 @@ static inline uint8_t xsetbv_safe(uint32_t index, uint64_t value) bool kvm_is_tdp_enabled(void); +static inline bool kvm_is_pmu_enabled(void) +{ + return get_kvm_param_bool("enable_pmu"); +} + uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr, int *level); uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 4c7133ddcda8..9e9dc4084c0d 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -545,7 +545,7 @@ static void test_intel_counters(void) int main(int argc, char *argv[]) { - TEST_REQUIRE(get_kvm_param_bool("enable_pmu")); + TEST_REQUIRE(kvm_is_pmu_enabled()); TEST_REQUIRE(host_cpu_is_intel); TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION)); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 7ec9fbed92e0..fa407e2ccb2f 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -867,7 +867,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu, *vcpu2 = NULL; struct kvm_vm *vm; - TEST_REQUIRE(get_kvm_param_bool("enable_pmu")); + TEST_REQUIRE(kvm_is_pmu_enabled()); TEST_REQUIRE(kvm_has_cap(KVM_CAP_PMU_EVENT_FILTER)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_PMU_EVENT_MASKED_EVENTS)); 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 2a8d4ac2f020..8ded194c5a6d 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 @@ -237,7 +237,7 @@ int main(int argc, char *argv[]) { union perf_capabilities host_cap; - TEST_REQUIRE(get_kvm_param_bool("enable_pmu")); + TEST_REQUIRE(kvm_is_pmu_enabled()); TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM)); TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION)); From 45e4755c39fc2df55f58ea893615a7d45a0fbcc8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:43 -0800 Subject: [PATCH 148/814] KVM: selftests: Add helpers to read integer module params Add helpers to read integer module params, which is painfully non-trivial because the pain of dealing with strings in C is exacerbated by the kernel inserting a newline. Don't bother differentiating between int, uint, short, etc. They all fit in an int, and KVM (thankfully) doesn't have any integer params larger than an int. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-24-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/kvm_util_base.h | 4 ++ tools/testing/selftests/kvm/lib/kvm_util.c | 62 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 9e5afc472c14..070f250036fc 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -259,6 +259,10 @@ bool get_kvm_param_bool(const char *param); bool get_kvm_intel_param_bool(const char *param); bool get_kvm_amd_param_bool(const char *param); +int get_kvm_param_integer(const char *param); +int get_kvm_intel_param_integer(const char *param); +int get_kvm_amd_param_integer(const char *param); + unsigned int kvm_check_cap(long cap); static inline bool kvm_has_cap(long cap) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e066d584c656..9bafe44cb978 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -51,13 +51,13 @@ int open_kvm_dev_path_or_exit(void) return _open_kvm_dev_path_or_exit(O_RDONLY); } -static bool get_module_param_bool(const char *module_name, const char *param) +static ssize_t get_module_param(const char *module_name, const char *param, + void *buffer, size_t buffer_size) { const int path_size = 128; char path[path_size]; - char value; - ssize_t r; - int fd; + ssize_t bytes_read; + int fd, r; r = snprintf(path, path_size, "/sys/module/%s/parameters/%s", module_name, param); @@ -66,11 +66,46 @@ static bool get_module_param_bool(const char *module_name, const char *param) fd = open_path_or_exit(path, O_RDONLY); - r = read(fd, &value, 1); - TEST_ASSERT(r == 1, "read(%s) failed", path); + bytes_read = read(fd, buffer, buffer_size); + TEST_ASSERT(bytes_read > 0, "read(%s) returned %ld, wanted %ld bytes", + path, bytes_read, buffer_size); r = close(fd); TEST_ASSERT(!r, "close(%s) failed", path); + return bytes_read; +} + +static int get_module_param_integer(const char *module_name, const char *param) +{ + /* + * 16 bytes to hold a 64-bit value (1 byte per char), 1 byte for the + * NUL char, and 1 byte because the kernel sucks and inserts a newline + * at the end. + */ + char value[16 + 1 + 1]; + ssize_t r; + + memset(value, '\0', sizeof(value)); + + r = get_module_param(module_name, param, value, sizeof(value)); + TEST_ASSERT(value[r - 1] == '\n', + "Expected trailing newline, got char '%c'", value[r - 1]); + + /* + * Squash the newline, otherwise atoi_paranoid() will complain about + * trailing non-NUL characters in the string. + */ + value[r - 1] = '\0'; + return atoi_paranoid(value); +} + +static bool get_module_param_bool(const char *module_name, const char *param) +{ + char value; + ssize_t r; + + r = get_module_param(module_name, param, &value, sizeof(value)); + TEST_ASSERT_EQ(r, 1); if (value == 'Y') return true; @@ -95,6 +130,21 @@ bool get_kvm_amd_param_bool(const char *param) return get_module_param_bool("kvm_amd", param); } +int get_kvm_param_integer(const char *param) +{ + return get_module_param_integer("kvm", param); +} + +int get_kvm_intel_param_integer(const char *param) +{ + return get_module_param_integer("kvm_intel", param); +} + +int get_kvm_amd_param_integer(const char *param) +{ + return get_module_param_integer("kvm_amd", param); +} + /* * Capability * From 0326cc6b02c8e099bb6631168791924be097e1d9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:44 -0800 Subject: [PATCH 149/814] KVM: selftests: Query module param to detect FEP in MSR filtering test Add a helper to detect KVM support for forced emulation by querying the module param, and use the helper to detect support for the MSR filtering test instead of throwing a noodle/NOP at KVM to see if it sticks. Cc: Aaron Lewis Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-25-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 5 ++++ .../kvm/x86_64/userspace_msr_exit_test.c | 27 +++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index ee082ae58f40..d211cea188be 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1222,6 +1222,11 @@ static inline bool kvm_is_pmu_enabled(void) return get_kvm_param_bool("enable_pmu"); } +static inline bool kvm_is_forced_emulation_enabled(void) +{ + return !!get_kvm_param_integer("force_emulation_prefix"); +} + uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr, int *level); uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr); diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index 3533dc2fbfee..9e12dbc47a72 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -14,8 +14,7 @@ /* Forced emulation prefix, used to invoke the emulator unconditionally. */ #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" -#define KVM_FEP_LENGTH 5 -static int fep_available = 1; +static bool fep_available; #define MSR_NON_EXISTENT 0x474f4f00 @@ -260,13 +259,6 @@ static void guest_code_filter_allow(void) GUEST_ASSERT(data == 2); GUEST_ASSERT(guest_exception_count == 0); - /* - * Test to see if the instruction emulator is available (ie: the module - * parameter 'kvm.force_emulation_prefix=1' is set). This instruction - * will #UD if it isn't available. - */ - __asm__ __volatile__(KVM_FEP "nop"); - if (fep_available) { /* Let userspace know we aren't done. */ GUEST_SYNC(0); @@ -388,12 +380,6 @@ static void guest_fep_gp_handler(struct ex_regs *regs) &em_wrmsr_start, &em_wrmsr_end); } -static void guest_ud_handler(struct ex_regs *regs) -{ - fep_available = 0; - regs->rip += KVM_FEP_LENGTH; -} - static void check_for_guest_assert(struct kvm_vcpu *vcpu) { struct ucall uc; @@ -531,9 +517,11 @@ static void test_msr_filter_allow(void) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; + uint64_t cmd; int rc; vm = vm_create_with_one_vcpu(&vcpu, guest_code_filter_allow); + sync_global_to_guest(vm, fep_available); rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); @@ -561,11 +549,11 @@ static void test_msr_filter_allow(void) run_guest_then_process_wrmsr(vcpu, MSR_NON_EXISTENT); run_guest_then_process_rdmsr(vcpu, MSR_NON_EXISTENT); - vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); vcpu_run(vcpu); - vm_install_exception_handler(vm, UD_VECTOR, NULL); + cmd = process_ucall(vcpu); - if (process_ucall(vcpu) != UCALL_DONE) { + if (fep_available) { + TEST_ASSERT_EQ(cmd, UCALL_SYNC); vm_install_exception_handler(vm, GP_VECTOR, guest_fep_gp_handler); /* Process emulated rdmsr and wrmsr instructions. */ @@ -583,6 +571,7 @@ static void test_msr_filter_allow(void) /* Confirm the guest completed without issues. */ run_guest_then_process_ucall_done(vcpu); } else { + TEST_ASSERT_EQ(cmd, UCALL_DONE); printf("To run the instruction emulated tests set the module parameter 'kvm.force_emulation_prefix=1'\n"); } @@ -804,6 +793,8 @@ static void test_user_exit_msr_flags(void) int main(int argc, char *argv[]) { + fep_available = kvm_is_forced_emulation_enabled(); + test_msr_filter_allow(); test_msr_filter_deny(); From 00856e17da730299205270234cda30628ae53b92 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:45 -0800 Subject: [PATCH 150/814] KVM: selftests: Move KVM_FEP macro into common library header Move the KVM_FEP definition, a.k.a. the KVM force emulation prefix, into processor.h so that it can be used for other tests besides the MSR filter test. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-26-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/x86_64/processor.h | 3 +++ tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index d211cea188be..6be365ac2a85 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -23,6 +23,9 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; +/* Forced emulation prefix, used to invoke the emulator unconditionally. */ +#define KVM_FEP "ud2; .byte 'k', 'v', 'm';" + #define NMI_VECTOR 0x02 #define X86_EFLAGS_FIXED (1u << 1) diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index 9e12dbc47a72..ab3a8c4f0b86 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -12,8 +12,6 @@ #include "kvm_util.h" #include "vmx.h" -/* Forced emulation prefix, used to invoke the emulator unconditionally. */ -#define KVM_FEP "ud2; .byte 'k', 'v', 'm';" static bool fep_available; #define MSR_NON_EXISTENT 0x474f4f00 From cd34fd8c758e968aae15944b1679c974af719648 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:46 -0800 Subject: [PATCH 151/814] KVM: selftests: Test PMC virtualization with forced emulation Extend the PMC counters test to use forced emulation to verify that KVM emulates counter events for instructions retired and branches retired. Force emulation for only a subset of the measured code to test that KVM does the right thing when mixing perf events with emulated events. Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-27-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 9e9dc4084c0d..cb808ac827ba 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -21,6 +21,7 @@ static uint8_t kvm_pmu_version; static bool kvm_has_perf_caps; +static bool is_forced_emulation_enabled; static struct kvm_vm *pmu_vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, void *guest_code, @@ -34,6 +35,7 @@ static struct kvm_vm *pmu_vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, vcpu_init_descriptor_tables(*vcpu); sync_global_to_guest(vm, kvm_pmu_version); + sync_global_to_guest(vm, is_forced_emulation_enabled); /* * Set PERF_CAPABILITIES before PMU version as KVM disallows enabling @@ -138,37 +140,50 @@ sanity_checks: * If CLFUSH{,OPT} is supported, flush the cacheline containing (at least) the * start of the loop to force LLC references and misses, i.e. to allow testing * that those events actually count. + * + * If forced emulation is enabled (and specified), force emulation on a subset + * of the measured code to verify that KVM correctly emulates instructions and + * branches retired events in conjunction with hardware also counting said + * events. */ -#define GUEST_MEASURE_EVENT(_msr, _value, clflush) \ +#define GUEST_MEASURE_EVENT(_msr, _value, clflush, FEP) \ do { \ __asm__ __volatile__("wrmsr\n\t" \ clflush "\n\t" \ "mfence\n\t" \ "1: mov $" __stringify(NUM_BRANCHES) ", %%ecx\n\t" \ - "loop .\n\t" \ - "mov %%edi, %%ecx\n\t" \ - "xor %%eax, %%eax\n\t" \ - "xor %%edx, %%edx\n\t" \ + FEP "loop .\n\t" \ + FEP "mov %%edi, %%ecx\n\t" \ + FEP "xor %%eax, %%eax\n\t" \ + FEP "xor %%edx, %%edx\n\t" \ "wrmsr\n\t" \ :: "a"((uint32_t)_value), "d"(_value >> 32), \ "c"(_msr), "D"(_msr) \ ); \ } while (0) +#define GUEST_TEST_EVENT(_idx, _event, _pmc, _pmc_msr, _ctrl_msr, _value, FEP) \ +do { \ + wrmsr(pmc_msr, 0); \ + \ + if (this_cpu_has(X86_FEATURE_CLFLUSHOPT)) \ + GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflushopt 1f", FEP); \ + else if (this_cpu_has(X86_FEATURE_CLFLUSH)) \ + GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflush 1f", FEP); \ + else \ + GUEST_MEASURE_EVENT(_ctrl_msr, _value, "nop", FEP); \ + \ + guest_assert_event_count(_idx, _event, _pmc, _pmc_msr); \ +} while (0) + static void __guest_test_arch_event(uint8_t idx, struct kvm_x86_pmu_feature event, uint32_t pmc, uint32_t pmc_msr, uint32_t ctrl_msr, uint64_t ctrl_msr_value) { - wrmsr(pmc_msr, 0); + GUEST_TEST_EVENT(idx, event, pmc, pmc_msr, ctrl_msr, ctrl_msr_value, ""); - if (this_cpu_has(X86_FEATURE_CLFLUSHOPT)) - GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "clflushopt 1f"); - else if (this_cpu_has(X86_FEATURE_CLFLUSH)) - GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "clflush 1f"); - else - GUEST_MEASURE_EVENT(ctrl_msr, ctrl_msr_value, "nop"); - - guest_assert_event_count(idx, event, pmc, pmc_msr); + if (is_forced_emulation_enabled) + GUEST_TEST_EVENT(idx, event, pmc, pmc_msr, ctrl_msr, ctrl_msr_value, KVM_FEP); } #define X86_PMU_FEATURE_NULL \ @@ -553,6 +568,7 @@ int main(int argc, char *argv[]) kvm_pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION); kvm_has_perf_caps = kvm_cpu_has(X86_FEATURE_PDCM); + is_forced_emulation_enabled = kvm_is_forced_emulation_enabled(); test_intel_counters(); From ab3b6a7de8df00b380fb66a523c79e3b387aa877 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:47 -0800 Subject: [PATCH 152/814] KVM: selftests: Add a forced emulation variation of KVM_ASM_SAFE() Add KVM_ASM_SAFE_FEP() to allow forcing emulation on an instruction that might fault. Note, KVM skips RIP past the FEP prefix before injecting an exception, i.e. the fixup needs to be on the instruction itself. Do not check for FEP support, that is firmly the responsibility of whatever code wants to use KVM_ASM_SAFE_FEP(). Sadly, chaining variadic arguments that contain commas doesn't work, thus the unfortunate amount of copy+paste. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-28-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 6be365ac2a85..fe891424ff55 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1154,16 +1154,19 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, * r9 = exception vector (non-zero) * r10 = error code */ -#define KVM_ASM_SAFE(insn) \ +#define __KVM_ASM_SAFE(insn, fep) \ "mov $" __stringify(KVM_EXCEPTION_MAGIC) ", %%r9\n\t" \ "lea 1f(%%rip), %%r10\n\t" \ "lea 2f(%%rip), %%r11\n\t" \ - "1: " insn "\n\t" \ + fep "1: " insn "\n\t" \ "xor %%r9, %%r9\n\t" \ "2:\n\t" \ "mov %%r9b, %[vector]\n\t" \ "mov %%r10, %[error_code]\n\t" +#define KVM_ASM_SAFE(insn) __KVM_ASM_SAFE(insn, "") +#define KVM_ASM_SAFE_FEP(insn) __KVM_ASM_SAFE(insn, KVM_FEP) + #define KVM_ASM_SAFE_OUTPUTS(v, ec) [vector] "=qm"(v), [error_code] "=rm"(ec) #define KVM_ASM_SAFE_CLOBBERS "r9", "r10", "r11" @@ -1190,6 +1193,29 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, vector; \ }) +#define kvm_asm_safe_fep(insn, inputs...) \ +({ \ + uint64_t ign_error_code; \ + uint8_t vector; \ + \ + asm volatile(KVM_ASM_SAFE(insn) \ + : KVM_ASM_SAFE_OUTPUTS(vector, ign_error_code) \ + : inputs \ + : KVM_ASM_SAFE_CLOBBERS); \ + vector; \ +}) + +#define kvm_asm_safe_ec_fep(insn, error_code, inputs...) \ +({ \ + uint8_t vector; \ + \ + asm volatile(KVM_ASM_SAFE_FEP(insn) \ + : KVM_ASM_SAFE_OUTPUTS(vector, error_code) \ + : inputs \ + : KVM_ASM_SAFE_CLOBBERS); \ + vector; \ +}) + static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val) { uint64_t error_code; From b5e66df34cb0de716859595ce7a4d9d1d015a695 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:48 -0800 Subject: [PATCH 153/814] KVM: selftests: Add helpers for safe and safe+forced RDMSR, RDPMC, and XGETBV Add helpers for safe and safe-with-forced-emulations versions of RDMSR, RDPMC, and XGETBV. Use macro shenanigans to eliminate the rather large amount of boilerplate needed to get values in and out of registers. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-29-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index fe891424ff55..abac816f6594 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1216,21 +1216,35 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, vector; \ }) -static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val) -{ - uint64_t error_code; - uint8_t vector; - uint32_t a, d; - - asm volatile(KVM_ASM_SAFE("rdmsr") - : "=a"(a), "=d"(d), KVM_ASM_SAFE_OUTPUTS(vector, error_code) - : "c"(msr) - : KVM_ASM_SAFE_CLOBBERS); - - *val = (uint64_t)a | ((uint64_t)d << 32); - return vector; +#define BUILD_READ_U64_SAFE_HELPER(insn, _fep, _FEP) \ +static inline uint8_t insn##_safe ##_fep(uint32_t idx, uint64_t *val) \ +{ \ + uint64_t error_code; \ + uint8_t vector; \ + uint32_t a, d; \ + \ + asm volatile(KVM_ASM_SAFE##_FEP(#insn) \ + : "=a"(a), "=d"(d), \ + KVM_ASM_SAFE_OUTPUTS(vector, error_code) \ + : "c"(idx) \ + : KVM_ASM_SAFE_CLOBBERS); \ + \ + *val = (uint64_t)a | ((uint64_t)d << 32); \ + return vector; \ } +/* + * Generate {insn}_safe() and {insn}_safe_fep() helpers for instructions that + * use ECX as in input index, and EDX:EAX as a 64-bit output. + */ +#define BUILD_READ_U64_SAFE_HELPERS(insn) \ + BUILD_READ_U64_SAFE_HELPER(insn, , ) \ + BUILD_READ_U64_SAFE_HELPER(insn, _fep, _FEP) \ + +BUILD_READ_U64_SAFE_HELPERS(rdmsr) +BUILD_READ_U64_SAFE_HELPERS(rdpmc) +BUILD_READ_U64_SAFE_HELPERS(xgetbv) + static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val) { return kvm_asm_safe("wrmsr", "a"(val & -1u), "d"(val >> 32), "c"(msr)); From a8a37f5556845b13be2df3d545e7245b574e0ff5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 15:02:49 -0800 Subject: [PATCH 154/814] KVM: selftests: Extend PMU counters test to validate RDPMC after WRMSR Extend the read/write PMU counters subtest to verify that RDPMC also reads back the written value. Opportunsitically verify that attempting to use the "fast" mode of RDPMC fails, as the "fast" flag is only supported by non-architectural PMUs, which KVM doesn't virtualize. Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20240109230250.424295-30-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/pmu_counters_test.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index cb808ac827ba..ae5f6042f1e8 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -325,9 +325,30 @@ __GUEST_ASSERT(expect_gp ? vector == GP_VECTOR : !vector, \ "Expected " #insn "(0x%x) to yield 0x%lx, got 0x%lx", \ msr, expected_val, val); +static void guest_test_rdpmc(uint32_t rdpmc_idx, bool expect_success, + uint64_t expected_val) +{ + uint8_t vector; + uint64_t val; + + vector = rdpmc_safe(rdpmc_idx, &val); + GUEST_ASSERT_PMC_MSR_ACCESS(RDPMC, rdpmc_idx, !expect_success, vector); + if (expect_success) + GUEST_ASSERT_PMC_VALUE(RDPMC, rdpmc_idx, val, expected_val); + + if (!is_forced_emulation_enabled) + return; + + vector = rdpmc_safe_fep(rdpmc_idx, &val); + GUEST_ASSERT_PMC_MSR_ACCESS(RDPMC, rdpmc_idx, !expect_success, vector); + if (expect_success) + GUEST_ASSERT_PMC_VALUE(RDPMC, rdpmc_idx, val, expected_val); +} + static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters, uint8_t nr_counters, uint32_t or_mask) { + const bool pmu_has_fast_mode = !guest_get_pmu_version(); uint8_t i; for (i = 0; i < nr_possible_counters; i++) { @@ -352,6 +373,7 @@ static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters const uint64_t expected_val = expect_success ? test_val : 0; const bool expect_gp = !expect_success && msr != MSR_P6_PERFCTR0 && msr != MSR_P6_PERFCTR1; + uint32_t rdpmc_idx; uint8_t vector; uint64_t val; @@ -365,6 +387,25 @@ static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters if (!expect_gp) GUEST_ASSERT_PMC_VALUE(RDMSR, msr, val, expected_val); + /* + * Redo the read tests with RDPMC, which has different indexing + * semantics and additional capabilities. + */ + rdpmc_idx = i; + if (base_msr == MSR_CORE_PERF_FIXED_CTR0) + rdpmc_idx |= INTEL_RDPMC_FIXED; + + guest_test_rdpmc(rdpmc_idx, expect_success, expected_val); + + /* + * KVM doesn't support non-architectural PMUs, i.e. it should + * impossible to have fast mode RDPMC. Verify that attempting + * to use fast RDPMC always #GPs. + */ + GUEST_ASSERT(!expect_success || !pmu_has_fast_mode); + rdpmc_idx |= INTEL_RDPMC_FAST; + guest_test_rdpmc(rdpmc_idx, false, -1ull); + vector = wrmsr_safe(msr, 0); GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector); } From a96fb711c6be76bcfbcf594a865002fa7c0eb525 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Jan 2024 21:32:28 -0800 Subject: [PATCH 155/814] Input: matrix_keypad - avoid repeatedly converting GPIO to IRQ There is no need to do conversion from GPIOs to interrupt numbers. Convert row GPIOs to interrupt numbers once in probe() and use this information when the driver needs to enable or disable given interrupt line. Link: https://lore.kernel.org/r/20240121053232.276968-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 48 ++++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 50fa764c82d2..1cd1ffb80401 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -27,6 +27,7 @@ struct matrix_keypad { const struct matrix_keypad_platform_data *pdata; struct input_dev *input_dev; unsigned int row_shift; + unsigned int row_irqs[MATRIX_MAX_ROWS]; DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); @@ -92,7 +93,7 @@ static void enable_row_irqs(struct matrix_keypad *keypad) enable_irq(pdata->clustered_irq); else { for (i = 0; i < pdata->num_row_gpios; i++) - enable_irq(gpio_to_irq(pdata->row_gpios[i])); + enable_irq(keypad->row_irqs[i]); } } @@ -105,7 +106,7 @@ static void disable_row_irqs(struct matrix_keypad *keypad) disable_irq_nosync(pdata->clustered_irq); else { for (i = 0; i < pdata->num_row_gpios; i++) - disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); + disable_irq_nosync(keypad->row_irqs[i]); } } @@ -233,7 +234,6 @@ static void matrix_keypad_stop(struct input_dev *dev) static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; - unsigned int gpio; int i; if (pdata->clustered_irq > 0) { @@ -241,21 +241,16 @@ static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) keypad->gpio_all_disabled = true; } else { - for (i = 0; i < pdata->num_row_gpios; i++) { - if (!test_bit(i, keypad->disabled_gpios)) { - gpio = pdata->row_gpios[i]; - - if (enable_irq_wake(gpio_to_irq(gpio)) == 0) + for (i = 0; i < pdata->num_row_gpios; i++) + if (!test_bit(i, keypad->disabled_gpios)) + if (enable_irq_wake(keypad->row_irqs[i]) == 0) __set_bit(i, keypad->disabled_gpios); - } - } } } static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; - unsigned int gpio; int i; if (pdata->clustered_irq > 0) { @@ -264,12 +259,9 @@ static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) keypad->gpio_all_disabled = false; } } else { - for (i = 0; i < pdata->num_row_gpios; i++) { - if (test_and_clear_bit(i, keypad->disabled_gpios)) { - gpio = pdata->row_gpios[i]; - disable_irq_wake(gpio_to_irq(gpio)); - } - } + for (i = 0; i < pdata->num_row_gpios; i++) + if (test_and_clear_bit(i, keypad->disabled_gpios)) + disable_irq_wake(keypad->row_irqs[i]); } } @@ -306,7 +298,7 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; - int i, err; + int i, irq, err; /* initialized strobe lines as outputs, activated */ for (i = 0; i < pdata->num_col_gpios; i++) { @@ -345,11 +337,19 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, } } else { for (i = 0; i < pdata->num_row_gpios; i++) { - err = request_any_context_irq( - gpio_to_irq(pdata->row_gpios[i]), + irq = gpio_to_irq(pdata->row_gpios[i]); + if (irq < 0) { + err = irq; + dev_err(&pdev->dev, + "Unable to convert GPIO line %i to irq: %d\n", + pdata->row_gpios[i], err); + goto err_free_irqs; + } + + err = request_any_context_irq(irq, matrix_keypad_interrupt, IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING, "matrix-keypad", keypad); if (err < 0) { dev_err(&pdev->dev, @@ -357,6 +357,8 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, pdata->row_gpios[i]); goto err_free_irqs; } + + keypad->row_irqs[i] = irq; } } @@ -366,7 +368,7 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, err_free_irqs: while (--i >= 0) - free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); + free_irq(keypad->row_irqs[i], keypad); i = pdata->num_row_gpios; err_free_rows: while (--i >= 0) @@ -388,7 +390,7 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) free_irq(pdata->clustered_irq, keypad); } else { for (i = 0; i < pdata->num_row_gpios; i++) - free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); + free_irq(keypad->row_irqs[i], keypad); } for (i = 0; i < pdata->num_row_gpios; i++) From 8cf4b3683a713a4b54d44565e8a32b4cca357084 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Jan 2024 21:32:29 -0800 Subject: [PATCH 156/814] Input: matrix_keypad - consolidate handling of clustered interrupt Now that the driver stores interrupt numbers corresponding to individual GPIOs in non-clustered mode, it is possible to unify handling of both modes by storing clustered interrupt at position 0 and setting the number of interrupts in this case to 1. Link: https://lore.kernel.org/r/20240121053232.276968-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 63 ++++++++------------------ 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 1cd1ffb80401..44ef600b8f19 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -27,9 +27,10 @@ struct matrix_keypad { const struct matrix_keypad_platform_data *pdata; struct input_dev *input_dev; unsigned int row_shift; - unsigned int row_irqs[MATRIX_MAX_ROWS]; - DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); + unsigned int row_irqs[MATRIX_MAX_ROWS]; + unsigned int num_row_irqs; + DECLARE_BITMAP(wakeup_enabled_irqs, MATRIX_MAX_ROWS); uint32_t last_key_state[MATRIX_MAX_COLS]; struct delayed_work work; @@ -86,28 +87,18 @@ static bool row_asserted(const struct matrix_keypad_platform_data *pdata, static void enable_row_irqs(struct matrix_keypad *keypad) { - const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; - if (pdata->clustered_irq > 0) - enable_irq(pdata->clustered_irq); - else { - for (i = 0; i < pdata->num_row_gpios; i++) - enable_irq(keypad->row_irqs[i]); - } + for (i = 0; i < keypad->num_row_irqs; i++) + enable_irq(keypad->row_irqs[i]); } static void disable_row_irqs(struct matrix_keypad *keypad) { - const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; - if (pdata->clustered_irq > 0) - disable_irq_nosync(pdata->clustered_irq); - else { - for (i = 0; i < pdata->num_row_gpios; i++) - disable_irq_nosync(keypad->row_irqs[i]); - } + for (i = 0; i < keypad->num_row_irqs; i++) + disable_irq_nosync(keypad->row_irqs[i]); } /* @@ -233,35 +224,20 @@ static void matrix_keypad_stop(struct input_dev *dev) static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) { - const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; - if (pdata->clustered_irq > 0) { - if (enable_irq_wake(pdata->clustered_irq) == 0) - keypad->gpio_all_disabled = true; - } else { - - for (i = 0; i < pdata->num_row_gpios; i++) - if (!test_bit(i, keypad->disabled_gpios)) - if (enable_irq_wake(keypad->row_irqs[i]) == 0) - __set_bit(i, keypad->disabled_gpios); - } + for_each_clear_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs) + if (enable_irq_wake(keypad->row_irqs[i]) == 0) + __set_bit(i, keypad->wakeup_enabled_irqs); } static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) { - const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; - if (pdata->clustered_irq > 0) { - if (keypad->gpio_all_disabled) { - disable_irq_wake(pdata->clustered_irq); - keypad->gpio_all_disabled = false; - } - } else { - for (i = 0; i < pdata->num_row_gpios; i++) - if (test_and_clear_bit(i, keypad->disabled_gpios)) - disable_irq_wake(keypad->row_irqs[i]); + for_each_set_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs) { + disable_irq_wake(keypad->row_irqs[i]); + __clear_bit(i, keypad->wakeup_enabled_irqs); } } @@ -335,6 +311,9 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, "Unable to acquire clustered interrupt\n"); goto err_free_rows; } + + keypad->row_irqs[0] = pdata->clustered_irq; + keypad->num_row_irqs = 1; } else { for (i = 0; i < pdata->num_row_gpios; i++) { irq = gpio_to_irq(pdata->row_gpios[i]); @@ -360,6 +339,8 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, keypad->row_irqs[i] = irq; } + + keypad->num_row_irqs = pdata->num_row_gpios; } /* initialized as disabled - enabled by input->open */ @@ -386,12 +367,8 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; - if (pdata->clustered_irq > 0) { - free_irq(pdata->clustered_irq, keypad); - } else { - for (i = 0; i < pdata->num_row_gpios; i++) - free_irq(keypad->row_irqs[i], keypad); - } + for (i = 0; i < keypad->num_row_irqs; i++) + free_irq(keypad->row_irqs[i], keypad); for (i = 0; i < pdata->num_row_gpios; i++) gpio_free(pdata->row_gpios[i]); From 7d0f351da46098b3bbb147f886f059473b84ff48 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Jan 2024 21:32:30 -0800 Subject: [PATCH 157/814] Input: matrix_keypad - switch to using managed resources Switch the drivers to use managed resources (devm) to simplify error handling and remove the need to have remove() implementation. Link: https://lore.kernel.org/r/20240121053232.276968-3-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 89 +++++++------------------- 1 file changed, 24 insertions(+), 65 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 44ef600b8f19..695c03e075b5 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -278,38 +278,41 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, /* initialized strobe lines as outputs, activated */ for (i = 0; i < pdata->num_col_gpios; i++) { - err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col"); + err = devm_gpio_request(&pdev->dev, + pdata->col_gpios[i], "matrix_kbd_col"); if (err) { dev_err(&pdev->dev, "failed to request GPIO%d for COL%d\n", pdata->col_gpios[i], i); - goto err_free_cols; + return err; } gpio_direction_output(pdata->col_gpios[i], !pdata->active_low); } for (i = 0; i < pdata->num_row_gpios; i++) { - err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row"); + err = devm_gpio_request(&pdev->dev, + pdata->row_gpios[i], "matrix_kbd_row"); if (err) { dev_err(&pdev->dev, "failed to request GPIO%d for ROW%d\n", pdata->row_gpios[i], i); - goto err_free_rows; + return err; } gpio_direction_input(pdata->row_gpios[i]); } if (pdata->clustered_irq > 0) { - err = request_any_context_irq(pdata->clustered_irq, + err = devm_request_any_context_irq(&pdev->dev, + pdata->clustered_irq, matrix_keypad_interrupt, pdata->clustered_irq_flags, "matrix-keypad", keypad); if (err < 0) { dev_err(&pdev->dev, "Unable to acquire clustered interrupt\n"); - goto err_free_rows; + return err; } keypad->row_irqs[0] = pdata->clustered_irq; @@ -322,10 +325,11 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, dev_err(&pdev->dev, "Unable to convert GPIO line %i to irq: %d\n", pdata->row_gpios[i], err); - goto err_free_irqs; + return err; } - err = request_any_context_irq(irq, + err = devm_request_any_context_irq(&pdev->dev, + irq, matrix_keypad_interrupt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -334,7 +338,7 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, dev_err(&pdev->dev, "Unable to acquire interrupt for GPIO line %i\n", pdata->row_gpios[i]); - goto err_free_irqs; + return err; } keypad->row_irqs[i] = irq; @@ -345,36 +349,8 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, /* initialized as disabled - enabled by input->open */ disable_row_irqs(keypad); + return 0; - -err_free_irqs: - while (--i >= 0) - free_irq(keypad->row_irqs[i], keypad); - i = pdata->num_row_gpios; -err_free_rows: - while (--i >= 0) - gpio_free(pdata->row_gpios[i]); - i = pdata->num_col_gpios; -err_free_cols: - while (--i >= 0) - gpio_free(pdata->col_gpios[i]); - - return err; -} - -static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) -{ - const struct matrix_keypad_platform_data *pdata = keypad->pdata; - int i; - - for (i = 0; i < keypad->num_row_irqs; i++) - free_irq(keypad->row_irqs[i], keypad); - - for (i = 0; i < pdata->num_row_gpios; i++) - gpio_free(pdata->row_gpios[i]); - - for (i = 0; i < pdata->num_col_gpios; i++) - gpio_free(pdata->col_gpios[i]); } #ifdef CONFIG_OF @@ -473,12 +449,13 @@ static int matrix_keypad_probe(struct platform_device *pdev) return -EINVAL; } - keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!keypad || !input_dev) { - err = -ENOMEM; - goto err_free_mem; - } + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; keypad->input_dev = input_dev; keypad->pdata = pdata; @@ -489,7 +466,6 @@ static int matrix_keypad_probe(struct platform_device *pdev) input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; - input_dev->dev.parent = &pdev->dev; input_dev->open = matrix_keypad_start; input_dev->close = matrix_keypad_stop; @@ -499,7 +475,7 @@ static int matrix_keypad_probe(struct platform_device *pdev) NULL, input_dev); if (err) { dev_err(&pdev->dev, "failed to build keymap\n"); - goto err_free_mem; + return -ENOMEM; } if (!pdata->no_autorepeat) @@ -509,32 +485,16 @@ static int matrix_keypad_probe(struct platform_device *pdev) err = matrix_keypad_init_gpio(pdev, keypad); if (err) - goto err_free_mem; + return err; err = input_register_device(keypad->input_dev); if (err) - goto err_free_gpio; + return err; device_init_wakeup(&pdev->dev, pdata->wakeup); platform_set_drvdata(pdev, keypad); return 0; - -err_free_gpio: - matrix_keypad_free_gpio(keypad); -err_free_mem: - input_free_device(input_dev); - kfree(keypad); - return err; -} - -static void matrix_keypad_remove(struct platform_device *pdev) -{ - struct matrix_keypad *keypad = platform_get_drvdata(pdev); - - matrix_keypad_free_gpio(keypad); - input_unregister_device(keypad->input_dev); - kfree(keypad); } #ifdef CONFIG_OF @@ -547,7 +507,6 @@ MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, - .remove_new = matrix_keypad_remove, .driver = { .name = "matrix-keypad", .pm = pm_sleep_ptr(&matrix_keypad_pm_ops), From d5b8fbee1e7264143c38740ebcdabb88475e0590 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 22 Jan 2024 15:15:00 -0600 Subject: [PATCH 158/814] MAINTAINERS: Drop Frank Rowand from DT maintainership Frank retired a while back and surprisingly has found better things to do than DT maintainership. Thank you Frank for all of your help with DT for many years. Link: https://lore.kernel.org/r/20240122211501.1719374-1-robh@kernel.org Signed-off-by: Rob Herring --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a69..eda745c0f92a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16359,7 +16359,6 @@ F: drivers/infiniband/ulp/opa_vnic OPEN FIRMWARE AND FLATTENED DEVICE TREE M: Rob Herring -M: Frank Rowand L: devicetree@vger.kernel.org S: Maintained W: http://www.devicetree.org/ From 442fd190d3471afdfd9ac8e067bc5e2aff88213c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 22 Jan 2024 15:15:26 -0600 Subject: [PATCH 159/814] MAINTAINERS: Drop my "+dt" sub-address I never really implemented any filtering on the "+dt" sub-address, so drop it. Acked-by: Wolfram Sang # for I2C Link: https://lore.kernel.org/r/20240122211528.1719994-1-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/gpio/mrvl-gpio.yaml | 2 +- Documentation/devicetree/bindings/i2c/i2c-pxa.yaml | 2 +- Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml | 2 +- Documentation/devicetree/bindings/timer/mrvl,mmp-timer.yaml | 2 +- MAINTAINERS | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.yaml b/Documentation/devicetree/bindings/gpio/mrvl-gpio.yaml index 9cf6137dd524..65155bb701a9 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.yaml @@ -9,7 +9,7 @@ title: Marvell PXA GPIO controller maintainers: - Linus Walleij - Bartosz Golaszewski - - Rob Herring + - Rob Herring allOf: - if: diff --git a/Documentation/devicetree/bindings/i2c/i2c-pxa.yaml b/Documentation/devicetree/bindings/i2c/i2c-pxa.yaml index 31386a8d7684..e89ee361741e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-pxa.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-pxa.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Marvell MMP I2C controller maintainers: - - Rob Herring + - Rob Herring allOf: - $ref: /schemas/i2c/i2c-controller.yaml# diff --git a/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml b/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml index a16c355dcd11..fcf52d2cac9e 100644 --- a/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml @@ -12,7 +12,7 @@ allOf: maintainers: - Alessandro Zummo - Alexandre Belloni - - Rob Herring + - Rob Herring properties: compatible: diff --git a/Documentation/devicetree/bindings/timer/mrvl,mmp-timer.yaml b/Documentation/devicetree/bindings/timer/mrvl,mmp-timer.yaml index 1ee4aab695d3..fe6bc4173789 100644 --- a/Documentation/devicetree/bindings/timer/mrvl,mmp-timer.yaml +++ b/Documentation/devicetree/bindings/timer/mrvl,mmp-timer.yaml @@ -9,7 +9,7 @@ title: Marvell MMP Timer maintainers: - Daniel Lezcano - Thomas Gleixner - - Rob Herring + - Rob Herring properties: $nodename: diff --git a/MAINTAINERS b/MAINTAINERS index eda745c0f92a..42b43337c266 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16358,7 +16358,7 @@ S: Supported F: drivers/infiniband/ulp/opa_vnic OPEN FIRMWARE AND FLATTENED DEVICE TREE -M: Rob Herring +M: Rob Herring L: devicetree@vger.kernel.org S: Maintained W: http://www.devicetree.org/ @@ -16374,7 +16374,7 @@ K: of_overlay_fdt_apply K: of_overlay_remove OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS -M: Rob Herring +M: Rob Herring M: Krzysztof Kozlowski M: Conor Dooley L: devicetree@vger.kernel.org From 85f838adad5487f96ff3acf6d3eb8263a39a0757 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 29 Jan 2024 13:18:53 +0100 Subject: [PATCH 160/814] dt-bindings: fpga: Convert fpga-region binding to yaml Convert the generic fpga region DT binding to json-schema. There are some differences compare to txt version. 1. DT overlay can't be described in example that's why directly include information from overlay to node which was referenced. It is visible in example with /* DT Overlay contains: &... */ 2. All example have been rewritten to be simpler and describe only full reconfiguration and partial reconfiguration with one bridge. Completely drop the case where fpga region can inside partial reconfiguration region which is already described in description 3. Fixed some typos in descriptions compare to txt version but most of it is just c&p from txt file. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/37b107d86b39ef4bc9c482b57b27de8b92c3fa43.1706530726.git.michal.simek@amd.com Signed-off-by: Rob Herring --- .../devicetree/bindings/fpga/fpga-region.txt | 479 ------------------ .../devicetree/bindings/fpga/fpga-region.yaml | 358 +++++++++++++ 2 files changed, 358 insertions(+), 479 deletions(-) delete mode 100644 Documentation/devicetree/bindings/fpga/fpga-region.txt create mode 100644 Documentation/devicetree/bindings/fpga/fpga-region.yaml diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt deleted file mode 100644 index 528df8a0e6d8..000000000000 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ /dev/null @@ -1,479 +0,0 @@ -FPGA Region Device Tree Binding - -Alan Tull 2016 - - CONTENTS - - Introduction - - Terminology - - Sequence - - FPGA Region - - Supported Use Models - - Device Tree Examples - - Constraints - - -Introduction -============ - -FPGA Regions represent FPGA's and partial reconfiguration regions of FPGA's in -the Device Tree. FPGA Regions provide a way to program FPGAs under device tree -control. - -This device tree binding document hits some of the high points of FPGA usage and -attempts to include terminology used by both major FPGA manufacturers. This -document isn't a replacement for any manufacturers specifications for FPGA -usage. - - -Terminology -=========== - -Full Reconfiguration - * The entire FPGA is programmed. - -Partial Reconfiguration (PR) - * A section of an FPGA is reprogrammed while the rest of the FPGA is not - affected. - * Not all FPGA's support PR. - -Partial Reconfiguration Region (PRR) - * Also called a "reconfigurable partition" - * A PRR is a specific section of an FPGA reserved for reconfiguration. - * A base (or static) FPGA image may create a set of PRR's that later may - be independently reprogrammed many times. - * The size and specific location of each PRR is fixed. - * The connections at the edge of each PRR are fixed. The image that is loaded - into a PRR must fit and must use a subset of the region's connections. - * The busses within the FPGA are split such that each region gets its own - branch that may be gated independently. - -Persona - * Also called a "partial bit stream" - * An FPGA image that is designed to be loaded into a PRR. There may be - any number of personas designed to fit into a PRR, but only one at at time - may be loaded. - * A persona may create more regions. - -FPGA Bridge - * FPGA Bridges gate bus signals between a host and FPGA. - * FPGA Bridges should be disabled while the FPGA is being programmed to - prevent spurious signals on the cpu bus and to the soft logic. - * FPGA bridges may be actual hardware or soft logic on an FPGA. - * During Full Reconfiguration, hardware bridges between the host and FPGA - will be disabled. - * During Partial Reconfiguration of a specific region, that region's bridge - will be used to gate the busses. Traffic to other regions is not affected. - * In some implementations, the FPGA Manager transparently handles gating the - buses, eliminating the need to show the hardware FPGA bridges in the - device tree. - * An FPGA image may create a set of reprogrammable regions, each having its - own bridge and its own split of the busses in the FPGA. - -FPGA Manager - * An FPGA Manager is a hardware block that programs an FPGA under the control - of a host processor. - -Base Image - * Also called the "static image" - * An FPGA image that is designed to do full reconfiguration of the FPGA. - * A base image may set up a set of partial reconfiguration regions that may - later be reprogrammed. - - ---------------- ---------------------------------- - | Host CPU | | FPGA | - | | | | - | ----| | ----------- -------- | - | | H | | |==>| Bridge0 |<==>| PRR0 | | - | | W | | | ----------- -------- | - | | | | | | - | | B |<=====>|<==| ----------- -------- | - | | R | | |==>| Bridge1 |<==>| PRR1 | | - | | I | | | ----------- -------- | - | | D | | | | - | | G | | | ----------- -------- | - | | E | | |==>| Bridge2 |<==>| PRR2 | | - | ----| | ----------- -------- | - | | | | - ---------------- ---------------------------------- - -Figure 1: An FPGA set up with a base image that created three regions. Each -region (PRR0-2) gets its own split of the busses that is independently gated by -a soft logic bridge (Bridge0-2) in the FPGA. The contents of each PRR can be -reprogrammed independently while the rest of the system continues to function. - - -Sequence -======== - -When a DT overlay that targets an FPGA Region is applied, the FPGA Region will -do the following: - - 1. Disable appropriate FPGA bridges. - 2. Program the FPGA using the FPGA manager. - 3. Enable the FPGA bridges. - 4. The Device Tree overlay is accepted into the live tree. - 5. Child devices are populated. - -When the overlay is removed, the child nodes will be removed and the FPGA Region -will disable the bridges. - - -FPGA Region -=========== - -FPGA Regions represent FPGA's and FPGA PR regions in the device tree. An FPGA -Region brings together the elements needed to program on a running system and -add the child devices: - - * FPGA Manager - * FPGA Bridges - * image-specific information needed to to the programming. - * child nodes - -The intended use is that a Device Tree overlay (DTO) can be used to reprogram an -FPGA while an operating system is running. - -An FPGA Region that exists in the live Device Tree reflects the current state. -If the live tree shows a "firmware-name" property or child nodes under an FPGA -Region, the FPGA already has been programmed. A DTO that targets an FPGA Region -and adds the "firmware-name" property is taken as a request to reprogram the -FPGA. After reprogramming is successful, the overlay is accepted into the live -tree. - -The base FPGA Region in the device tree represents the FPGA and supports full -reconfiguration. It must include a phandle to an FPGA Manager. The base -FPGA region will be the child of one of the hardware bridges (the bridge that -allows register access) between the cpu and the FPGA. If there are more than -one bridge to control during FPGA programming, the region will also contain a -list of phandles to the additional hardware FPGA Bridges. - -For partial reconfiguration (PR), each PR region will have an FPGA Region. -These FPGA regions are children of FPGA bridges which are then children of the -base FPGA region. The "Full Reconfiguration to add PRR's" example below shows -this. - -If an FPGA Region does not specify an FPGA Manager, it will inherit the FPGA -Manager specified by its ancestor FPGA Region. This supports both the case -where the same FPGA Manager is used for all of an FPGA as well the case where -a different FPGA Manager is used for each region. - -FPGA Regions do not inherit their ancestor FPGA regions' bridges. This prevents -shutting down bridges that are upstream from the other active regions while one -region is getting reconfigured (see Figure 1 above). During PR, the FPGA's -hardware bridges remain enabled. The PR regions' bridges will be FPGA bridges -within the static image of the FPGA. - -Required properties: -- compatible : should contain "fpga-region" -- fpga-mgr : should contain a phandle to an FPGA Manager. Child FPGA Regions - inherit this property from their ancestor regions. An fpga-mgr property - in a region will override any inherited FPGA manager. -- #address-cells, #size-cells, ranges : must be present to handle address space - mapping for child nodes. - -Optional properties: -- firmware-name : should contain the name of an FPGA image file located on the - firmware search path. If this property shows up in a live device tree - it indicates that the FPGA has already been programmed with this image. - If this property is in an overlay targeting an FPGA region, it is a - request to program the FPGA with that image. -- fpga-bridges : should contain a list of phandles to FPGA Bridges that must be - controlled during FPGA programming along with the parent FPGA bridge. - This property is optional if the FPGA Manager handles the bridges. - If the fpga-region is the child of an fpga-bridge, the list should not - contain the parent bridge. -- partial-fpga-config : boolean, set if partial reconfiguration is to be done, - otherwise full reconfiguration is done. -- external-fpga-config : boolean, set if the FPGA has already been configured - prior to OS boot up. -- encrypted-fpga-config : boolean, set if the bitstream is encrypted -- region-unfreeze-timeout-us : The maximum time in microseconds to wait for - bridges to successfully become enabled after the region has been - programmed. -- region-freeze-timeout-us : The maximum time in microseconds to wait for - bridges to successfully become disabled before the region has been - programmed. -- config-complete-timeout-us : The maximum time in microseconds time for the - FPGA to go to operating mode after the region has been programmed. -- child nodes : devices in the FPGA after programming. - -In the example below, when an overlay is applied targeting fpga-region0, -fpga_mgr is used to program the FPGA. Two bridges are controlled during -programming: the parent fpga_bridge0 and fpga_bridge1. Because the region is -the child of fpga_bridge0, only fpga_bridge1 needs to be specified in the -fpga-bridges property. During programming, these bridges are disabled, the -firmware specified in the overlay is loaded to the FPGA using the FPGA manager -specified in the region. If FPGA programming succeeds, the bridges are -reenabled and the overlay makes it into the live device tree. The child devices -are then populated. If FPGA programming fails, the bridges are left disabled -and the overlay is rejected. The overlay's ranges property maps the lwhps -bridge's region (0xff200000) and the hps bridge's region (0xc0000000) for use by -the two child devices. - -Example: -Base tree contains: - - fpga_mgr: fpga-mgr@ff706000 { - compatible = "altr,socfpga-fpga-mgr"; - reg = <0xff706000 0x1000 - 0xffb90000 0x20>; - interrupts = <0 175 4>; - }; - - fpga_bridge0: fpga-bridge@ff400000 { - compatible = "altr,socfpga-lwhps2fpga-bridge"; - reg = <0xff400000 0x100000>; - resets = <&rst LWHPS2FPGA_RESET>; - clocks = <&l4_main_clk>; - - #address-cells = <1>; - #size-cells = <1>; - ranges; - - fpga_region0: fpga-region0 { - compatible = "fpga-region"; - fpga-mgr = <&fpga_mgr>; - }; - }; - - fpga_bridge1: fpga-bridge@ff500000 { - compatible = "altr,socfpga-hps2fpga-bridge"; - reg = <0xff500000 0x10000>; - resets = <&rst HPS2FPGA_RESET>; - clocks = <&l4_main_clk>; - }; - -Overlay contains: - -/dts-v1/; -/plugin/; - -&fpga_region0 { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_system.rbf"; - fpga-bridges = <&fpga_bridge1>; - ranges = <0x20000 0xff200000 0x100000>, - <0x0 0xc0000000 0x20000000>; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - altr,ngpio = <4>; - #gpio-cells = <2>; - clocks = <2>; - gpio-controller; - }; - - onchip-memory { - device_type = "memory"; - compatible = "altr,onchipmem-15.1"; - reg = <0x0 0x10000>; - }; -}; - - -Supported Use Models -==================== - -In all cases the live DT must have the FPGA Manager, FPGA Bridges (if any), and -a FPGA Region. The target of the Device Tree Overlay is the FPGA Region. Some -uses are specific to an FPGA device. - - * No FPGA Bridges - In this case, the FPGA Manager which programs the FPGA also handles the - bridges behind the scenes. No FPGA Bridge devices are needed for full - reconfiguration. - - * Full reconfiguration with hardware bridges - In this case, there are hardware bridges between the processor and FPGA that - need to be controlled during full reconfiguration. Before the overlay is - applied, the live DT must include the FPGA Manager, FPGA Bridges, and a - FPGA Region. The FPGA Region is the child of the bridge that allows - register access to the FPGA. Additional bridges may be listed in a - fpga-bridges property in the FPGA region or in the device tree overlay. - - * Partial reconfiguration with bridges in the FPGA - In this case, the FPGA will have one or more PRR's that may be programmed - separately while the rest of the FPGA can remain active. To manage this, - bridges need to exist in the FPGA that can gate the buses going to each FPGA - region while the buses are enabled for other sections. Before any partial - reconfiguration can be done, a base FPGA image must be loaded which includes - PRR's with FPGA bridges. The device tree should have an FPGA region for each - PRR. - -Device Tree Examples -==================== - -The intention of this section is to give some simple examples, focusing on -the placement of the elements detailed above, especially: - * FPGA Manager - * FPGA Bridges - * FPGA Region - * ranges - * target-path or target - -For the purposes of this section, I'm dividing the Device Tree into two parts, -each with its own requirements. The two parts are: - * The live DT prior to the overlay being added - * The DT overlay - -The live Device Tree must contain an FPGA Region, an FPGA Manager, and any FPGA -Bridges. The FPGA Region's "fpga-mgr" property specifies the manager by phandle -to handle programming the FPGA. If the FPGA Region is the child of another FPGA -Region, the parent's FPGA Manager is used. If FPGA Bridges need to be involved, -they are specified in the FPGA Region by the "fpga-bridges" property. During -FPGA programming, the FPGA Region will disable the bridges that are in its -"fpga-bridges" list and will re-enable them after FPGA programming has -succeeded. - -The Device Tree Overlay will contain: - * "target-path" or "target" - The insertion point where the contents of the overlay will go into the - live tree. target-path is a full path, while target is a phandle. - * "ranges" - The address space mapping from processor to FPGA bus(ses). - * "firmware-name" - Specifies the name of the FPGA image file on the firmware search - path. The search path is described in the firmware class documentation. - * "partial-fpga-config" - This binding is a boolean and should be present if partial reconfiguration - is to be done. - * child nodes corresponding to hardware that will be loaded in this region of - the FPGA. - -Device Tree Example: Full Reconfiguration without Bridges -========================================================= - -Live Device Tree contains: - fpga_mgr0: fpga-mgr@f8007000 { - compatible = "xlnx,zynq-devcfg-1.0"; - reg = <0xf8007000 0x100>; - interrupt-parent = <&intc>; - interrupts = <0 8 4>; - clocks = <&clkc 12>; - clock-names = "ref_clk"; - syscon = <&slcr>; - }; - - fpga_region0: fpga-region0 { - compatible = "fpga-region"; - fpga-mgr = <&fpga_mgr0>; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - -DT Overlay contains: - -/dts-v1/; -/plugin/; - -&fpga_region0 { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "zynq-gpio.bin"; - - gpio1: gpio@40000000 { - compatible = "xlnx,xps-gpio-1.00.a"; - reg = <0x40000000 0x10000>; - gpio-controller; - #gpio-cells = <0x2>; - xlnx,gpio-width= <0x6>; - }; -}; - -Device Tree Example: Full Reconfiguration to add PRR's -====================================================== - -The base FPGA Region is specified similar to the first example above. - -This example programs the FPGA to have two regions that can later be partially -configured. Each region has its own bridge in the FPGA fabric. - -DT Overlay contains: - -/dts-v1/; -/plugin/; - -&fpga_region0 { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "base.rbf"; - - fpga-bridge@4400 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4400 0x10>; - - fpga_region1: fpga-region1 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; - - fpga-bridge@4420 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4420 0x10>; - - fpga_region2: fpga-region2 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; -}; - -Device Tree Example: Partial Reconfiguration -============================================ - -This example reprograms one of the PRR's set up in the previous example. - -The sequence that occurs when this overlay is similar to the above, the only -differences are that the FPGA is partially reconfigured due to the -"partial-fpga-config" boolean and the only bridge that is controlled during -programming is the FPGA based bridge of fpga_region1. - -/dts-v1/; -/plugin/; - -&fpga_region1 { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_image2.rbf"; - partial-fpga-config; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - clocks = <0x2>; - altr,ngpio = <0x4>; - #gpio-cells = <0x2>; - gpio-controller; - }; -}; - -Constraints -=========== - -It is beyond the scope of this document to fully describe all the FPGA design -constraints required to make partial reconfiguration work[1] [2] [3], but a few -deserve quick mention. - -A persona must have boundary connections that line up with those of the partition -or region it is designed to go into. - -During programming, transactions through those connections must be stopped and -the connections must be held at a fixed logic level. This can be achieved by -FPGA Bridges that exist on the FPGA fabric prior to the partial reconfiguration. - --- -[1] www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_partrecon.pdf -[2] tspace.library.utoronto.ca/bitstream/1807/67932/1/Byma_Stuart_A_201411_MAS_thesis.pdf -[3] https://www.xilinx.com/support/documentation/sw_manuals/xilinx14_1/ug702.pdf diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.yaml b/Documentation/devicetree/bindings/fpga/fpga-region.yaml new file mode 100644 index 000000000000..77554885a6c4 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/fpga-region.yaml @@ -0,0 +1,358 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/fpga-region.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: FPGA Region + +maintainers: + - Michal Simek + +description: | + CONTENTS + - Introduction + - Terminology + - Sequence + - FPGA Region + - Supported Use Models + - Constraints + + + Introduction + ============ + + FPGA Regions represent FPGA's and partial reconfiguration regions of FPGA's in + the Device Tree. FPGA Regions provide a way to program FPGAs under device tree + control. + + The documentation hits some of the high points of FPGA usage and + attempts to include terminology used by both major FPGA manufacturers. This + document isn't a replacement for any manufacturers specifications for FPGA + usage. + + + Terminology + =========== + + Full Reconfiguration + * The entire FPGA is programmed. + + Partial Reconfiguration (PR) + * A section of an FPGA is reprogrammed while the rest of the FPGA is not + affected. + * Not all FPGA's support PR. + + Partial Reconfiguration Region (PRR) + * Also called a "reconfigurable partition" + * A PRR is a specific section of an FPGA reserved for reconfiguration. + * A base (or static) FPGA image may create a set of PRR's that later may + be independently reprogrammed many times. + * The size and specific location of each PRR is fixed. + * The connections at the edge of each PRR are fixed. The image that is loaded + into a PRR must fit and must use a subset of the region's connections. + * The busses within the FPGA are split such that each region gets its own + branch that may be gated independently. + + Persona + * Also called a "partial bit stream" + * An FPGA image that is designed to be loaded into a PRR. There may be + any number of personas designed to fit into a PRR, but only one at a time + may be loaded. + * A persona may create more regions. + + FPGA Bridge + * FPGA Bridges gate bus signals between a host and FPGA. + * FPGA Bridges should be disabled while the FPGA is being programmed to + prevent spurious signals on the cpu bus and to the soft logic. + * FPGA bridges may be actual hardware or soft logic on an FPGA. + * During Full Reconfiguration, hardware bridges between the host and FPGA + will be disabled. + * During Partial Reconfiguration of a specific region, that region's bridge + will be used to gate the busses. Traffic to other regions is not affected. + * In some implementations, the FPGA Manager transparently handles gating the + buses, eliminating the need to show the hardware FPGA bridges in the + device tree. + * An FPGA image may create a set of reprogrammable regions, each having its + own bridge and its own split of the busses in the FPGA. + + FPGA Manager + * An FPGA Manager is a hardware block that programs an FPGA under the control + of a host processor. + + Base Image + * Also called the "static image" + * An FPGA image that is designed to do full reconfiguration of the FPGA. + * A base image may set up a set of partial reconfiguration regions that may + later be reprogrammed. + + ---------------- ---------------------------------- + | Host CPU | | FPGA | + | | | | + | ----| | ----------- -------- | + | | H | | |==>| Bridge0 |<==>| PRR0 | | + | | W | | | ----------- -------- | + | | | | | | + | | B |<=====>|<==| ----------- -------- | + | | R | | |==>| Bridge1 |<==>| PRR1 | | + | | I | | | ----------- -------- | + | | D | | | | + | | G | | | ----------- -------- | + | | E | | |==>| Bridge2 |<==>| PRR2 | | + | ----| | ----------- -------- | + | | | | + ---------------- ---------------------------------- + + Figure 1: An FPGA set up with a base image that created three regions. Each + region (PRR0-2) gets its own split of the busses that is independently gated by + a soft logic bridge (Bridge0-2) in the FPGA. The contents of each PRR can be + reprogrammed independently while the rest of the system continues to function. + + + Sequence + ======== + + When a DT overlay that targets an FPGA Region is applied, the FPGA Region will + do the following: + + 1. Disable appropriate FPGA bridges. + 2. Program the FPGA using the FPGA manager. + 3. Enable the FPGA bridges. + 4. The Device Tree overlay is accepted into the live tree. + 5. Child devices are populated. + + When the overlay is removed, the child nodes will be removed and the FPGA Region + will disable the bridges. + + + FPGA Region + =========== + + FPGA Regions represent FPGA's and FPGA PR regions in the device tree. An FPGA + Region brings together the elements needed to program on a running system and + add the child devices: + + * FPGA Manager + * FPGA Bridges + * image-specific information needed to the programming. + * child nodes + + The intended use is that a Device Tree overlay (DTO) can be used to reprogram an + FPGA while an operating system is running. + + An FPGA Region that exists in the live Device Tree reflects the current state. + If the live tree shows a "firmware-name" property or child nodes under an FPGA + Region, the FPGA already has been programmed. A DTO that targets an FPGA Region + and adds the "firmware-name" property is taken as a request to reprogram the + FPGA. After reprogramming is successful, the overlay is accepted into the live + tree. + + The base FPGA Region in the device tree represents the FPGA and supports full + reconfiguration. It must include a phandle to an FPGA Manager. The base + FPGA region will be the child of one of the hardware bridges (the bridge that + allows register access) between the cpu and the FPGA. If there are more than + one bridge to control during FPGA programming, the region will also contain a + list of phandles to the additional hardware FPGA Bridges. + + For partial reconfiguration (PR), each PR region will have an FPGA Region. + These FPGA regions are children of FPGA bridges which are then children of the + base FPGA region. The "Full Reconfiguration to add PRR's" example below shows + this. + + If an FPGA Region does not specify an FPGA Manager, it will inherit the FPGA + Manager specified by its ancestor FPGA Region. This supports both the case + where the same FPGA Manager is used for all of an FPGA as well the case where + a different FPGA Manager is used for each region. + + FPGA Regions do not inherit their ancestor FPGA regions' bridges. This prevents + shutting down bridges that are upstream from the other active regions while one + region is getting reconfigured (see Figure 1 above). During PR, the FPGA's + hardware bridges remain enabled. The PR regions' bridges will be FPGA bridges + within the static image of the FPGA. + + + Supported Use Models + ==================== + + In all cases the live DT must have the FPGA Manager, FPGA Bridges (if any), and + a FPGA Region. The target of the Device Tree Overlay is the FPGA Region. Some + uses are specific to an FPGA device. + + * No FPGA Bridges + In this case, the FPGA Manager which programs the FPGA also handles the + bridges behind the scenes. No FPGA Bridge devices are needed for full + reconfiguration. + + * Full reconfiguration with hardware bridges + In this case, there are hardware bridges between the processor and FPGA that + need to be controlled during full reconfiguration. Before the overlay is + applied, the live DT must include the FPGA Manager, FPGA Bridges, and a + FPGA Region. The FPGA Region is the child of the bridge that allows + register access to the FPGA. Additional bridges may be listed in a + fpga-bridges property in the FPGA region or in the device tree overlay. + + * Partial reconfiguration with bridges in the FPGA + In this case, the FPGA will have one or more PRR's that may be programmed + separately while the rest of the FPGA can remain active. To manage this, + bridges need to exist in the FPGA that can gate the buses going to each FPGA + region while the buses are enabled for other sections. Before any partial + reconfiguration can be done, a base FPGA image must be loaded which includes + PRR's with FPGA bridges. The device tree should have an FPGA region for each + PRR. + + Constraints + =========== + + It is beyond the scope of this document to fully describe all the FPGA design + constraints required to make partial reconfiguration work[1] [2] [3], but a few + deserve quick mention. + + A persona must have boundary connections that line up with those of the partition + or region it is designed to go into. + + During programming, transactions through those connections must be stopped and + the connections must be held at a fixed logic level. This can be achieved by + FPGA Bridges that exist on the FPGA fabric prior to the partial reconfiguration. + + -- + [1] www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_partrecon.pdf + [2] tspace.library.utoronto.ca/bitstream/1807/67932/1/Byma_Stuart_A_201411_MAS_thesis.pdf + [3] https://www.xilinx.com/support/documentation/sw_manuals/xilinx14_1/ug702.pdf + +properties: + $nodename: + pattern: "^fpga-region(@.*|-([0-9]|[1-9][0-9]+))?$" + + compatible: + const: fpga-region + + reg: + maxItems: 1 + + ranges: true + "#address-cells": true + "#size-cells": true + + config-complete-timeout-us: + description: + The maximum time in microseconds time for the FPGA to go to operating + mode after the region has been programmed. + + encrypted-fpga-config: + type: boolean + description: + Set if the bitstream is encrypted. + + external-fpga-config: + type: boolean + description: + Set if the FPGA has already been configured prior to OS boot up. + + firmware-name: + maxItems: 1 + description: + Should contain the name of an FPGA image file located on the firmware + search path. If this property shows up in a live device tree it indicates + that the FPGA has already been programmed with this image. + If this property is in an overlay targeting an FPGA region, it is + a request to program the FPGA with that image. + + fpga-bridges: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Should contain a list of phandles to FPGA Bridges that must be + controlled during FPGA programming along with the parent FPGA bridge. + This property is optional if the FPGA Manager handles the bridges. + If the fpga-region is the child of an fpga-bridge, the list should not + contain the parent bridge. + + fpga-mgr: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Should contain a phandle to an FPGA Manager. Child FPGA Regions + inherit this property from their ancestor regions. An fpga-mgr property + in a region will override any inherited FPGA manager. + + partial-fpga-config: + type: boolean + description: + Set if partial reconfiguration is to be done, otherwise full + reconfiguration is done. + + region-freeze-timeout-us: + description: + The maximum time in microseconds to wait for bridges to successfully + become disabled before the region has been programmed. + + region-unfreeze-timeout-us: + description: + The maximum time in microseconds to wait for bridges to successfully + become enabled after the region has been programmed. + +required: + - compatible + - fpga-mgr + +additionalProperties: + type: object + +examples: + - | + /* + * Full Reconfiguration without Bridges with DT overlay + */ + fpga_region0: fpga-region@0 { + compatible = "fpga-region"; + reg = <0 0>; + #address-cells = <1>; + #size-cells = <1>; + fpga-mgr = <&fpga_mgr0>; + ranges = <0x10000000 0x20000000 0x10000000>; + + /* DT Overlay contains: &fpga_region0 */ + firmware-name = "zynq-gpio.bin"; + gpio@40000000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0x40000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + - | + /* + * Partial reconfiguration with bridge + */ + fpga_region1: fpga-region@0 { + compatible = "fpga-region"; + reg = <0 0>; + ranges; + #address-cells = <1>; + #size-cells = <1>; + fpga-mgr = <&fpga_mgr1>; + fpga-bridges = <&fpga_bridge1>; + partial-fpga-config; + + /* DT Overlay contains: &fpga_region1 */ + firmware-name = "zynq-gpio-partial.bin"; + clk: clock { + compatible = "fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + gpio@40000000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0x40000000 0x10000>; + #gpio-cells = <2>; + gpio-controller; + clocks = <&clk>; + }; + }; + }; From 0dbd054699661dfffbc1c148664f8d03fd132569 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 16 Jan 2024 18:00:25 +0800 Subject: [PATCH 161/814] KVM: x86/mmu: Use KMEM_CACHE instead of kmem_cache_create() Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Note, KMEM_CACHE() uses the required alignment of the struct, '8' as the alignment, whereas KVM's existing code passes '0'. In the end, the two values yield the same result as x86's minimum slab alignment is also '8' (which is not at all coincidental). Signed-off-by: Kunwu Chan Link: https://lore.kernel.org/r/20240116100025.95702-1-chentao@kylinos.cn [sean: call out alignment behavior] Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2d6cdeab1f8a..3c193b096b45 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6997,9 +6997,7 @@ int kvm_mmu_vendor_module_init(void) kvm_mmu_reset_all_pte_masks(); - pte_list_desc_cache = kmem_cache_create("pte_list_desc", - sizeof(struct pte_list_desc), - 0, SLAB_ACCOUNT, NULL); + pte_list_desc_cache = KMEM_CACHE(pte_list_desc, SLAB_ACCOUNT); if (!pte_list_desc_cache) goto out; From f933b88e20150f15787390e2a1754a7e412754ed Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:48 -0800 Subject: [PATCH 162/814] KVM: x86/pmu: Zero out PMU metadata on AMD if PMU is disabled Move the purging of common PMU metadata from intel_pmu_refresh() to kvm_pmu_refresh(), and invoke the vendor refresh() hook if and only if the VM is supposed to have a vPMU. KVM already denies access to the PMU based on kvm->arch.enable_pmu, as get_gp_pmc_amd() returns NULL for all PMCs in that case, i.e. KVM already violates AMD's architecture by not virtualizing a PMU (kernels have long since learned to not panic when the PMU is unavailable). But configuring the PMU as if it were enabled causes unwanted side effects, e.g. calls to kvm_pmu_trigger_event() waste an absurd number of cycles due to the all_valid_pmc_idx bitmap being non-zero. Fixes: b1d66dad65dc ("KVM: x86/svm: Add module param to control PMU virtualization") Reported-by: Konstantin Khorenko Closes: https://lore.kernel.org/all/20231109180646.2963718-2-khorenko@virtuozzo.com Link: https://lore.kernel.org/r/20231110022857.1273836-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 20 ++++++++++++++++++-- arch/x86/kvm/vmx/pmu_intel.c | 16 ++-------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 09b0feb975c3..4d4366c6f7cd 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -749,6 +749,8 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu) */ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) { + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); + if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm)) return; @@ -758,8 +760,22 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) */ kvm_pmu_reset(vcpu); - bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX); - static_call(kvm_x86_pmu_refresh)(vcpu); + pmu->version = 0; + pmu->nr_arch_gp_counters = 0; + pmu->nr_arch_fixed_counters = 0; + pmu->counter_bitmask[KVM_PMC_GP] = 0; + pmu->counter_bitmask[KVM_PMC_FIXED] = 0; + pmu->reserved_bits = 0xffffffff00200000ull; + pmu->raw_event_mask = X86_RAW_EVENT_MASK; + pmu->global_ctrl_mask = ~0ull; + pmu->global_status_mask = ~0ull; + pmu->fixed_ctr_ctrl_mask = ~0ull; + pmu->pebs_enable_mask = ~0ull; + pmu->pebs_data_cfg_mask = ~0ull; + bitmap_zero(pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX); + + if (vcpu->kvm->arch.enable_pmu) + static_call(kvm_x86_pmu_refresh)(vcpu); } void kvm_pmu_init(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index b41bdb0a0995..a87f4725a9be 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -471,19 +471,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) u64 counter_mask; int i; - pmu->nr_arch_gp_counters = 0; - pmu->nr_arch_fixed_counters = 0; - pmu->counter_bitmask[KVM_PMC_GP] = 0; - pmu->counter_bitmask[KVM_PMC_FIXED] = 0; - pmu->version = 0; - pmu->reserved_bits = 0xffffffff00200000ull; - pmu->raw_event_mask = X86_RAW_EVENT_MASK; - pmu->global_ctrl_mask = ~0ull; - pmu->global_status_mask = ~0ull; - pmu->fixed_ctr_ctrl_mask = ~0ull; - pmu->pebs_enable_mask = ~0ull; - pmu->pebs_data_cfg_mask = ~0ull; - memset(&lbr_desc->records, 0, sizeof(lbr_desc->records)); /* @@ -495,8 +482,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) return; entry = kvm_find_cpuid_entry(vcpu, 0xa); - if (!entry || !vcpu->kvm->arch.enable_pmu) + if (!entry) return; + eax.full = entry->eax; edx.full = entry->edx; From be6b067dae1573cf4d53c8b08175d8872d82f030 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:49 -0800 Subject: [PATCH 163/814] KVM: x86/pmu: Add common define to capture fixed counters offset Add a common define to "officially" solidify KVM's split of counters, i.e. to commit to using bits 31:0 to track general purpose counters and bits 63:32 to track fixed counters (which only Intel supports). KVM already bleeds this behavior all over common PMU code, and adding a KVM- defined macro allows clarifying that the value is a _base_, as oppposed to the _flag_ that is used to access fixed PMCs via RDPMC (which perf confusingly calls INTEL_PMC_FIXED_RDPMC_BASE). No functional change intended. Link: https://lore.kernel.org/r/20231110022857.1273836-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 8 ++++---- arch/x86/kvm/pmu.h | 4 +++- arch/x86/kvm/vmx/pmu_intel.c | 12 ++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 4d4366c6f7cd..67d589ac9363 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -67,7 +67,7 @@ static const struct x86_cpu_id vmx_pebs_pdist_cpu[] = { * all perf counters (both gp and fixed). The mapping relationship * between pmc and perf counters is as the following: * * Intel: [0 .. KVM_INTEL_PMC_MAX_GENERIC-1] <=> gp counters - * [INTEL_PMC_IDX_FIXED .. INTEL_PMC_IDX_FIXED + 2] <=> fixed + * [KVM_FIXED_PMC_BASE_IDX .. KVM_FIXED_PMC_BASE_IDX + 2] <=> fixed * * AMD: [0 .. AMD64_NUM_COUNTERS-1] and, for families 15H * and later, [0 .. AMD64_NUM_COUNTERS_CORE-1] <=> gp counters */ @@ -411,7 +411,7 @@ static bool is_gp_event_allowed(struct kvm_x86_pmu_event_filter *f, static bool is_fixed_event_allowed(struct kvm_x86_pmu_event_filter *filter, int idx) { - int fixed_idx = idx - INTEL_PMC_IDX_FIXED; + int fixed_idx = idx - KVM_FIXED_PMC_BASE_IDX; if (filter->action == KVM_PMU_EVENT_DENY && test_bit(fixed_idx, (ulong *)&filter->fixed_counter_bitmap)) @@ -465,7 +465,7 @@ static void reprogram_counter(struct kvm_pmc *pmc) if (pmc_is_fixed(pmc)) { fixed_ctr_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, - pmc->idx - INTEL_PMC_IDX_FIXED); + pmc->idx - KVM_FIXED_PMC_BASE_IDX); if (fixed_ctr_ctrl & 0x1) eventsel |= ARCH_PERFMON_EVENTSEL_OS; if (fixed_ctr_ctrl & 0x2) @@ -841,7 +841,7 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) select_user = config & ARCH_PERFMON_EVENTSEL_USR; } else { config = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl, - pmc->idx - INTEL_PMC_IDX_FIXED); + pmc->idx - KVM_FIXED_PMC_BASE_IDX); select_os = config & 0x1; select_user = config & 0x2; } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 51bbb01b21c8..e8c6a1f4b8e8 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -18,6 +18,8 @@ #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 +#define KVM_FIXED_PMC_BASE_IDX INTEL_PMC_IDX_FIXED + struct kvm_pmu_ops { struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx); struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, @@ -130,7 +132,7 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) if (pmc_is_fixed(pmc)) return fixed_ctrl_field(pmu->fixed_ctr_ctrl, - pmc->idx - INTEL_PMC_IDX_FIXED) & 0x3; + pmc->idx - KVM_FIXED_PMC_BASE_IDX) & 0x3; return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE; } diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index a87f4725a9be..fe7a2ba51e1b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -50,18 +50,18 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); - __set_bit(INTEL_PMC_IDX_FIXED + i, pmu->pmc_in_use); + __set_bit(KVM_FIXED_PMC_BASE_IDX + i, pmu->pmc_in_use); kvm_pmu_request_counter_reprogram(pmc); } } static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) { - if (pmc_idx < INTEL_PMC_IDX_FIXED) { + if (pmc_idx < KVM_FIXED_PMC_BASE_IDX) { return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx, MSR_P6_EVNTSEL0); } else { - u32 idx = pmc_idx - INTEL_PMC_IDX_FIXED; + u32 idx = pmc_idx - KVM_FIXED_PMC_BASE_IDX; return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0); } @@ -516,7 +516,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) for (i = 0; i < pmu->nr_arch_fixed_counters; i++) pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4)); counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) | - (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED)); + (((1ull << pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX)); pmu->global_ctrl_mask = counter_mask; /* @@ -560,7 +560,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { pmu->fixed_ctr_ctrl_mask &= - ~(1ULL << (INTEL_PMC_IDX_FIXED + i * 4)); + ~(1ULL << (KVM_FIXED_PMC_BASE_IDX + i * 4)); } pmu->pebs_data_cfg_mask = ~0xff00000full; } else { @@ -586,7 +586,7 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) for (i = 0; i < KVM_PMC_MAX_FIXED; i++) { pmu->fixed_counters[i].type = KVM_PMC_FIXED; pmu->fixed_counters[i].vcpu = vcpu; - pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED; + pmu->fixed_counters[i].idx = i + KVM_FIXED_PMC_BASE_IDX; pmu->fixed_counters[i].current_config = 0; pmu->fixed_counters[i].eventsel = intel_get_fixed_pmc_eventsel(i); } From b31880ca2f41dc2196e31d97e498b0fa884c2b2a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:50 -0800 Subject: [PATCH 164/814] KVM: x86/pmu: Move pmc_idx => pmc translation helper to common code Add a common helper for *internal* PMC lookups, and delete the ops hook and Intel's implementation. Keep AMD's implementation, but rename it to amd_pmu_get_pmc() to make it somewhat more obvious that it's suited for both KVM-internal and guest-initiated lookups. Because KVM tracks all counters in a single bitmap, getting a counter when iterating over a bitmap, e.g. of all valid PMCs, requires a small amount of math, that while simple, isn't super obvious and doesn't use the same semantics as PMC lookups from RDPMC! Although AMD doesn't support fixed counters, the common PMU code still behaves as if there a split, the high half of which just happens to always be empty. Opportunstically add a comment to explain both what is going on, and why KVM uses a single bitmap, e.g. the boilerplate for iterating over separate bitmaps could be done via macros, so it's not (just) about deduplicating code. Link: https://lore.kernel.org/r/20231110022857.1273836-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 - arch/x86/kvm/pmu.c | 8 +++---- arch/x86/kvm/pmu.h | 29 +++++++++++++++++++++++++- arch/x86/kvm/svm/pmu.c | 7 +++---- arch/x86/kvm/vmx/pmu_intel.c | 15 +------------ 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index f0cd48222133..f852b13aeefe 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -12,7 +12,6 @@ BUILD_BUG_ON(1) * a NULL definition, for example if "static_call_cond()" will be used * at the call sites. */ -KVM_X86_PMU_OP(pmc_idx_to_pmc) KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) KVM_X86_PMU_OP(msr_idx_to_pmc) KVM_X86_PMU_OP_OPTIONAL(check_rdpmc_early) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 67d589ac9363..0873937c90bc 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -505,7 +505,7 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) int bit; for_each_set_bit(bit, pmu->reprogram_pmi, X86_PMC_IDX_MAX) { - struct kvm_pmc *pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, bit); + struct kvm_pmc *pmc = kvm_pmc_idx_to_pmc(pmu, bit); if (unlikely(!pmc)) { clear_bit(bit, pmu->reprogram_pmi); @@ -725,7 +725,7 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu) bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX); for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { - pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); + pmc = kvm_pmc_idx_to_pmc(pmu, i); if (!pmc) continue; @@ -801,7 +801,7 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu) pmu->pmc_in_use, X86_PMC_IDX_MAX); for_each_set_bit(i, bitmask, X86_PMC_IDX_MAX) { - pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); + pmc = kvm_pmc_idx_to_pmc(pmu, i); if (pmc && pmc->perf_event && !pmc_speculative_in_use(pmc)) pmc_stop_counter(pmc); @@ -856,7 +856,7 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) int i; for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { - pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); + pmc = kvm_pmc_idx_to_pmc(pmu, i); if (!pmc || !pmc_event_is_allowed(pmc)) continue; diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index e8c6a1f4b8e8..56e8e665e1af 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -4,6 +4,8 @@ #include +#include + #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu) @@ -21,7 +23,6 @@ #define KVM_FIXED_PMC_BASE_IDX INTEL_PMC_IDX_FIXED struct kvm_pmu_ops { - struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx); struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr); @@ -56,6 +57,32 @@ static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu) return pmu->version > 1; } +/* + * KVM tracks all counters in 64-bit bitmaps, with general purpose counters + * mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0 + * is tracked internally via index 32. On Intel, (AMD doesn't support fixed + * counters), this mirrors how fixed counters are mapped to PERF_GLOBAL_CTRL + * and similar MSRs, i.e. tracking fixed counters at base index 32 reduces the + * amounter of boilerplate needed to iterate over PMCs *and* simplifies common + * enabling/disable/reset operations. + * + * WARNING! This helper is only for lookups that are initiated by KVM, it is + * NOT safe for guest lookups, e.g. will do the wrong thing if passed a raw + * ECX value from RDPMC (fixed counters are accessed by setting bit 30 in ECX + * for RDPMC, not by adding 32 to the fixed counter index). + */ +static inline struct kvm_pmc *kvm_pmc_idx_to_pmc(struct kvm_pmu *pmu, int idx) +{ + if (idx < pmu->nr_arch_gp_counters) + return &pmu->gp_counters[idx]; + + idx -= KVM_FIXED_PMC_BASE_IDX; + if (idx >= 0 && idx < pmu->nr_arch_fixed_counters) + return &pmu->fixed_counters[idx]; + + return NULL; +} + static inline u64 pmc_bitmask(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index e886300f0f97..dfcc38bd97d3 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -25,7 +25,7 @@ enum pmu_type { PMU_TYPE_EVNTSEL, }; -static struct kvm_pmc *amd_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) +static struct kvm_pmc *amd_pmu_get_pmc(struct kvm_pmu *pmu, int pmc_idx) { unsigned int num_counters = pmu->nr_arch_gp_counters; @@ -70,7 +70,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, return NULL; } - return amd_pmc_idx_to_pmc(pmu, idx); + return amd_pmu_get_pmc(pmu, idx); } static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) @@ -87,7 +87,7 @@ static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { - return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx); + return amd_pmu_get_pmc(vcpu_to_pmu(vcpu), idx); } static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) @@ -229,7 +229,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu) } struct kvm_pmu_ops amd_pmu_ops __initdata = { - .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = amd_msr_idx_to_pmc, .check_rdpmc_early = amd_check_rdpmc_early, diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index fe7a2ba51e1b..845a964f22a6 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -55,18 +55,6 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) } } -static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) -{ - if (pmc_idx < KVM_FIXED_PMC_BASE_IDX) { - return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx, - MSR_P6_EVNTSEL0); - } else { - u32 idx = pmc_idx - KVM_FIXED_PMC_BASE_IDX; - - return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0); - } -} - static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { @@ -718,7 +706,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) for_each_set_bit(bit, (unsigned long *)&pmu->global_ctrl, X86_PMC_IDX_MAX) { - pmc = intel_pmc_idx_to_pmc(pmu, bit); + pmc = kvm_pmc_idx_to_pmc(pmu, bit); if (!pmc || !pmc_speculative_in_use(pmc) || !pmc_is_globally_enabled(pmc) || !pmc->perf_event) @@ -735,7 +723,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) } struct kvm_pmu_ops intel_pmu_ops __initdata = { - .pmc_idx_to_pmc = intel_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = intel_msr_idx_to_pmc, .is_valid_msr = intel_is_valid_msr, From 004a0aa56edea3effc97bc90a620da1bcde5c63c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:51 -0800 Subject: [PATCH 165/814] KVM: x86/pmu: Snapshot and clear reprogramming bitmap before reprogramming Refactor the handling of the reprogramming bitmap to snapshot and clear to-be-processed bits before doing the reprogramming, and then explicitly set bits for PMCs that need to be reprogrammed (again). This will allow adding a macro to iterate over all valid PMCs without having to add special handling for the reprogramming bit, which (a) can have bits set for non-existent PMCs and (b) needs to clear such bits to avoid wasting cycles in perpetuity. Note, the existing behavior of clearing bits after reprogramming does NOT have a race with kvm_vm_ioctl_set_pmu_event_filter(). Setting a new PMU filter synchronizes SRCU _before_ setting the bitmap, i.e. guarantees that the vCPU isn't in the middle of reprogramming with a stale filter prior to setting the bitmap. Link: https://lore.kernel.org/r/20231110022857.1273836-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/pmu.c | 52 ++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b5b2d0fde579..ad5319a503f0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -536,6 +536,7 @@ struct kvm_pmc { #define KVM_PMC_MAX_FIXED 3 #define MSR_ARCH_PERFMON_FIXED_CTR_MAX (MSR_ARCH_PERFMON_FIXED_CTR0 + KVM_PMC_MAX_FIXED - 1) #define KVM_AMD_PMC_MAX_GENERIC 6 + struct kvm_pmu { u8 version; unsigned nr_arch_gp_counters; diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 0873937c90bc..81a0c6719863 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -444,7 +444,7 @@ static bool pmc_event_is_allowed(struct kvm_pmc *pmc) check_pmu_event_filter(pmc); } -static void reprogram_counter(struct kvm_pmc *pmc) +static int reprogram_counter(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); u64 eventsel = pmc->eventsel; @@ -455,7 +455,7 @@ static void reprogram_counter(struct kvm_pmc *pmc) emulate_overflow = pmc_pause_counter(pmc); if (!pmc_event_is_allowed(pmc)) - goto reprogram_complete; + return 0; if (emulate_overflow) __kvm_perf_overflow(pmc, false); @@ -476,43 +476,49 @@ static void reprogram_counter(struct kvm_pmc *pmc) } if (pmc->current_config == new_config && pmc_resume_counter(pmc)) - goto reprogram_complete; + return 0; pmc_release_perf_event(pmc); pmc->current_config = new_config; - /* - * If reprogramming fails, e.g. due to contention, leave the counter's - * regprogram bit set, i.e. opportunistically try again on the next PMU - * refresh. Don't make a new request as doing so can stall the guest - * if reprogramming repeatedly fails. - */ - if (pmc_reprogram_counter(pmc, PERF_TYPE_RAW, - (eventsel & pmu->raw_event_mask), - !(eventsel & ARCH_PERFMON_EVENTSEL_USR), - !(eventsel & ARCH_PERFMON_EVENTSEL_OS), - eventsel & ARCH_PERFMON_EVENTSEL_INT)) - return; - -reprogram_complete: - clear_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->reprogram_pmi); + return pmc_reprogram_counter(pmc, PERF_TYPE_RAW, + (eventsel & pmu->raw_event_mask), + !(eventsel & ARCH_PERFMON_EVENTSEL_USR), + !(eventsel & ARCH_PERFMON_EVENTSEL_OS), + eventsel & ARCH_PERFMON_EVENTSEL_INT); } void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) { + DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); int bit; - for_each_set_bit(bit, pmu->reprogram_pmi, X86_PMC_IDX_MAX) { + bitmap_copy(bitmap, pmu->reprogram_pmi, X86_PMC_IDX_MAX); + + /* + * The reprogramming bitmap can be written asynchronously by something + * other than the task that holds vcpu->mutex, take care to clear only + * the bits that will actually processed. + */ + BUILD_BUG_ON(sizeof(bitmap) != sizeof(atomic64_t)); + atomic64_andnot(*(s64 *)bitmap, &pmu->__reprogram_pmi); + + for_each_set_bit(bit, bitmap, X86_PMC_IDX_MAX) { struct kvm_pmc *pmc = kvm_pmc_idx_to_pmc(pmu, bit); - if (unlikely(!pmc)) { - clear_bit(bit, pmu->reprogram_pmi); + if (unlikely(!pmc)) continue; - } - reprogram_counter(pmc); + /* + * If reprogramming fails, e.g. due to contention, re-set the + * regprogram bit set, i.e. opportunistically try again on the + * next PMU refresh. Don't make a new request as doing so can + * stall the guest if reprogramming repeatedly fails. + */ + if (reprogram_counter(pmc)) + set_bit(pmc->idx, pmu->reprogram_pmi); } /* From e5a65d4f723ab9997deab798c539e6bfd71f8440 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:52 -0800 Subject: [PATCH 166/814] KVM: x86/pmu: Add macros to iterate over all PMCs given a bitmap Add and use kvm_for_each_pmc() to dedup a variety of open coded for-loops that iterate over valid PMCs given a bitmap (and because seeing checkpatch whine about bad macro style is always amusing). No functional change intended. Link: https://lore.kernel.org/r/20231110022857.1273836-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 26 +++++++------------------- arch/x86/kvm/pmu.h | 6 ++++++ arch/x86/kvm/vmx/pmu_intel.c | 7 ++----- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 81a0c6719863..7b5563ff259c 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -493,6 +493,7 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) { DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); + struct kvm_pmc *pmc; int bit; bitmap_copy(bitmap, pmu->reprogram_pmi, X86_PMC_IDX_MAX); @@ -505,12 +506,7 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) BUILD_BUG_ON(sizeof(bitmap) != sizeof(atomic64_t)); atomic64_andnot(*(s64 *)bitmap, &pmu->__reprogram_pmi); - for_each_set_bit(bit, bitmap, X86_PMC_IDX_MAX) { - struct kvm_pmc *pmc = kvm_pmc_idx_to_pmc(pmu, bit); - - if (unlikely(!pmc)) - continue; - + kvm_for_each_pmc(pmu, pmc, bit, bitmap) { /* * If reprogramming fails, e.g. due to contention, re-set the * regprogram bit set, i.e. opportunistically try again on the @@ -730,11 +726,7 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu) bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX); - for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { - pmc = kvm_pmc_idx_to_pmc(pmu, i); - if (!pmc) - continue; - + kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx) { pmc_stop_counter(pmc); pmc->counter = 0; pmc->emulated_counter = 0; @@ -806,10 +798,8 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu) bitmap_andnot(bitmask, pmu->all_valid_pmc_idx, pmu->pmc_in_use, X86_PMC_IDX_MAX); - for_each_set_bit(i, bitmask, X86_PMC_IDX_MAX) { - pmc = kvm_pmc_idx_to_pmc(pmu, i); - - if (pmc && pmc->perf_event && !pmc_speculative_in_use(pmc)) + kvm_for_each_pmc(pmu, pmc, i, bitmask) { + if (pmc->perf_event && !pmc_speculative_in_use(pmc)) pmc_stop_counter(pmc); } @@ -861,10 +851,8 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) struct kvm_pmc *pmc; int i; - for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { - pmc = kvm_pmc_idx_to_pmc(pmu, i); - - if (!pmc || !pmc_event_is_allowed(pmc)) + kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx) { + if (!pmc_event_is_allowed(pmc)) continue; /* Ignore checks for edge detect, pin control, invert and CMASK bits */ diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 56e8e665e1af..fd18bc0b281c 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -83,6 +83,12 @@ static inline struct kvm_pmc *kvm_pmc_idx_to_pmc(struct kvm_pmu *pmu, int idx) return NULL; } +#define kvm_for_each_pmc(pmu, pmc, i, bitmap) \ + for_each_set_bit(i, bitmap, X86_PMC_IDX_MAX) \ + if (!(pmc = kvm_pmc_idx_to_pmc(pmu, i))) \ + continue; \ + else \ + static inline u64 pmc_bitmask(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 845a964f22a6..73b9943ceb17 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -704,11 +704,8 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) struct kvm_pmc *pmc = NULL; int bit, hw_idx; - for_each_set_bit(bit, (unsigned long *)&pmu->global_ctrl, - X86_PMC_IDX_MAX) { - pmc = kvm_pmc_idx_to_pmc(pmu, bit); - - if (!pmc || !pmc_speculative_in_use(pmc) || + kvm_for_each_pmc(pmu, pmc, bit, (unsigned long *)&pmu->global_ctrl) { + if (!pmc_speculative_in_use(pmc) || !pmc_is_globally_enabled(pmc) || !pmc->perf_event) continue; From d2b321ea9380564510d281d45ccd2b424da14e7f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:53 -0800 Subject: [PATCH 167/814] KVM: x86/pmu: Process only enabled PMCs when emulating events in software Mask off disabled counters based on PERF_GLOBAL_CTRL *before* iterating over PMCs to emulate (branch) instruction required events in software. In the common case where the guest isn't utilizing the PMU, pre-checking for enabled counters turns a relatively expensive search into a few AND uops and a Jcc. Sadly, PMUs without PERF_GLOBAL_CTRL, e.g. most existing AMD CPUs, are out of luck as there is no way to check that a PMC isn't being used without checking the PMC's event selector. Cc: Konstantin Khorenko Link: https://lore.kernel.org/r/20231110022857.1273836-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 7b5563ff259c..c04c3f37a1b8 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -847,11 +847,20 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) { + DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); struct kvm_pmc *pmc; int i; - kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx) { + BUILD_BUG_ON(sizeof(pmu->global_ctrl) * BITS_PER_BYTE != X86_PMC_IDX_MAX); + + if (!kvm_pmu_has_perf_global_ctrl(pmu)) + bitmap_copy(bitmap, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX); + else if (!bitmap_and(bitmap, pmu->all_valid_pmc_idx, + (unsigned long *)&pmu->global_ctrl, X86_PMC_IDX_MAX)) + return; + + kvm_for_each_pmc(pmu, pmc, i, bitmap) { if (!pmc_event_is_allowed(pmc)) continue; From f19063b1ca058b3971d6883b5ec45955b7f53f9c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:54 -0800 Subject: [PATCH 168/814] KVM: x86/pmu: Snapshot event selectors that KVM emulates in software Snapshot the event selectors for the events that KVM emulates in software, which is currently instructions retired and branch instructions retired. The event selectors a tied to the underlying CPU, i.e. are constant for a given platform even though perf doesn't manage the mappings as such. Getting the event selectors from perf isn't exactly cheap, especially if mitigations are enabled, as at least one indirect call is involved. Snapshot the values in KVM instead of optimizing perf as working with the raw event selectors will be required if KVM ever wants to emulate events that aren't part of perf's uABI, i.e. that don't have an "enum perf_hw_id" entry. Link: https://lore.kernel.org/r/20231110022857.1273836-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 17 ++++++++--------- arch/x86/kvm/pmu.h | 13 ++++++++++++- arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/x86.c | 6 +++--- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index c04c3f37a1b8..f40d8c1edca9 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -29,6 +29,9 @@ struct x86_pmu_capability __read_mostly kvm_pmu_cap; EXPORT_SYMBOL_GPL(kvm_pmu_cap); +struct kvm_pmu_emulated_event_selectors __read_mostly kvm_pmu_eventsel; +EXPORT_SYMBOL_GPL(kvm_pmu_eventsel); + /* Precise Distribution of Instructions Retired (PDIR) */ static const struct x86_cpu_id vmx_pebs_pdir_cpu[] = { X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), @@ -819,13 +822,6 @@ static void kvm_pmu_incr_counter(struct kvm_pmc *pmc) kvm_pmu_request_counter_reprogram(pmc); } -static inline bool eventsel_match_perf_hw_id(struct kvm_pmc *pmc, - unsigned int perf_hw_id) -{ - return !((pmc->eventsel ^ perf_get_hw_event_config(perf_hw_id)) & - AMD64_RAW_EVENT_MASK_NB); -} - static inline bool cpl_is_matched(struct kvm_pmc *pmc) { bool select_os, select_user; @@ -845,7 +841,7 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) return (static_call(kvm_x86_get_cpl)(pmc->vcpu) == 0) ? select_os : select_user; } -void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) +void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) { DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -865,7 +861,10 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) continue; /* Ignore checks for edge detect, pin control, invert and CMASK bits */ - if (eventsel_match_perf_hw_id(pmc, perf_hw_id) && cpl_is_matched(pmc)) + if ((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB) + continue; + + if (cpl_is_matched(pmc)) kvm_pmu_incr_counter(pmc); } } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index fd18bc0b281c..4d52b0b539ba 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -22,6 +22,11 @@ #define KVM_FIXED_PMC_BASE_IDX INTEL_PMC_IDX_FIXED +struct kvm_pmu_emulated_event_selectors { + u64 INSTRUCTIONS_RETIRED; + u64 BRANCH_INSTRUCTIONS_RETIRED; +}; + struct kvm_pmu_ops { struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); @@ -171,6 +176,7 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) } extern struct x86_pmu_capability kvm_pmu_cap; +extern struct kvm_pmu_emulated_event_selectors kvm_pmu_eventsel; static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) { @@ -212,6 +218,11 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) pmu_ops->MAX_NR_GP_COUNTERS); kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, KVM_PMC_MAX_FIXED); + + kvm_pmu_eventsel.INSTRUCTIONS_RETIRED = + perf_get_hw_event_config(PERF_COUNT_HW_INSTRUCTIONS); + kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED = + perf_get_hw_event_config(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc) @@ -259,7 +270,7 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu); void kvm_pmu_cleanup(struct kvm_vcpu *vcpu); void kvm_pmu_destroy(struct kvm_vcpu *vcpu); int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp); -void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id); +void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel); bool is_vmware_backdoor_pmc(u32 pmc_idx); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 6329a306856b..994e014f8a50 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3606,7 +3606,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) return 1; } - kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); if (CC(evmptrld_status == EVMPTRLD_VMFAIL)) return nested_vmx_failInvalid(vcpu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cbee277254f0..a30df9f8d9d5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8903,7 +8903,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) if (unlikely(!r)) return 0; - kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_INSTRUCTIONS); + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); /* * rflags is the old, "raw" value of the flags. The new value has @@ -9216,9 +9216,9 @@ writeback: */ if (!ctxt->have_exception || exception_type(ctxt->exception.vector) == EXCPT_TRAP) { - kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_INSTRUCTIONS); + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); if (ctxt->is_branch) - kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); kvm_rip_write(vcpu, ctxt->eip); if (r && (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) r = kvm_vcpu_do_singlestep(vcpu); From afda2d7666f894d1d7b8406cf54801e6c11f63c2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:55 -0800 Subject: [PATCH 169/814] KVM: x86/pmu: Expand the comment about what bits are check emulating events Expand the comment about what bits are and aren't checked when emulating PMC events in software. As pointed out by Jim, AMD's mask includes bits 35:32, which on Intel overlap with the IN_TX and IN_TXCP bits (32 and 33) as well as reserved bits (34 and 45). Checking The IN_TX* bits is actually correct, as it's safe to assert that the vCPU can't be in an HLE/RTM transaction if KVM is emulating an instruction, i.e. KVM *shouldn't count if either of those bits is set. For the reserved bits, KVM is has equal odds of being right if Intel adds new behavior, i.e. ignoring them is just as likely to be correct as checking them. Opportunistically explain *why* the other flags aren't checked. Suggested-by: Jim Mattson Link: https://lore.kernel.org/r/20231110022857.1273836-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index f40d8c1edca9..d891a954b45a 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -860,7 +860,20 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) if (!pmc_event_is_allowed(pmc)) continue; - /* Ignore checks for edge detect, pin control, invert and CMASK bits */ + /* + * Ignore checks for edge detect (all events currently emulated + * but KVM are always rising edges), pin control (unsupported + * by modern CPUs), and counter mask and its invert flag (KVM + * doesn't emulate multiple events in a single clock cycle). + * + * Note, the uppermost nibble of AMD's mask overlaps Intel's + * IN_TX (bit 32) and IN_TXCP (bit 33), as well as two reserved + * bits (bits 35:34). Checking the "in HLE/RTM transaction" + * flags is correct as the vCPU can't be in a transaction if + * KVM is emulating an instruction. Checking the reserved bits + * might be wrong if they are defined in the future, but so + * could ignoring them, so do the simple thing for now. + */ if ((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB) continue; From e35529fb4ac930a4a39e0c15bafcb28a30d26611 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:56 -0800 Subject: [PATCH 170/814] KVM: x86/pmu: Check eventsel first when emulating (branch) insns retired When triggering events, i.e. emulating PMC events in software, check for a matching event selector before checking the event is allowed. The "is allowed" check *might* be cheap, but it could also be very costly, e.g. if userspace has defined a large PMU event filter. The event selector check on the other hand is all but guaranteed to be <10 uops, e.g. looks something like: 0xffffffff8105e615 <+5>: movabs $0xf0000ffff,%rax 0xffffffff8105e61f <+15>: xor %rdi,%rsi 0xffffffff8105e622 <+18>: test %rax,%rsi 0xffffffff8105e625 <+21>: sete %al Link: https://lore.kernel.org/r/20231110022857.1273836-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index d891a954b45a..8d81f176ab7b 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -857,9 +857,6 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - if (!pmc_event_is_allowed(pmc)) - continue; - /* * Ignore checks for edge detect (all events currently emulated * but KVM are always rising edges), pin control (unsupported @@ -874,11 +871,11 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) * might be wrong if they are defined in the future, but so * could ignoring them, so do the simple thing for now. */ - if ((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB) + if (((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB) || + !pmc_event_is_allowed(pmc) || !cpl_is_matched(pmc)) continue; - if (cpl_is_matched(pmc)) - kvm_pmu_incr_counter(pmc); + kvm_pmu_incr_counter(pmc); } } EXPORT_SYMBOL_GPL(kvm_pmu_trigger_event); From 83bdfe04c968e0fe3181e4cd41b764e17ac73911 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Nov 2023 18:28:57 -0800 Subject: [PATCH 171/814] KVM: x86/pmu: Avoid CPL lookup if PMC enabline for USER and KERNEL is the same Don't bother querying the CPL if a PMC is (not) counting for both USER and KERNEL, i.e. if the end result is guaranteed to be the same regardless of the CPL. Querying the CPL on Intel requires a VMREAD, i.e. isn't free, and a single CMP+Jcc is cheap. Link: https://lore.kernel.org/r/20231110022857.1273836-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 8d81f176ab7b..c397b28e3d1b 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -838,6 +838,13 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) select_user = config & 0x2; } + /* + * Skip the CPL lookup, which isn't free on Intel, if the result will + * be the same regardless of the CPL. + */ + if (select_os == select_user) + return select_os; + return (static_call(kvm_x86_get_cpl)(pmc->vcpu) == 0) ? select_os : select_user; } From c4d15f841570dafc079966baa8fd1bc31cd5bf36 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:05 -0800 Subject: [PATCH 172/814] KVM: arm64: debug: fix kernel-doc warnings Change one "/**" comment to a common "/*" comment since the comment is not in kernel-doc format. Add description for the @vcpu function parameter. These changes prevent warnings: debug.c:27: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * save/restore_guest_debug_regs debug.c:27: warning: missing initial short description on line: * save/restore_guest_debug_regs debug.c:149: warning: Function parameter or struct member 'vcpu' not described in 'kvm_arm_reset_debug_ptr' Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-2-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8725291cb00a..ce8886122ed3 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -23,7 +23,7 @@ static DEFINE_PER_CPU(u64, mdcr_el2); -/** +/* * save/restore_guest_debug_regs * * For some debug operations we need to tweak some guest registers. As @@ -143,6 +143,7 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu) /** * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state + * @vcpu: the vcpu pointer */ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) From 39db66e6b404a096bdc1717e44757dad94756e2c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:06 -0800 Subject: [PATCH 173/814] KVM: arm64: guest: fix kernel-doc warnings Fix multiple function parameter descriptions to prevent warnings: guest.c:718: warning: Function parameter or struct member 'vcpu' not described in 'kvm_arm_num_regs' guest.c:736: warning: Function parameter or struct member 'vcpu' not described in 'kvm_arm_copy_reg_indices' guest.c:736: warning: Function parameter or struct member 'uindices' not described in 'kvm_arm_copy_reg_indices' arch/arm64/kvm/guest.c:915: warning: Excess function parameter 'kvm' description in 'kvm_arch_vcpu_ioctl_set_guest_debug' arch/arm64/kvm/guest.c:915: warning: Excess function parameter 'kvm_guest_debug' description in 'kvm_arch_vcpu_ioctl_set_guest_debug' Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-3-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/guest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index aaf1d4939739..6e22e658795a 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -711,6 +711,7 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu, /** * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG + * @vcpu: the vCPU pointer * * This is for all registers. */ @@ -729,6 +730,8 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) /** * kvm_arm_copy_reg_indices - get indices of all registers. + * @vcpu: the vCPU pointer + * @uindices: register list to copy * * We do core registers right here, then we append system regs. */ @@ -902,8 +905,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging - * @kvm: pointer to the KVM struct - * @kvm_guest_debug: the ioctl data buffer + * @vcpu: the vCPU pointer + * @dbg: the ioctl data buffer * * This sets up and enables the VM for guest debugging. Userspace * passes in a control flag to enable different debug types and From bc13610b42408c84dbc927a2d6632140865a33f1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:07 -0800 Subject: [PATCH 174/814] KVM: arm64: hyp/aarch32: fix kernel-doc warnings Use the correct function name in the kernel-doc comments to prevent kernel-doc warnings: arch/arm64/kvm/hyp/vhe/../aarch32.c:97: warning: expecting prototype for adjust_itstate(). Prototype was for kvm_adjust_itstate() instead arch/arm64/kvm/hyp/vhe/../aarch32.c:127: warning: expecting prototype for kvm_skip_instr(). Prototype was for kvm_skip_instr32() instead Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-4-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/aarch32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp/aarch32.c b/arch/arm64/kvm/hyp/aarch32.c index f98cbe2626a1..8d9670e6615d 100644 --- a/arch/arm64/kvm/hyp/aarch32.c +++ b/arch/arm64/kvm/hyp/aarch32.c @@ -84,7 +84,7 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu) } /** - * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block + * kvm_adjust_itstate - adjust ITSTATE when emulating instructions in IT-block * @vcpu: The VCPU pointer * * When exceptions occur while instructions are executed in Thumb IF-THEN @@ -120,7 +120,7 @@ static void kvm_adjust_itstate(struct kvm_vcpu *vcpu) } /** - * kvm_skip_instr - skip a trapped instruction and proceed to the next + * kvm_skip_instr32 - skip a trapped instruction and proceed to the next * @vcpu: The vcpu pointer */ void kvm_skip_instr32(struct kvm_vcpu *vcpu) From aa96af24f3203d2cfbcec220ffcb034864dd2a3f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:08 -0800 Subject: [PATCH 175/814] KVM: arm64: vhe: fix a kernel-doc warning Use the correct function name in the kernel-doc comment to prevent a warning: arch/arm64/kvm/hyp/vhe/sysreg-sr.c:109: warning: expecting prototype for __vcpu_put_switch_syregs(). Prototype was for __vcpu_put_switch_sysregs() instead Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-5-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c index 8e1e0d5033b6..a8b9ea496706 100644 --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c @@ -95,7 +95,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu) } /** - * __vcpu_put_switch_syregs - Restore host system registers to the physical CPU + * __vcpu_put_switch_sysregs - Restore host system registers to the physical CPU * * @vcpu: The VCPU pointer * From ffd9eaffa34d793bdfc36a8a1ed9d830cea1d1fa Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:09 -0800 Subject: [PATCH 176/814] KVM: arm64: mmu: fix a kernel-doc warning Use the correct function name in a kernel-doc comment to prevent a warning: arch/arm64/kvm/mmu.c:321: warning: expecting prototype for unmap_stage2_range(). Prototype was for __unmap_stage2_range() instead Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-6-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index d14504821b79..937e4fc1020e 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -305,7 +305,7 @@ static void invalidate_icache_guest_page(void *va, size_t size) * does. */ /** - * unmap_stage2_range -- Clear stage2 page table entries to unmap a range + * __unmap_stage2_range -- Clear stage2 page table entries to unmap a range * @mmu: The KVM stage-2 MMU pointer * @start: The intermediate physical base address of the range to unmap * @size: The size of the area to unmap From 2a00f0855530a8911a9145670cd24d9010141d30 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:10 -0800 Subject: [PATCH 177/814] KVM: arm64: PMU: fix kernel-doc warnings Change 2 uses of "/**" on non-kernel-doc comments to common "/*" comments to prevent kernel-doc warnings: arch/arm64/kvm/pmu-emul.c:423: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * When perf interrupt is an NMI, we cannot safely notify the vcpu corresponding arch/arm64/kvm/pmu-emul.c:494: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * When the perf event overflows, set the overflow status and inform the vcpu. Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-7-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/pmu-emul.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 3d9467ff73bc..bf96bd656d86 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -419,7 +419,7 @@ void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu) kvm_pmu_update_state(vcpu); } -/** +/* * When perf interrupt is an NMI, we cannot safely notify the vcpu corresponding * to the event. * This is why we need a callback to do it once outside of the NMI context. @@ -490,7 +490,7 @@ static u64 compute_period(struct kvm_pmc *pmc, u64 counter) return val; } -/** +/* * When the perf event overflows, set the overflow status and inform the vcpu. */ static void kvm_pmu_perf_overflow(struct perf_event *perf_event, From 8ce783927268914f8d171e96925e9be49a0234c2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:11 -0800 Subject: [PATCH 178/814] KVM: arm64: sys_regs: fix kernel-doc warnings Drop the @run function parameter descriptions and add the actual ones for 2 functions to prevent kernel-doc warnings: arch/arm64/kvm/sys_regs.c:3167: warning: Excess function parameter 'run' description in 'kvm_handle_cp_64' arch/arm64/kvm/sys_regs.c:3335: warning: Excess function parameter 'run' description in 'kvm_handle_cp_32' Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-8-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 30253bd19917..de750d5b960e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3159,7 +3159,8 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu, /** * kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP14/CP15 access * @vcpu: The VCPU pointer - * @run: The kvm_run struct + * @global: &struct sys_reg_desc + * @nr_global: size of the @global array */ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, const struct sys_reg_desc *global, @@ -3326,7 +3327,9 @@ static int kvm_emulate_cp15_id_reg(struct kvm_vcpu *vcpu, /** * kvm_handle_cp_32 -- handles a mrc/mcr trap on a guest CP14/CP15 access * @vcpu: The VCPU pointer - * @run: The kvm_run struct + * @params: &struct sys_reg_params + * @global: &struct sys_reg_desc + * @nr_global: size of the @global array */ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, struct sys_reg_params *params, From dd609a574a029b9eafe7e1a90d05391431db60c4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:12 -0800 Subject: [PATCH 179/814] KVM: arm64: vgic-init: fix a kernel-doc warning Change the function comment block to kernel-doc format to prevent a kernel-doc warning: arch/arm64/kvm/vgic/vgic-init.c:448: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Map the MMIO regions depending on the VGIC model exposed to the guest Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-9-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index e949e1d0fd9f..e0d14a5ff63e 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -445,13 +445,15 @@ int vgic_lazy_init(struct kvm *kvm) /* RESOURCE MAPPING */ /** + * kvm_vgic_map_resources - map the MMIO regions + * @kvm: kvm struct pointer + * * Map the MMIO regions depending on the VGIC model exposed to the guest * called on the first VCPU run. * Also map the virtual CPU interface into the VM. * v2 calls vgic_init() if not already done. * v3 and derivatives return an error if the VGIC is not initialized. * vgic_ready() returns true if this function has succeeded. - * @kvm: kvm struct pointer */ int kvm_vgic_map_resources(struct kvm *kvm) { From f779d2c0176c425e516df9d384ecb1887a406185 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:13 -0800 Subject: [PATCH 180/814] KVM: arm64: vgic-its: fix kernel-doc warnings Correct the function parameter name "@save tables" -> "@save_tables". Use the "typedef" keyword in the kernel-doc comment for a typedef. These changes prevent kernel-doc warnings: vgic/vgic-its.c:174: warning: Function parameter or struct member 'save_tables' not described in 'vgic_its_abi' arch/arm64/kvm/vgic/vgic-its.c:2152: warning: expecting prototype for entry_fn_t(). Prototype was for int() instead Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-10-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-its.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index e2764d0ffa9f..9dfe307ff4fe 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -158,7 +158,7 @@ struct vgic_translation_cache_entry { * @cte_esz: collection table entry size * @dte_esz: device table entry size * @ite_esz: interrupt translation table entry size - * @save tables: save the ITS tables into guest RAM + * @save_tables: save the ITS tables into guest RAM * @restore_tables: restore the ITS internal structs from tables * stored in guest RAM * @commit: initialize the registers which expose the ABI settings, @@ -2139,7 +2139,7 @@ static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite) } /** - * entry_fn_t - Callback called on a table entry restore path + * typedef entry_fn_t - Callback called on a table entry restore path * @its: its handle * @id: id of the entry * @entry: pointer to the entry From e634ff9598a416a2ab6cfe5a2dcee0f69743ddf9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Jan 2024 15:07:14 -0800 Subject: [PATCH 181/814] KVM: arm64: vgic: fix a kernel-doc warning Use the correct function name in a kernel-doc comment to prevent a warning: arch/arm64/kvm/vgic/vgic.c:217: warning: expecting prototype for kvm_vgic_target_oracle(). Prototype was for vgic_target_oracle() instead Signed-off-by: Randy Dunlap Cc: Marc Zyngier Cc: Oliver Upton Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Suzuki K Poulose Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240117230714.31025-11-rdunlap@infradead.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index db2a95762b1b..8e1ecc37a5e0 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -203,7 +203,7 @@ void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active) } /** - * kvm_vgic_target_oracle - compute the target vcpu for an irq + * vgic_target_oracle - compute the target vcpu for an irq * * @irq: The irq to route. Must be already locked. * From 68baa4289b8554998771799ed1f9695721e41a22 Mon Sep 17 00:00:00 2001 From: Qi Tao Date: Fri, 26 Jan 2024 17:38:25 +0800 Subject: [PATCH 182/814] crypto: hisilicon/sec2 - updates the sec DFX function register As the sec DFX function is enhanced, some RAS registers are added to the original DFX registers to enhance the DFX positioning function. Signed-off-by: Qi Tao Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index efa957ece23d..c290d8937b19 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -282,6 +282,11 @@ static const struct debugfs_reg32 sec_dfx_regs[] = { {"SEC_BD_SAA6 ", 0x301C38}, {"SEC_BD_SAA7 ", 0x301C3C}, {"SEC_BD_SAA8 ", 0x301C40}, + {"SEC_RAS_CE_ENABLE ", 0x301050}, + {"SEC_RAS_FE_ENABLE ", 0x301054}, + {"SEC_RAS_NFE_ENABLE ", 0x301058}, + {"SEC_REQ_TRNG_TIME_TH ", 0x30112C}, + {"SEC_CHANNEL_RNG_REQ_THLD ", 0x302110}, }; /* define the SEC's dfx regs region and region length */ From c4af422545474a0dbae1b17d306ec94e32ee0551 Mon Sep 17 00:00:00 2001 From: Qi Tao Date: Fri, 26 Jan 2024 17:38:26 +0800 Subject: [PATCH 183/814] crypto: hisilicon/sec2 - modify nested macro call Nested macros are integrated into a single macro, making the code simpler. Signed-off-by: Qi Tao Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index f028dcfd0ead..692ba3213cc6 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -2145,8 +2145,8 @@ static int sec_skcipher_decrypt(struct skcipher_request *sk_req) return sec_skcipher_crypto(sk_req, false); } -#define SEC_SKCIPHER_GEN_ALG(sec_cra_name, sec_set_key, sec_min_key_size, \ - sec_max_key_size, ctx_init, ctx_exit, blk_size, iv_size)\ +#define SEC_SKCIPHER_ALG(sec_cra_name, sec_set_key, \ + sec_min_key_size, sec_max_key_size, blk_size, iv_size)\ {\ .base = {\ .cra_name = sec_cra_name,\ @@ -2158,8 +2158,8 @@ static int sec_skcipher_decrypt(struct skcipher_request *sk_req) .cra_ctxsize = sizeof(struct sec_ctx),\ .cra_module = THIS_MODULE,\ },\ - .init = ctx_init,\ - .exit = ctx_exit,\ + .init = sec_skcipher_ctx_init,\ + .exit = sec_skcipher_ctx_exit,\ .setkey = sec_set_key,\ .decrypt = sec_skcipher_decrypt,\ .encrypt = sec_skcipher_encrypt,\ @@ -2168,11 +2168,6 @@ static int sec_skcipher_decrypt(struct skcipher_request *sk_req) .ivsize = iv_size,\ } -#define SEC_SKCIPHER_ALG(name, key_func, min_key_size, \ - max_key_size, blk_size, iv_size) \ - SEC_SKCIPHER_GEN_ALG(name, key_func, min_key_size, max_key_size, \ - sec_skcipher_ctx_init, sec_skcipher_ctx_exit, blk_size, iv_size) - static struct sec_skcipher sec_skciphers[] = { { .alg_msk = BIT(0), From dd1a502cabcaa410c68ee9f74eae50d85e89fee3 Mon Sep 17 00:00:00 2001 From: Qi Tao Date: Fri, 26 Jan 2024 17:38:27 +0800 Subject: [PATCH 184/814] crypto: hisilicon/sec2 - fix some cleanup issues This patch fixes following cleanup issues: - The return value of the function is inconsistent with the actual return type. - After the pointer type is directly converted to the `__le64` type, the program may crash or produce unexpected results. Signed-off-by: Qi Tao Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 692ba3213cc6..f7e2ba0bf160 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -118,7 +118,7 @@ struct sec_aead { }; /* Get an en/de-cipher queue cyclically to balance load over queues of TFM */ -static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req) +static inline u32 sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req) { if (req->c_req.encrypt) return (u32)atomic_inc_return(&ctx->enc_qcyclic) % @@ -1371,7 +1371,7 @@ static int sec_skcipher_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req) sec_sqe3->bd_param = cpu_to_le32(bd_param); sec_sqe3->c_len_ivin |= cpu_to_le32(c_req->c_len); - sec_sqe3->tag = cpu_to_le64(req); + sec_sqe3->tag = cpu_to_le64((unsigned long)req); return 0; } From 0c753f33428d824f476c1e76fac2f06b8dd0b3d5 Mon Sep 17 00:00:00 2001 From: Wenkai Lin Date: Fri, 26 Jan 2024 17:38:28 +0800 Subject: [PATCH 185/814] crypto: hisilicon/sec - remove unused parameter Unused parameter of static functions should be removed. Signed-off-by: Wenkai Lin Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index f7e2ba0bf160..93a972fcbf63 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -485,8 +485,7 @@ static void sec_alg_resource_free(struct sec_ctx *ctx, sec_free_mac_resource(dev, qp_ctx->res); } -static int sec_alloc_qp_ctx_resource(struct hisi_qm *qm, struct sec_ctx *ctx, - struct sec_qp_ctx *qp_ctx) +static int sec_alloc_qp_ctx_resource(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) { u16 q_depth = qp_ctx->qp->sq_depth; struct device *dev = ctx->dev; @@ -541,8 +540,7 @@ static void sec_free_qp_ctx_resource(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ kfree(qp_ctx->req_list); } -static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx, - int qp_ctx_id, int alg_type) +static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) { struct sec_qp_ctx *qp_ctx; struct hisi_qp *qp; @@ -561,7 +559,7 @@ static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx, idr_init(&qp_ctx->req_idr); INIT_LIST_HEAD(&qp_ctx->backlog); - ret = sec_alloc_qp_ctx_resource(qm, ctx, qp_ctx); + ret = sec_alloc_qp_ctx_resource(ctx, qp_ctx); if (ret) goto err_destroy_idr; @@ -614,7 +612,7 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) } for (i = 0; i < sec->ctx_q_num; i++) { - ret = sec_create_qp_ctx(&sec->qm, ctx, i, 0); + ret = sec_create_qp_ctx(ctx, i); if (ret) goto err_sec_release_qp_ctx; } @@ -750,9 +748,7 @@ static void sec_skcipher_uninit(struct crypto_skcipher *tfm) sec_ctx_base_uninit(ctx); } -static int sec_skcipher_3des_setkey(struct crypto_skcipher *tfm, const u8 *key, - const u32 keylen, - const enum sec_cmode c_mode) +static int sec_skcipher_3des_setkey(struct crypto_skcipher *tfm, const u8 *key, const u32 keylen) { struct sec_ctx *ctx = crypto_skcipher_ctx(tfm); struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; @@ -843,7 +839,7 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, switch (c_alg) { case SEC_CALG_3DES: - ret = sec_skcipher_3des_setkey(tfm, key, keylen, c_mode); + ret = sec_skcipher_3des_setkey(tfm, key, keylen); break; case SEC_CALG_AES: case SEC_CALG_SM4: From 9a14b311f2f786a7ac68f445bc550459b36d3190 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 26 Jan 2024 23:49:27 -0800 Subject: [PATCH 186/814] crypto: ahash - unexport crypto_hash_alg_has_setkey() Since crypto_hash_alg_has_setkey() is only called from ahash.c itself, make it a static function. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/ahash.c | 21 ++++++++++----------- include/crypto/internal/hash.h | 2 -- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index 80c3e5354711..0ac83f7f701d 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -618,6 +618,16 @@ int crypto_has_ahash(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_has_ahash); +static bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) +{ + struct crypto_alg *alg = &halg->base; + + if (alg->cra_type == &crypto_shash_type) + return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); + + return __crypto_ahash_alg(alg)->setkey != ahash_nosetkey; +} + struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash) { struct hash_alg_common *halg = crypto_hash_alg_common(hash); @@ -760,16 +770,5 @@ int ahash_register_instance(struct crypto_template *tmpl, } EXPORT_SYMBOL_GPL(ahash_register_instance); -bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) -{ - struct crypto_alg *alg = &halg->base; - - if (alg->cra_type == &crypto_shash_type) - return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); - - return __crypto_ahash_alg(alg)->setkey != ahash_nosetkey; -} -EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 59c707e4dea4..58967593b6b4 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -87,8 +87,6 @@ static inline bool crypto_shash_alg_needs_key(struct shash_alg *alg) !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY); } -bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg); - int crypto_grab_ahash(struct crypto_ahash_spawn *spawn, struct crypto_instance *inst, const char *name, u32 type, u32 mask); From d4d8fbcef03f590288b44955d8d51e334627b013 Mon Sep 17 00:00:00 2001 From: Dragan Cvetic Date: Wed, 31 Jan 2024 17:06:45 +0000 Subject: [PATCH 187/814] dt-bindings: misc: xlnx,sd-fec: convert bindings to yaml Convert AMD (Xilinx) sd-fec bindings to yaml format, so it can validate dt-entries as well as any future additions to yaml. Change in clocks is due to IP is itself configurable and only the first two clocks are in all combinations. The last 6 clocks can be present in some of them. It means order is not really fixed and any combination is possible. Interrupt may or may not be present. The documentation for sd-fec bindings is now YAML, so update the MAINTAINERS file. Update the link to the new yaml file in xilinx_sdfec.rst. Signed-off-by: Dragan Cvetic Link: https://lore.kernel.org/r/20240131170650.530079-1-dragan.cvetic@amd.com Signed-off-by: Rob Herring --- .../devicetree/bindings/misc/xlnx,sd-fec.txt | 58 -------- .../devicetree/bindings/misc/xlnx,sd-fec.yaml | 140 ++++++++++++++++++ Documentation/misc-devices/xilinx_sdfec.rst | 2 +- MAINTAINERS | 2 +- 4 files changed, 142 insertions(+), 60 deletions(-) delete mode 100644 Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt create mode 100644 Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml diff --git a/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt b/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt deleted file mode 100644 index e3289634fa30..000000000000 --- a/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt +++ /dev/null @@ -1,58 +0,0 @@ -* Xilinx SDFEC(16nm) IP * - -The Soft Decision Forward Error Correction (SDFEC) Engine is a Hard IP block -which provides high-throughput LDPC and Turbo Code implementations. -The LDPC decode & encode functionality is capable of covering a range of -customer specified Quasi-cyclic (QC) codes. The Turbo decode functionality -principally covers codes used by LTE. The FEC Engine offers significant -power and area savings versus implementations done in the FPGA fabric. - - -Required properties: -- compatible: Must be "xlnx,sd-fec-1.1" -- clock-names : List of input clock names from the following: - - "core_clk", Main processing clock for processing core (required) - - "s_axi_aclk", AXI4-Lite memory-mapped slave interface clock (required) - - "s_axis_din_aclk", DIN AXI4-Stream Slave interface clock (optional) - - "s_axis_din_words-aclk", DIN_WORDS AXI4-Stream Slave interface clock (optional) - - "s_axis_ctrl_aclk", Control input AXI4-Stream Slave interface clock (optional) - - "m_axis_dout_aclk", DOUT AXI4-Stream Master interface clock (optional) - - "m_axis_dout_words_aclk", DOUT_WORDS AXI4-Stream Master interface clock (optional) - - "m_axis_status_aclk", Status output AXI4-Stream Master interface clock (optional) -- clocks : Clock phandles (see clock_bindings.txt for details). -- reg: Should contain Xilinx SDFEC 16nm Hardened IP block registers - location and length. -- xlnx,sdfec-code : Should contain "ldpc" or "turbo" to describe the codes - being used. -- xlnx,sdfec-din-words : A value 0 indicates that the DIN_WORDS interface is - driven with a fixed value and is not present on the device, a value of 1 - configures the DIN_WORDS to be block based, while a value of 2 configures the - DIN_WORDS input to be supplied for each AXI transaction. -- xlnx,sdfec-din-width : Configures the DIN AXI stream where a value of 1 - configures a width of "1x128b", 2 a width of "2x128b" and 4 configures a width - of "4x128b". -- xlnx,sdfec-dout-words : A value 0 indicates that the DOUT_WORDS interface is - driven with a fixed value and is not present on the device, a value of 1 - configures the DOUT_WORDS to be block based, while a value of 2 configures the - DOUT_WORDS input to be supplied for each AXI transaction. -- xlnx,sdfec-dout-width : Configures the DOUT AXI stream where a value of 1 - configures a width of "1x128b", 2 a width of "2x128b" and 4 configures a width - of "4x128b". -Optional properties: -- interrupts: should contain SDFEC interrupt number - -Example ---------------------------------------- - sd_fec_0: sd-fec@a0040000 { - compatible = "xlnx,sd-fec-1.1"; - clock-names = "core_clk","s_axi_aclk","s_axis_ctrl_aclk","s_axis_din_aclk","m_axis_status_aclk","m_axis_dout_aclk"; - clocks = <&misc_clk_2>,<&misc_clk_0>,<&misc_clk_1>,<&misc_clk_1>,<&misc_clk_1>, <&misc_clk_1>; - reg = <0x0 0xa0040000 0x0 0x40000>; - interrupt-parent = <&axi_intc>; - interrupts = <1 0>; - xlnx,sdfec-code = "ldpc"; - xlnx,sdfec-din-words = <0>; - xlnx,sdfec-din-width = <2>; - xlnx,sdfec-dout-words = <0>; - xlnx,sdfec-dout-width = <1>; - }; diff --git a/Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml b/Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml new file mode 100644 index 000000000000..9bd210337426 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/misc/xlnx,sd-fec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx SDFEC(16nm) IP + +maintainers: + - Cvetic, Dragan + - Erim, Salih + +description: + The Soft Decision Forward Error Correction (SDFEC) Engine is a Hard IP block + which provides high-throughput LDPC and Turbo Code implementations. + The LDPC decode & encode functionality is capable of covering a range of + customer specified Quasi-cyclic (QC) codes. The Turbo decode functionality + principally covers codes used by LTE. The FEC Engine offers significant + power and area savings versus implementations done in the FPGA fabric. + +properties: + compatible: + const: xlnx,sd-fec-1.1 + + reg: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 8 + additionalItems: true + items: + - description: Main processing clock for processing core + - description: AXI4-Lite memory-mapped slave interface clock + - description: Control input AXI4-Stream Slave interface clock + - description: DIN AXI4-Stream Slave interface clock + - description: Status output AXI4-Stream Master interface clock + - description: DOUT AXI4-Stream Master interface clock + - description: DIN_WORDS AXI4-Stream Slave interface clock + - description: DOUT_WORDS AXI4-Stream Master interface clock + + clock-names: + allOf: + - minItems: 2 + maxItems: 8 + additionalItems: true + items: + - const: core_clk + - const: s_axi_aclk + - items: + enum: + - core_clk + - s_axi_aclk + - s_axis_ctrl_aclk + - s_axis_din_aclk + - m_axis_status_aclk + - m_axis_dout_aclk + - s_axis_din_words_aclk + - m_axis_dout_words_aclk + + interrupts: + maxItems: 1 + + xlnx,sdfec-code: + description: + The SD-FEC integrated block supports Low Density Parity Check (LDPC) + decoding and encoding and Turbo code decoding. The LDPC codes used are + highly configurable, and the specific code used can be specified on + a codeword-by-codeword basis. The Turbo code decoding is required by LTE + standard. + $ref: /schemas/types.yaml#/definitions/string + items: + enum: [ ldpc, turbo ] + + xlnx,sdfec-din-width: + description: + Configures the DIN AXI stream where a value of 1 + configures a width of "1x128b", 2 a width of "2x128b" and 4 configures a width + of "4x128b". + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1, 2, 4 ] + + xlnx,sdfec-din-words: + description: + A value 0 indicates that the DIN_WORDS interface is + driven with a fixed value and is not present on the device, a value of 1 + configures the DIN_WORDS to be block based, while a value of 2 configures the + DIN_WORDS input to be supplied for each AXI transaction. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2 ] + + xlnx,sdfec-dout-width: + description: + Configures the DOUT AXI stream where a value of 1 configures a width of "1x128b", + 2 a width of "2x128b" and 4 configures a width of "4x128b". + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1, 2, 4 ] + + xlnx,sdfec-dout-words: + description: + A value 0 indicates that the DOUT_WORDS interface is + driven with a fixed value and is not present on the device, a value of 1 + configures the DOUT_WORDS to be block based, while a value of 2 configures the + DOUT_WORDS input to be supplied for each AXI transaction. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2 ] + +required: + - compatible + - reg + - clocks + - clock-names + - xlnx,sdfec-code + - xlnx,sdfec-din-width + - xlnx,sdfec-din-words + - xlnx,sdfec-dout-width + - xlnx,sdfec-dout-words + +additionalProperties: false + +examples: + - | + #include + + sd-fec@a0040000 { + compatible = "xlnx,sd-fec-1.1"; + reg = <0xa0040000 0x40000>; + clocks = <&misc_clk_2>, <&misc_clk_0>, <&misc_clk_1>, <&misc_clk_1>, + <&misc_clk_1>, <&misc_clk_1>; + clock-names = "core_clk", "s_axi_aclk", "s_axis_ctrl_aclk", + "s_axis_din_aclk", "m_axis_status_aclk", + "m_axis_dout_aclk"; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + xlnx,sdfec-code = "ldpc"; + xlnx,sdfec-din-width = <2>; + xlnx,sdfec-din-words = <0>; + xlnx,sdfec-dout-width = <1>; + xlnx,sdfec-dout-words = <0>; + }; + diff --git a/Documentation/misc-devices/xilinx_sdfec.rst b/Documentation/misc-devices/xilinx_sdfec.rst index 8c8a289d69a3..698e6630f3a7 100644 --- a/Documentation/misc-devices/xilinx_sdfec.rst +++ b/Documentation/misc-devices/xilinx_sdfec.rst @@ -29,7 +29,7 @@ follows: - Does not support shared LDPC code table wraparound The device tree entry is described in: -`linux-xlnx/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt `_ +`linux-xlnx/Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml `_ Modes of Operation diff --git a/MAINTAINERS b/MAINTAINERS index 42b43337c266..b01f890ec789 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24154,7 +24154,7 @@ XILINX SD-FEC IP CORES M: Derek Kiernan M: Dragan Cvetic S: Maintained -F: Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt +F: Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml F: Documentation/misc-devices/xilinx_sdfec.rst F: drivers/misc/Kconfig F: drivers/misc/Makefile From 281dc6c69b0ef3e30781451e141628618152a8c0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 9 Jan 2024 09:25:11 +0100 Subject: [PATCH 188/814] dt-bindings: mux: restrict node name suffixes Make the pattern matching node names a bit stricter to improve DTS consistency. The pattern is restricted to -N suffixes to decimal numbers. Suggested-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Acked-by: Peter Rosin Link: https://lore.kernel.org/r/20240109082511.15278-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/mux/mux-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mux/mux-controller.yaml b/Documentation/devicetree/bindings/mux/mux-controller.yaml index 8b943082a241..571ad9e13ecf 100644 --- a/Documentation/devicetree/bindings/mux/mux-controller.yaml +++ b/Documentation/devicetree/bindings/mux/mux-controller.yaml @@ -74,7 +74,7 @@ select: properties: $nodename: - pattern: '^mux-controller(@.*|-[0-9a-f]+)?$' + pattern: '^mux-controller(@.*|-([0-9]|[1-9][0-9]+))?$' '#mux-control-cells': enum: [ 0, 1 ] From e1dda3afe2a9f466940d44db8baaaf6c0ff8793f Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sat, 3 Feb 2024 13:45:22 +0100 Subject: [PATCH 189/814] KVM: x86: Fix broken debugregs ABI for 32 bit kernels The ioctl()s to get and set KVM's debug registers are broken for 32 bit kernels as they'd only copy half of the user register state because of a UAPI and in-kernel type mismatch (__u64 vs. unsigned long; 8 vs. 4 bytes). This makes it impossible for userland to set anything but DR0 without resorting to bit folding tricks. Switch to a loop for copying debug registers that'll implicitly do the type conversion for us, if needed. There are likely no users (left) for 32bit KVM, fix the bug nonetheless. Fixes: a1efbe77c1fd ("KVM: x86: Add support for saving&restoring debug registers") Signed-off-by: Mathias Krause Link: https://lore.kernel.org/r/20240203124522.592778-4-minipli@grsecurity.net Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 709844fcd521..7eb7736cfd76 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5510,9 +5510,14 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, struct kvm_debugregs *dbgregs) { unsigned long val; + unsigned int i; memset(dbgregs, 0, sizeof(*dbgregs)); - memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db)); + + BUILD_BUG_ON(ARRAY_SIZE(vcpu->arch.db) != ARRAY_SIZE(dbgregs->db)); + for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++) + dbgregs->db[i] = vcpu->arch.db[i]; + kvm_get_dr(vcpu, 6, &val); dbgregs->dr6 = val; dbgregs->dr7 = vcpu->arch.dr7; @@ -5521,6 +5526,8 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, struct kvm_debugregs *dbgregs) { + unsigned int i; + if (dbgregs->flags) return -EINVAL; @@ -5529,7 +5536,9 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, if (!kvm_dr7_valid(dbgregs->dr7)) return -EINVAL; - memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); + for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++) + vcpu->arch.db[i] = dbgregs->db[i]; + kvm_update_dr0123(vcpu); vcpu->arch.dr6 = dbgregs->dr6; vcpu->arch.dr7 = dbgregs->dr7; From 3d0f9342ae200aa1ddc4d6e7a573c6f8f068d994 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:50:56 -0800 Subject: [PATCH 190/814] scsi: lpfc: Initialize status local variable in lpfc_sli4_repost_sgl_list() A static code analyzer tool indicates that the local variable called status in the lpfc_sli4_repost_sgl_list() routine could be used to print garbage uninitialized values in the routine's log message. Fix by initializing to zero. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-2-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 706985358c6a..c7a2f565e2c2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -7582,7 +7582,7 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba, struct lpfc_sglq *sglq_entry = NULL; struct lpfc_sglq *sglq_entry_next = NULL; struct lpfc_sglq *sglq_entry_first = NULL; - int status, total_cnt; + int status = 0, total_cnt; int post_cnt = 0, num_posted = 0, block_cnt = 0; int last_xritag = NO_XRI; LIST_HEAD(prep_sgl_list); From 2ae917d4bcab80ab304b774d492e2fcd6c52c06b Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:50:57 -0800 Subject: [PATCH 191/814] scsi: lpfc: Fix possible memory leak in lpfc_rcv_padisc() The call to lpfc_sli4_resume_rpi() in lpfc_rcv_padisc() may return an unsuccessful status. In such cases, the elsiocb is not issued, the completion is not called, and thus the elsiocb resource is leaked. Check return value after calling lpfc_sli4_resume_rpi() and conditionally release the elsiocb resource. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-3-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d9074929fbab..b147304b01fa 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -748,8 +748,10 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Save the ELS cmd */ elsiocb->drvrTimeout = cmd; - lpfc_sli4_resume_rpi(ndlp, - lpfc_mbx_cmpl_resume_rpi, elsiocb); + if (lpfc_sli4_resume_rpi(ndlp, + lpfc_mbx_cmpl_resume_rpi, + elsiocb)) + kfree(elsiocb); goto out; } } From aa7674bd8da57932766b7aaf73cc7837f74d7852 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:50:58 -0800 Subject: [PATCH 192/814] scsi: lpfc: Use sg_dma_len() API to get struct scatterlist's length The sg_dma_len() API should be used to retrieve a scatterlist's length instead of directly accessing scatterlist->length. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-4-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index d26941b131fd..07e941da8a16 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2728,14 +2728,14 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) sgde = scsi_sglist(cmd); blksize = scsi_prot_interval(cmd); data_src = (uint8_t *)sg_virt(sgde); - data_len = sgde->length; + data_len = sg_dma_len(sgde); if ((data_len & (blksize - 1)) == 0) chk_guard = 1; src = (struct scsi_dif_tuple *)sg_virt(sgpe); start_ref_tag = scsi_prot_ref_tag(cmd); start_app_tag = src->app_tag; - len = sgpe->length; + len = sg_dma_len(sgpe); while (src && protsegcnt) { while (len) { @@ -2800,7 +2800,7 @@ skipit: goto out; data_src = (uint8_t *)sg_virt(sgde); - data_len = sgde->length; + data_len = sg_dma_len(sgde); if ((data_len & (blksize - 1)) == 0) chk_guard = 1; } @@ -2810,7 +2810,7 @@ skipit: sgpe = sg_next(sgpe); if (sgpe) { src = (struct scsi_dif_tuple *)sg_virt(sgpe); - len = sgpe->length; + len = sg_dma_len(sgpe); } else { src = NULL; } From b76beac1a4f57f0f049476d4271710b3c0d05f91 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:50:59 -0800 Subject: [PATCH 193/814] scsi: lpfc: Remove D_ID swap log message from trace event logger D_ID swaps are common during cable swaps in a SAN. Thus, there's no reason to log the event at a KERN_ERR level with the trace event logger. Change the log level to KERN_INFO and the normal LOG_ELS flag. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-5-justintee8345@gmail.com Reviewed-by: Himanshu Madhani 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 b147304b01fa..0bc93f346d90 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -434,7 +434,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0143 PLOGI recv'd from DID: x%x " "WWPN changed: old %llx new %llx\n", ndlp->nlp_DID, From e1b3acad0d7bb3b7134eebe6a35b2dbc72c52b32 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:00 -0800 Subject: [PATCH 194/814] scsi: lpfc: Allow lpfc_plogi_confirm_nport() logic to execute for Fabric nodes Remove the early return NLP_FABRIC check in lpfc_plogi_confirm_nport() because it is possible for switch domain controllers to change WWPN. As a result, allow lpfc_plogi_confirm_nport() to detect that a new ndlp should be initialized in such cases. The old ndlp object will be cleaned up when dev_loss_tmo callbk executes. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-6-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 49 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4d723200690a..a17c66e31637 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1696,18 +1696,13 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; uint32_t keepDID = 0, keep_nlp_flag = 0; + int rc; uint32_t keep_new_nlp_flag = 0; uint16_t keep_nlp_state; u32 keep_nlp_fc4_type = 0; struct lpfc_nvme_rport *keep_nrport = NULL; unsigned long *active_rrqs_xri_bitmap = NULL; - /* Fabric nodes can have the same WWPN so we don't bother searching - * by WWPN. Just return the ndlp that was given to us. - */ - if (ndlp->nlp_type & NLP_FABRIC) - return ndlp; - sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t)); memset(name, 0, sizeof(struct lpfc_name)); @@ -1717,15 +1712,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); /* return immediately if the WWPN matches ndlp */ - if (!new_ndlp || (new_ndlp == ndlp)) + if (new_ndlp == ndlp) return ndlp; - /* - * Unregister from backend if not done yet. Could have been skipped - * due to ADISC - */ - lpfc_nlp_unreg_node(vport, new_ndlp); - if (phba->sli_rev == LPFC_SLI_REV4) { active_rrqs_xri_bitmap = mempool_alloc(phba->active_rrq_pool, GFP_KERNEL); @@ -1742,11 +1731,37 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, (new_ndlp ? new_ndlp->nlp_flag : 0), (new_ndlp ? new_ndlp->nlp_fc4_type : 0)); - keepDID = new_ndlp->nlp_DID; + if (!new_ndlp) { + rc = memcmp(&ndlp->nlp_portname, name, + sizeof(struct lpfc_name)); + if (!rc) { + if (active_rrqs_xri_bitmap) + mempool_free(active_rrqs_xri_bitmap, + phba->active_rrq_pool); + return ndlp; + } + new_ndlp = lpfc_nlp_init(vport, ndlp->nlp_DID); + if (!new_ndlp) { + if (active_rrqs_xri_bitmap) + mempool_free(active_rrqs_xri_bitmap, + phba->active_rrq_pool); + return ndlp; + } + } else { + if (phba->sli_rev == LPFC_SLI_REV4 && + active_rrqs_xri_bitmap) + memcpy(active_rrqs_xri_bitmap, + new_ndlp->active_rrqs_xri_bitmap, + phba->cfg_rrq_xri_bitmap_sz); - if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) - memcpy(active_rrqs_xri_bitmap, new_ndlp->active_rrqs_xri_bitmap, - phba->cfg_rrq_xri_bitmap_sz); + /* + * Unregister from backend if not done yet. Could have been + * skipped due to ADISC + */ + lpfc_nlp_unreg_node(vport, new_ndlp); + } + + keepDID = new_ndlp->nlp_DID; /* At this point in this routine, we know new_ndlp will be * returned. however, any previous GID_FTs that were done From a801d57a110d68aacf8f8b9bb85ef2164c800461 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:01 -0800 Subject: [PATCH 195/814] scsi: lpfc: Remove NLP_RCV_PLOGI early return during RSCN processing for ndlps Upon first RSCN receipt of a target server's remote port that is initially acting as an initiator function, the driver marks the ndlp->nlp_type as an initiator role. Then later, when processing an RSCN for a target function role switch, that ndlp remote port is permanently stuck as an initiator role and can never transition to be discovered as an updated target role function. Remove the NLP_RCV_PLOGI early return if statement clause so that the NLP_NPR_2B_DISC flag gets set. This allows for role change detections. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-7-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f80bbc315f4c..35ea67431239 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5774,14 +5774,6 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (vport->phba->nvmet_support) return ndlp; - /* If we've already received a PLOGI from this NPort - * we don't need to try to discover it again. - */ - if (ndlp->nlp_flag & NLP_RCV_PLOGI && - !(ndlp->nlp_type & - (NLP_FCP_TARGET | NLP_NVME_TARGET))) - return NULL; - if (ndlp->nlp_state > NLP_STE_UNUSED_NODE && ndlp->nlp_state < NLP_STE_PRLI_ISSUE) { lpfc_disc_state_machine(vport, ndlp, NULL, From 7bb6cb7bb21c01cda4425efc935eb8f187832eb6 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:02 -0800 Subject: [PATCH 196/814] scsi: lpfc: Fix failure to delete vports when discovery is in progress Requests to delete an NPIV port may fail repeatedly if the initial request is received during discovery. If the FC_UNLOADING load_flag is set, then skip CT response processing for the physical port. This allows discovery processing for other lpfc_vport objects to reach their cmpl routines before deleting the vport. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-8-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index baae1f8279e0..315db836404a 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -943,8 +943,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } - /* Don't bother processing response if vport is being torn down. */ - if (vport->load_flag & FC_UNLOADING) { + /* Skip processing response on pport if unloading */ + if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); goto out; @@ -1166,8 +1166,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } - /* Don't bother processing response if vport is being torn down. */ - if (vport->load_flag & FC_UNLOADING) { + /* Skip processing response on pport if unloading */ + if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); goto out; From 900db34ad26554d83ae033065a047358994bfe88 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:03 -0800 Subject: [PATCH 197/814] scsi: lpfc: Add condition to delete ndlp object after sending BLS_RJT to an ABTS The "Nodelist not empty" log message and an accompanying delay may be observed when deleting an NPIV port or unloading the lpfc driver. This can occur due to receipt of an ABTS for which there is no corresponding login context or ndlp allocated. In such cases, the driver allocates a new ndlp object to send a BLS_RJT after which the ndlp object unintentionally remains in the NLP_STE_UNUSED_NODE state forever. Add a check to conditionally remove ndlp's initial reference count when queuing a BLS response. If the initial reference is removed, then set the NLP_DROPPED flag to notify other code paths. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-9-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c7a2f565e2c2..29fd2eda70d5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -18933,7 +18933,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, "oxid:x%x SID:x%x\n", oxid, sid); return; } - /* Put ndlp onto pport node list */ + /* Put ndlp onto vport node list */ lpfc_enqueue_node(vport, ndlp); } @@ -18953,7 +18953,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, return; } - ctiocb->vport = phba->pport; + ctiocb->vport = vport; ctiocb->cmd_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; ctiocb->sli4_lxritag = NO_XRI; ctiocb->sli4_xritag = NO_XRI; @@ -19040,6 +19040,16 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, ctiocb->ndlp = NULL; lpfc_sli_release_iocbq(phba, ctiocb); } + + /* if only usage of this nodelist is BLS response, release initial ref + * to free ndlp when transmit completes + */ + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE && + !(ndlp->nlp_flag & NLP_DROPPED) && + !(ndlp->fc4_xpt_flags & (NVME_XPT_REGD | SCSI_XPT_REGD))) { + ndlp->nlp_flag |= NLP_DROPPED; + lpfc_nlp_put(ndlp); + } } /** From 6ca396c5e3c4fb3d2df176145d4800e47cd0d18b Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:04 -0800 Subject: [PATCH 198/814] scsi: lpfc: Save FPIN frequency statistics upon receipt of peer cgn notifications FPIN frequency is provided by the fabric in peer congestion notifications. Currently, the frequency is only logged in a message, but it should also be saved into the phba's cgn_fpin statistics member for proper application functionality. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-10-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index a17c66e31637..1ada8ba6cc2a 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -10131,6 +10131,9 @@ lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) pc_evt_str = lpfc_get_fpin_congn_event_nm(pc_evt); cnt = be32_to_cpu(pc->pname_count); + /* Capture FPIN frequency */ + phba->cgn_fpin_frequency = be32_to_cpu(pc->event_period); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_ELS, "4684 FPIN Peer Congestion %s (x%x) " "Duration %d mSecs " From 140bd888ed0dc192e858c68411ede16fff0fe5fb Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:05 -0800 Subject: [PATCH 199/814] scsi: lpfc: Move handling of reset congestion statistics events The ACQE notification event to reset congestion statistics should be moved into the specific lpfc_sli4_async_sli_evt() routine instead of being processed from the generic lpfc_sli4_async_event_proc() routine. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-11-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 5d4f9f27084d..f6b1168304f3 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -4069,7 +4069,6 @@ struct lpfc_mcqe { #define LPFC_TRAILER_CODE_GRP5 0x5 #define LPFC_TRAILER_CODE_FC 0x10 #define LPFC_TRAILER_CODE_SLI 0x11 -#define LPFC_TRAILER_CODE_CMSTAT 0x13 }; struct lpfc_acqe_link { @@ -4339,6 +4338,7 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE 0x10 #define LPFC_SLI_EVENT_TYPE_CGN_SIGNAL 0x11 #define LPFC_SLI_EVENT_TYPE_RD_SIGNAL 0x12 +#define LPFC_SLI_EVENT_TYPE_RESET_CM_STATS 0x13 }; /* diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 70bcee64bc8c..8e84ba0f7721 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -94,6 +94,7 @@ static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); static int lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *); +static void lpfc_sli4_async_cmstat_evt(struct lpfc_hba *phba); static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba); static struct scsi_transport_template *lpfc_transport_template = NULL; @@ -6636,6 +6637,11 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) acqe_sli->event_data1, acqe_sli->event_data2, acqe_sli->event_data3); break; + case LPFC_SLI_EVENT_TYPE_RESET_CM_STATS: + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2905 Reset CM statistics\n"); + lpfc_sli4_async_cmstat_evt(phba); + break; default: lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3193 Unrecognized SLI event, type: 0x%x", @@ -7346,9 +7352,6 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) case LPFC_TRAILER_CODE_SLI: lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli); break; - case LPFC_TRAILER_CODE_CMSTAT: - lpfc_sli4_async_cmstat_evt(phba); - break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, From 4be4ad6cd2371ffca86e4446feae3d8373e4b02a Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:06 -0800 Subject: [PATCH 200/814] scsi: lpfc: Remove shost_lock protection for fc_host_port shost APIs Desiring to reduce the amount of unnecessary shost_lock acquisitions in the lpfc driver, it has been determined that there is no need for shost_lock protection when retrieving fc_host port information because it is only for display to user via sysfs. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-12-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d3a5d6ecdf7d..1f9a529e09ff 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -6429,8 +6429,6 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - spin_lock_irq(shost->host_lock); - if (vport->port_type == LPFC_NPIV_PORT) { fc_host_port_type(shost) = FC_PORTTYPE_NPIV; } else if (lpfc_is_link_up(phba)) { @@ -6447,8 +6445,6 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) } } else fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - - spin_unlock_irq(shost->host_lock); } /** @@ -6461,8 +6457,6 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - spin_lock_irq(shost->host_lock); - if (vport->fc_flag & FC_OFFLINE_MODE) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; else { @@ -6490,8 +6484,6 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) break; } } - - spin_unlock_irq(shost->host_lock); } /** @@ -6504,8 +6496,6 @@ lpfc_get_host_speed(struct Scsi_Host *shost) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - spin_lock_irq(shost->host_lock); - if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) { switch(phba->fc_linkspeed) { case LPFC_LINK_SPEED_1GHZ: @@ -6568,8 +6558,6 @@ lpfc_get_host_speed(struct Scsi_Host *shost) } } else fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - - spin_unlock_irq(shost->host_lock); } /** @@ -6583,8 +6571,6 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) struct lpfc_hba *phba = vport->phba; u64 node_name; - spin_lock_irq(shost->host_lock); - if ((vport->port_state > LPFC_FLOGI) && ((vport->fc_flag & FC_FABRIC) || ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && @@ -6594,8 +6580,6 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) /* fabric is local port if there is no F/FL_Port */ node_name = 0; - spin_unlock_irq(shost->host_lock); - fc_host_fabric_name(shost) = node_name; } From 0dfd9cbc187c4bb7e35decacae9a131027ea50a3 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:07 -0800 Subject: [PATCH 201/814] scsi: lpfc: Change nlp state statistic counters into atomic_t There is no reason to use the shost_lock to synchronize an LLDD statistics counter. Convert all the nlp state statistic counters into atomic_t. Corresponding zeroing, increments, and reads are converted to atomic versions. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-13-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 17 ++++++------ drivers/scsi/lpfc/lpfc_attr.c | 3 ++- drivers/scsi/lpfc/lpfc_els.c | 10 ++++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 46 ++++++++++++++++---------------- drivers/scsi/lpfc/lpfc_init.c | 11 +++++++- 5 files changed, 50 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 04d608ea9106..8f3cac09a381 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -589,14 +589,15 @@ struct lpfc_vport { struct list_head fc_nodes; /* Keep counters for the number of entries in each list. */ - uint16_t fc_plogi_cnt; - uint16_t fc_adisc_cnt; - uint16_t fc_reglogin_cnt; - uint16_t fc_prli_cnt; - uint16_t fc_unmap_cnt; - uint16_t fc_map_cnt; - uint16_t fc_npr_cnt; - uint16_t fc_unused_cnt; + atomic_t fc_plogi_cnt; + atomic_t fc_adisc_cnt; + atomic_t fc_reglogin_cnt; + atomic_t fc_prli_cnt; + atomic_t fc_unmap_cnt; + atomic_t fc_map_cnt; + atomic_t fc_npr_cnt; + atomic_t fc_unused_cnt; + struct serv_parm fc_sparam; /* buffer for our service parameters */ uint32_t fc_myDID; /* fibre channel S_ID */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 1f9a529e09ff..142c90eb210f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1260,7 +1260,8 @@ lpfc_num_discovered_ports_show(struct device *dev, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; return scnprintf(buf, PAGE_SIZE, "%d\n", - vport->fc_map_cnt + vport->fc_unmap_cnt); + atomic_read(&vport->fc_map_cnt) + + atomic_read(&vport->fc_unmap_cnt)); } /** diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 1ada8ba6cc2a..e01583e2690b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1646,7 +1646,8 @@ lpfc_more_plogi(struct lpfc_vport *vport) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0232 Continue discovery with %d PLOGIs to go " "Data: x%x x%x x%x\n", - vport->num_disc_nodes, vport->fc_plogi_cnt, + vport->num_disc_nodes, + atomic_read(&vport->fc_plogi_cnt), vport->fc_flag, vport->port_state); /* Check to see if there are more PLOGIs to be sent */ if (vport->fc_flag & FC_NLP_MORE) @@ -2692,7 +2693,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport) /* RSCN discovery */ /* go thru NPR nodes and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) + if (atomic_read(&vport->fc_npr_cnt)) if (lpfc_els_disc_plogi(vport)) return; @@ -2752,7 +2753,7 @@ lpfc_adisc_done(struct lpfc_vport *vport) if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; /* go thru NPR list, issue ELS PLOGIs */ - if (vport->fc_npr_cnt) + if (atomic_read(&vport->fc_npr_cnt)) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { spin_lock_irq(shost->host_lock); @@ -2785,7 +2786,8 @@ lpfc_more_adisc(struct lpfc_vport *vport) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0210 Continue discovery with %d ADISCs to go " "Data: x%x x%x x%x\n", - vport->num_disc_nodes, vport->fc_adisc_cnt, + vport->num_disc_nodes, + atomic_read(&vport->fc_adisc_cnt), vport->fc_flag, vport->port_state); /* Check to see if there are more ADISCs to be sent */ if (vport->fc_flag & FC_NLP_MORE) { diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 35ea67431239..7c4356d87730 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4023,7 +4023,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) + if (atomic_read(&vport->fc_npr_cnt)) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { @@ -4600,40 +4600,35 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) static void lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - unsigned long iflags; - - spin_lock_irqsave(shost->host_lock, iflags); switch (state) { case NLP_STE_UNUSED_NODE: - vport->fc_unused_cnt += count; + atomic_add(count, &vport->fc_unused_cnt); break; case NLP_STE_PLOGI_ISSUE: - vport->fc_plogi_cnt += count; + atomic_add(count, &vport->fc_plogi_cnt); break; case NLP_STE_ADISC_ISSUE: - vport->fc_adisc_cnt += count; + atomic_add(count, &vport->fc_adisc_cnt); break; case NLP_STE_REG_LOGIN_ISSUE: - vport->fc_reglogin_cnt += count; + atomic_add(count, &vport->fc_reglogin_cnt); break; case NLP_STE_PRLI_ISSUE: - vport->fc_prli_cnt += count; + atomic_add(count, &vport->fc_prli_cnt); break; case NLP_STE_UNMAPPED_NODE: - vport->fc_unmap_cnt += count; + atomic_add(count, &vport->fc_unmap_cnt); break; case NLP_STE_MAPPED_NODE: - vport->fc_map_cnt += count; + atomic_add(count, &vport->fc_map_cnt); break; case NLP_STE_NPR_NODE: - if (vport->fc_npr_cnt == 0 && count == -1) - vport->fc_npr_cnt = 0; + if (!atomic_read(&vport->fc_npr_cnt) && count == -1) + atomic_set(&vport->fc_npr_cnt, 0); else - vport->fc_npr_cnt += count; + atomic_add(count, &vport->fc_npr_cnt); break; } - spin_unlock_irqrestore(shost->host_lock, iflags); } /* Register a node with backend if not already done */ @@ -5034,8 +5029,9 @@ lpfc_set_disctmo(struct lpfc_vport *vport) "0247 Start Discovery Timer state x%x " "Data: x%x x%lx x%x x%x\n", vport->port_state, tmo, - (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt, - vport->fc_adisc_cnt); + (unsigned long)&vport->fc_disctmo, + atomic_read(&vport->fc_plogi_cnt), + atomic_read(&vport->fc_adisc_cnt)); return; } @@ -5070,7 +5066,8 @@ lpfc_can_disctmo(struct lpfc_vport *vport) "0248 Cancel Discovery Timer state x%x " "Data: x%x x%x x%x\n", vport->port_state, vport->fc_flag, - vport->fc_plogi_cnt, vport->fc_adisc_cnt); + atomic_read(&vport->fc_plogi_cnt), + atomic_read(&vport->fc_adisc_cnt)); return 0; } @@ -5951,8 +5948,10 @@ lpfc_disc_start(struct lpfc_vport *vport) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0202 Start Discovery port state x%x " "flg x%x Data: x%x x%x x%x\n", - vport->port_state, vport->fc_flag, vport->fc_plogi_cnt, - vport->fc_adisc_cnt, vport->fc_npr_cnt); + vport->port_state, vport->fc_flag, + atomic_read(&vport->fc_plogi_cnt), + atomic_read(&vport->fc_adisc_cnt), + atomic_read(&vport->fc_npr_cnt)); /* First do ADISCs - if any */ num_sent = lpfc_els_disc_adisc(vport); @@ -5981,7 +5980,7 @@ lpfc_disc_start(struct lpfc_vport *vport) if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) + if (atomic_read(&vport->fc_npr_cnt)) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { @@ -6077,7 +6076,8 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_hba *phba = vport->phba; - if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { + if (atomic_read(&vport->fc_plogi_cnt) || + atomic_read(&vport->fc_adisc_cnt)) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 8e84ba0f7721..1285a7bbdced 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4770,6 +4770,14 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport->load_flag |= FC_LOADING; vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; vport->fc_rscn_flush = 0; + atomic_set(&vport->fc_plogi_cnt, 0); + atomic_set(&vport->fc_adisc_cnt, 0); + atomic_set(&vport->fc_reglogin_cnt, 0); + atomic_set(&vport->fc_prli_cnt, 0); + atomic_set(&vport->fc_unmap_cnt, 0); + atomic_set(&vport->fc_map_cnt, 0); + atomic_set(&vport->fc_npr_cnt, 0); + atomic_set(&vport->fc_unused_cnt, 0); lpfc_get_vport_cfgparam(vport); /* Adjust value in vport */ @@ -4946,7 +4954,8 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) goto finished; if (vport->num_disc_nodes || vport->fc_prli_sent) goto finished; - if (vport->fc_map_cnt == 0 && time < msecs_to_jiffies(2 * 1000)) + if (!atomic_read(&vport->fc_map_cnt) && + time < msecs_to_jiffies(2 * 1000)) goto finished; if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0) goto finished; From 9bb36777d0a2a22f11264c36f91a2682bfedb9d4 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:08 -0800 Subject: [PATCH 202/814] scsi: lpfc: Protect vport fc_nodes list with an explicit spin lock In attempt to reduce the amount of unnecessary shost_lock acquisitions in the lpfc driver, replace shost_lock with an explicit fc_nodes_list_lock spinlock when accessing vport->fc_nodes lists. Although vport memory region is owned by shost->hostdata, it is driver private memory and an explicit fc_nodes list lock for fc_nodes list mutations is more appropriate than locking the entire shost. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-14-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 35 +++++++++++----------- drivers/scsi/lpfc/lpfc_ct.c | 7 ++--- drivers/scsi/lpfc/lpfc_debugfs.c | 12 ++++---- drivers/scsi/lpfc/lpfc_hbadisc.c | 50 ++++++++++++++++---------------- drivers/scsi/lpfc/lpfc_init.c | 2 +- 6 files changed, 53 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8f3cac09a381..da9f87f89941 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -587,6 +587,7 @@ struct lpfc_vport { #define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */ struct list_head fc_nodes; + spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */ /* Keep counters for the number of entries in each list. */ atomic_t fc_plogi_cnt; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 142c90eb210f..023f4f2c62a6 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -344,6 +344,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_fc4_ctrl_stat *cstat; uint64_t data1, data2, data3; uint64_t totin, totout, tot; + unsigned long iflags; char *statep; int i; int len = 0; @@ -543,7 +544,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) goto buffer_done; - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { nrport = NULL; @@ -617,7 +618,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) goto unlock_buf_done; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); if (!lport) goto buffer_done; @@ -681,7 +682,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, goto buffer_done; unlock_buf_done: - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); buffer_done: len = strnlen(buf, PAGE_SIZE); @@ -3765,15 +3766,14 @@ lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val) static void lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) { - struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; + unsigned long iflags; #if (IS_ENABLED(CONFIG_NVME_FC)) struct lpfc_nvme_rport *rport; struct nvme_fc_remote_port *remoteport = NULL; #endif - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; @@ -3788,7 +3788,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) vport->cfg_devloss_tmo); #endif } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); } /** @@ -3974,8 +3974,8 @@ lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH, static int lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; + unsigned long iflags; if (!lpfc_rangecheck(val, LPFC_MIN_TGT_QDEPTH, LPFC_MAX_TGT_QDEPTH)) return -EINVAL; @@ -3983,14 +3983,13 @@ lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val) if (val == vport->cfg_tgt_queue_depth) return 0; - spin_lock_irq(shost->host_lock); vport->cfg_tgt_queue_depth = val; /* Next loop thru nodelist and change cmd_qdepth */ + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; - - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); return 0; } @@ -5236,8 +5235,8 @@ lpfc_vport_param_show(max_scsicmpl_time); static int lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp, *next_ndlp; + unsigned long iflags; if (val == vport->cfg_max_scsicmpl_time) return 0; @@ -5245,13 +5244,13 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) return -EINVAL; vport->cfg_max_scsicmpl_time = val; - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); return 0; } lpfc_vport_param_store(max_scsicmpl_time); @@ -6853,17 +6852,19 @@ lpfc_get_node_by_target(struct scsi_target *starget) struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_nodelist *ndlp; + unsigned long iflags; - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); /* Search for this, mapped, target ID */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && starget->id == ndlp->nlp_sid) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, + iflags); return ndlp; } } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 315db836404a..633b8ba25bc3 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1853,11 +1853,10 @@ static uint32_t lpfc_find_map_node(struct lpfc_vport *vport) { struct lpfc_nodelist *ndlp, *next_ndlp; - struct Scsi_Host *shost; + unsigned long iflags; uint32_t cnt = 0; - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_type & NLP_FABRIC) continue; @@ -1865,7 +1864,7 @@ lpfc_find_map_node(struct lpfc_vport *vport) (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)) cnt++; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); return cnt; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index ea9b42225e62..03abc401c5f2 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -806,10 +806,10 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) { int len = 0; int i, iocnt, outio, cnt; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; unsigned char *statep; + unsigned long iflags; struct nvme_fc_local_port *localport; struct nvme_fc_remote_port *nrport = NULL; struct lpfc_nvme_rport *rport; @@ -818,7 +818,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) outio = 0; len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n"); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { iocnt = 0; if (!cnt) { @@ -908,7 +908,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_defer_did); len += scnprintf(buf+len, size-len, "\n"); } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); len += scnprintf(buf + len, size - len, "\nOutstanding IO x%x\n", outio); @@ -940,8 +940,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) if (!localport) goto out_exit; - spin_lock_irq(shost->host_lock); - /* Port state is only one of two values for now. */ if (localport->port_id) statep = "ONLINE"; @@ -953,6 +951,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) localport->port_id, statep); len += scnprintf(buf + len, size - len, "\tRport List:\n"); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { /* local short-hand pointer. */ spin_lock(&ndlp->lock); @@ -1006,8 +1005,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) /* Terminate the string. */ len += scnprintf(buf + len, size - len, "\n"); } - - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); out_exit: return len; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7c4356d87730..08acd5d398aa 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4860,10 +4860,10 @@ void lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int state) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); int old_state = ndlp->nlp_state; int node_dropped = ndlp->nlp_flag & NLP_DROPPED; char name1[16], name2[16]; + unsigned long iflags; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0904 NPort state transition x%06x, %s -> %s\n", @@ -4890,9 +4890,9 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } if (list_empty(&ndlp->nlp_listp)) { - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); } else if (old_state) lpfc_nlp_counters(vport, old_state, -1); @@ -4904,26 +4904,26 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + unsigned long iflags; if (list_empty(&ndlp->nlp_listp)) { - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); } } void lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + unsigned long iflags; lpfc_cancel_retry_delay_tmo(vport, ndlp); if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) lpfc_nlp_counters(vport, ndlp->nlp_state, -1); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_del_init(&ndlp->nlp_listp); - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, NLP_STE_UNUSED_NODE); } @@ -5421,8 +5421,8 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) { struct lpfc_vport **vports; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; int i; + unsigned long iflags; vports = lpfc_create_vport_work_array(phba); if (!vports) { @@ -5431,17 +5431,18 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) return; } for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { /* The mempool_alloc might sleep */ - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, + iflags); lpfc_unreg_rpi(vports[i], ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, + iflags); } } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags); } lpfc_destroy_vport_work_array(phba, vports); } @@ -5683,12 +5684,11 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) struct lpfc_nodelist * lpfc_findnode_mapped(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; uint32_t data1; unsigned long iflags; - spin_lock_irqsave(shost->host_lock, iflags); + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || @@ -5697,7 +5697,8 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) ((uint32_t)ndlp->nlp_xri << 16) | ((uint32_t)ndlp->nlp_type << 8) | ((uint32_t)ndlp->nlp_rpi & 0xff)); - spin_unlock_irqrestore(shost->host_lock, iflags); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, + iflags); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE, "2025 FIND node DID MAPPED " "Data: x%px x%x x%x x%x x%px\n", @@ -5707,7 +5708,7 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) return ndlp; } } - spin_unlock_irqrestore(shost->host_lock, iflags); + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); /* FIND node did NOT FOUND */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -6742,7 +6743,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) struct lpfc_vport **vports; int i, ret = 0; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; + unsigned long iflags; vports = lpfc_create_vport_work_array(phba); @@ -6751,8 +6752,6 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) return 1; for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); /* * IF the CVL_RCVD bit is not set then we have sent the * flogi. @@ -6760,15 +6759,16 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) * unreg the fcf. */ if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) { - spin_unlock_irq(shost->host_lock); ret = 1; goto out; } + spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { if (ndlp->rport && (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { ret = 1; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, + iflags); goto out; } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { ret = 1; @@ -6780,7 +6780,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) ndlp->nlp_flag); } } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags); } out: lpfc_destroy_vport_work_array(phba, vports); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1285a7bbdced..c43118fab4aa 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3829,7 +3829,6 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) vports[i]->fc_flag &= ~FC_VFI_REGISTERED; spin_unlock_irq(shost->host_lock); - shost = lpfc_shost_from_vport(vports[i]); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { @@ -4833,6 +4832,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) /* Initialize all internally managed lists. */ INIT_LIST_HEAD(&vport->fc_nodes); + spin_lock_init(&vport->fc_nodes_list_lock); INIT_LIST_HEAD(&vport->rcv_buffer_list); spin_lock_init(&vport->work_port_lock); From a645b8c1f5bcfc5d6ce8cb8eb2015bcbc4b37909 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:09 -0800 Subject: [PATCH 203/814] scsi: lpfc: Change lpfc_vport fc_flag member into a bitmask In attempt to reduce the amount of unnecessary shost_lock acquisitions in the lpfc driver, change fc_flag into an unsigned long bitmask and use clear_bit/test_bit bitwise atomic APIs instead of reliance on shost_lock for synchronization. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-15-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 59 ++--- drivers/scsi/lpfc/lpfc_attr.c | 51 ++-- drivers/scsi/lpfc/lpfc_bsg.c | 6 +- drivers/scsi/lpfc/lpfc_ct.c | 132 +++++------ drivers/scsi/lpfc/lpfc_els.c | 360 +++++++++++------------------ drivers/scsi/lpfc/lpfc_hbadisc.c | 218 +++++++---------- drivers/scsi/lpfc/lpfc_init.c | 53 ++--- drivers/scsi/lpfc/lpfc_mbox.c | 8 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 68 +++--- drivers/scsi/lpfc/lpfc_sli.c | 14 +- drivers/scsi/lpfc/lpfc_vport.c | 46 ++-- 11 files changed, 425 insertions(+), 590 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index da9f87f89941..18c0adceaa6f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -535,6 +535,36 @@ struct lpfc_cgn_acqe_stat { atomic64_t warn; }; +enum lpfc_fc_flag { + /* Several of these flags are HBA centric and should be moved to + * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP) + */ + FC_PT2PT, /* pt2pt with no fabric */ + FC_PT2PT_PLOGI, /* pt2pt initiate PLOGI */ + FC_DISC_TMO, /* Discovery timer running */ + FC_PUBLIC_LOOP, /* Public loop */ + FC_LBIT, /* LOGIN bit in loopinit set */ + FC_RSCN_MODE, /* RSCN cmd rcv'ed */ + FC_NLP_MORE, /* More node to process in node tbl */ + FC_OFFLINE_MODE, /* Interface is offline for diag */ + FC_FABRIC, /* We are fabric attached */ + FC_VPORT_LOGO_RCVD, /* LOGO received on vport */ + FC_RSCN_DISCOVERY, /* Auth all devices after RSCN */ + FC_LOGO_RCVD_DID_CHNG, /* FDISC on phys port detect DID chng */ + FC_PT2PT_NO_NVME, /* Don't send NVME PRLI */ + FC_SCSI_SCAN_TMO, /* scsi scan timer running */ + FC_ABORT_DISCOVERY, /* we want to abort discovery */ + FC_NDISC_ACTIVE, /* NPort discovery active */ + FC_BYPASSED_MODE, /* NPort is in bypassed mode */ + FC_VPORT_NEEDS_REG_VPI, /* Needs to have its vpi registered */ + FC_RSCN_DEFERRED, /* A deferred RSCN being processed */ + FC_VPORT_NEEDS_INIT_VPI, /* Need to INIT_VPI before FDISC */ + FC_VPORT_CVL_RCVD, /* VLink failed due to CVL */ + FC_VFI_REGISTERED, /* VFI is registered */ + FC_FDISC_COMPLETED, /* FDISC completed */ + FC_DISC_DELAYED, /* Delay NPort discovery */ +}; + struct lpfc_vport { struct lpfc_hba *phba; struct list_head listentry; @@ -549,34 +579,7 @@ struct lpfc_vport { uint8_t vpi_state; #define LPFC_VPI_REGISTERED 0x1 - uint32_t fc_flag; /* FC flags */ -/* Several of these flags are HBA centric and should be moved to - * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP) - */ -#define FC_PT2PT 0x1 /* pt2pt with no fabric */ -#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */ -#define FC_DISC_TMO 0x4 /* Discovery timer running */ -#define FC_PUBLIC_LOOP 0x8 /* Public loop */ -#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */ -#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */ -#define FC_NLP_MORE 0x40 /* More node to process in node tbl */ -#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */ -#define FC_FABRIC 0x100 /* We are fabric attached */ -#define FC_VPORT_LOGO_RCVD 0x200 /* LOGO received on vport */ -#define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */ -#define FC_LOGO_RCVD_DID_CHNG 0x800 /* FDISC on phys port detect DID chng*/ -#define FC_PT2PT_NO_NVME 0x1000 /* Don't send NVME PRLI */ -#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ -#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ -#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ -#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ -#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ -#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ -#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */ -#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ -#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ -#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ -#define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */ + unsigned long fc_flag; /* FC flags */ uint32_t ct_flags; #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 023f4f2c62a6..55289abb6cf7 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1092,14 +1092,14 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, break; } if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - if (vport->fc_flag & FC_PUBLIC_LOOP) + if (test_bit(FC_PUBLIC_LOOP, &vport->fc_flag)) len += scnprintf(buf + len, PAGE_SIZE-len, " Public Loop\n"); else len += scnprintf(buf + len, PAGE_SIZE-len, " Private Loop\n"); } else { - if (vport->fc_flag & FC_FABRIC) { + if (test_bit(FC_FABRIC, &vport->fc_flag)) { if (phba->sli_rev == LPFC_SLI_REV4 && vport->port_type == LPFC_PHYSICAL_PORT && phba->sli4_hba.fawwpn_flag & @@ -1291,7 +1291,7 @@ lpfc_issue_lip(struct Scsi_Host *shost) * If the link is offline, disabled or BLOCK_MGMT_IO * it doesn't make any sense to allow issue_lip */ - if ((vport->fc_flag & FC_OFFLINE_MODE) || + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) || (phba->hba_flag & LINK_DISABLED) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; @@ -1305,8 +1305,8 @@ lpfc_issue_lip(struct Scsi_Host *shost) pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; pmboxq->u.mb.mbxOwner = OWN_HOST; - if ((vport->fc_flag & FC_PT2PT) && (vport->fc_flag & FC_PT2PT_NO_NVME)) - vport->fc_flag &= ~FC_PT2PT_NO_NVME; + if (test_bit(FC_PT2PT, &vport->fc_flag)) + clear_bit(FC_PT2PT_NO_NVME, &vport->fc_flag); mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); @@ -1496,7 +1496,8 @@ lpfc_reset_pci_bus(struct lpfc_hba *phba) if (shost) { phba_other = ((struct lpfc_vport *)shost->hostdata)->phba; - if (!(phba_other->pport->fc_flag & FC_OFFLINE_MODE)) { + if (!test_bit(FC_OFFLINE_MODE, + &phba_other->pport->fc_flag)) { lpfc_printf_log(phba_other, KERN_INFO, LOG_INIT, "8349 WWPN = 0x%02x%02x%02x%02x" "%02x%02x%02x%02x is not " @@ -1551,7 +1552,7 @@ lpfc_selective_reset(struct lpfc_hba *phba) if (!phba->cfg_enable_hba_reset) return -EACCES; - if (!(phba->pport->fc_flag & FC_OFFLINE_MODE)) { + if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) { status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); if (status != 0) @@ -1690,7 +1691,7 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) { struct completion online_compl; struct pci_dev *pdev = phba->pcidev; - uint32_t before_fc_flag; + unsigned long before_fc_flag; uint32_t sriov_nr_virtfn; uint32_t reg_val; int status = 0, rc = 0; @@ -1761,7 +1762,7 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) } /* keep the original port state */ - if (before_fc_flag & FC_OFFLINE_MODE) { + if (test_bit(FC_OFFLINE_MODE, &before_fc_flag)) { if (phba->fw_dump_cmpl) phba->fw_dump_cmpl = NULL; goto out; @@ -2099,7 +2100,7 @@ board_mode_out: *board_mode_str = '\0'; lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "3097 Failed \"%s\", status(%d), " - "fc_flag(x%x)\n", + "fc_flag(x%lx)\n", buf, status, phba->pport->fc_flag); return status; } @@ -2158,7 +2159,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, pmb->mbxOwner = OWN_HOST; pmboxq->ctx_buf = NULL; - if (phba->pport->fc_flag & FC_OFFLINE_MODE) + if (test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) rc = MBX_NOT_FINISHED; else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -6200,7 +6201,7 @@ sysfs_ctlreg_write(struct file *filp, struct kobject *kobj, if (memcmp(buf, LPFC_REG_WRITE_KEY, LPFC_REG_WRITE_KEY_SIZE)) return -EINVAL; - if (!(vport->fc_flag & FC_OFFLINE_MODE)) + if (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) return -EPERM; spin_lock_irq(&phba->hbalock); @@ -6433,12 +6434,12 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) fc_host_port_type(shost) = FC_PORTTYPE_NPIV; } else if (lpfc_is_link_up(phba)) { if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - if (vport->fc_flag & FC_PUBLIC_LOOP) + if (test_bit(FC_PUBLIC_LOOP, &vport->fc_flag)) fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; else fc_host_port_type(shost) = FC_PORTTYPE_LPORT; } else { - if (vport->fc_flag & FC_FABRIC) + if (test_bit(FC_FABRIC, &vport->fc_flag)) fc_host_port_type(shost) = FC_PORTTYPE_NPORT; else fc_host_port_type(shost) = FC_PORTTYPE_PTP; @@ -6457,7 +6458,7 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - if (vport->fc_flag & FC_OFFLINE_MODE) + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; else { switch (phba->link_state) { @@ -6571,10 +6572,10 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) struct lpfc_hba *phba = vport->phba; u64 node_name; - if ((vport->port_state > LPFC_FLOGI) && - ((vport->fc_flag & FC_FABRIC) || - ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - (vport->fc_flag & FC_PUBLIC_LOOP)))) + if (vport->port_state > LPFC_FLOGI && + (test_bit(FC_FABRIC, &vport->fc_flag) || + (phba->fc_topology == LPFC_TOPOLOGY_LOOP && + test_bit(FC_PUBLIC_LOOP, &vport->fc_flag)))) node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn); else /* fabric is local port if there is no F/FL_Port */ @@ -6630,7 +6631,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) { + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6683,7 +6684,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) { + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6770,8 +6771,8 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) || + !(psli->sli_flag & LPFC_SLI_ACTIVE)) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6792,8 +6793,8 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) || + !(psli->sli_flag & LPFC_SLI_ACTIVE)) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 595dca92e8db..095914854dda 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1977,7 +1977,7 @@ lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode, static int lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) { - if (phba->pport->fc_flag & FC_VFI_REGISTERED) { + if (test_bit(FC_VFI_REGISTERED, &phba->pport->fc_flag)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "3136 Port still had vfi registered: " "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", @@ -3448,7 +3448,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, case MBX_RUN_DIAGS: case MBX_RESTART: case MBX_SET_MASK: - if (!(vport->fc_flag & FC_OFFLINE_MODE)) { + if (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2743 Command 0x%x is illegal in on-line " "state\n", @@ -4886,7 +4886,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; job->dd_data = dd_data; - if ((vport->fc_flag & FC_OFFLINE_MODE) || + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) || (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); if (rc != MBX_SUCCESS) { diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 633b8ba25bc3..20520c7f58f6 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -265,7 +265,7 @@ ct_free_mp: kfree(mp); ct_exit: lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "6440 Unsol CT: Rsp err %d Data: x%x\n", + "6440 Unsol CT: Rsp err %d Data: x%lx\n", rc, vport->fc_flag); } @@ -298,7 +298,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) } /* Ignore traffic received during vport shutdown */ - if (vport->fc_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->fc_flag)) return; ndlp = lpfc_findnode_did(vport, did); @@ -723,7 +723,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) if (ndlp) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "Parse GID_FTrsp: did:x%x flg:x%x x%x", + "Parse GID_FTrsp: did:x%x flg:x%lx x%x", Did, ndlp->nlp_flag, vport->fc_flag); /* By default, the driver expects to support FCP FC4 */ @@ -735,7 +735,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0238 Process x%06x NameServer Rsp " - "Data: x%x x%x x%x x%x x%x\n", Did, + "Data: x%x x%x x%x x%lx x%x\n", Did, ndlp->nlp_flag, ndlp->nlp_fc4_type, ndlp->nlp_state, vport->fc_flag, vport->fc_rscn_id_cnt); @@ -751,20 +751,20 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) } } else { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "Skip1 GID_FTrsp: did:x%x flg:x%x cnt:%d", + "Skip1 GID_FTrsp: did:x%x flg:x%lx cnt:%d", Did, vport->fc_flag, vport->fc_rscn_id_cnt); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0239 Skip x%06x NameServer Rsp " - "Data: x%x x%x x%px\n", + "Data: x%lx x%x x%px\n", Did, vport->fc_flag, vport->fc_rscn_id_cnt, ndlp); } } else { - if (!(vport->fc_flag & FC_RSCN_MODE) || + if (!test_bit(FC_RSCN_MODE, &vport->fc_flag) || lpfc_rscn_payload_check(vport, Did)) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "Query GID_FTrsp: did:x%x flg:x%x cnt:%d", + "Query GID_FTrsp: did:x%x flg:x%lx cnt:%d", Did, vport->fc_flag, vport->fc_rscn_id_cnt); /* @@ -787,12 +787,12 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_setup_disc_node(vport, Did); } else { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "Skip2 GID_FTrsp: did:x%x flg:x%x cnt:%d", + "Skip2 GID_FTrsp: did:x%x flg:x%lx cnt:%d", Did, vport->fc_flag, vport->fc_rscn_id_cnt); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0245 Skip x%06x NameServer Rsp " - "Data: x%x x%x\n", Did, + "Data: x%lx x%x\n", Did, vport->fc_flag, vport->fc_rscn_id_cnt); } @@ -914,7 +914,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_dmabuf *outp; struct lpfc_dmabuf *inp; struct lpfc_sli_ct_request *CTrsp; @@ -945,7 +944,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Skip processing response on pport if unloading */ if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); goto out; } @@ -953,7 +952,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_chk_latt(vport)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0216 Link event during NS query\n"); - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out; @@ -961,22 +960,18 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_error_lost_link(vport, ulp_status, ulp_word4)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0226 NS query failed due to link event: " - "ulp_status x%x ulp_word4 x%x fc_flag x%x " + "ulp_status x%x ulp_word4 x%x fc_flag x%lx " "port_state x%x gidft_inp x%x\n", ulp_status, ulp_word4, vport->fc_flag, vport->port_state, vport->gidft_inp); - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); if (vport->gidft_inp) vport->gidft_inp--; goto out; } - spin_lock_irq(shost->host_lock); - if (vport->fc_flag & FC_RSCN_DEFERRED) { - vport->fc_flag &= ~FC_RSCN_DEFERRED; - spin_unlock_irq(shost->host_lock); - + if (test_and_clear_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) { /* This is a GID_FT completing so the gidft_inp counter was * incremented before the GID_FT was issued to the wire. */ @@ -988,13 +983,12 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * Re-issue the NS cmd */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0151 Process Deferred RSCN Data: x%x x%x\n", + "0151 Process Deferred RSCN Data: x%lx x%x\n", vport->fc_flag, vport->fc_rscn_id_cnt); lpfc_els_handle_rscn(vport); goto out; } - spin_unlock_irq(shost->host_lock); if (ulp_status) { /* Check for retry */ @@ -1018,7 +1012,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, vport->gidft_inp--; } } - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -1031,7 +1025,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0208 NameServer Rsp Data: x%x x%x " + "0208 NameServer Rsp Data: x%lx x%x " "x%x x%x sz x%x\n", vport->fc_flag, CTreq->un.gid.Fc4Type, @@ -1051,7 +1045,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0269 No NameServer Entries " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation, @@ -1066,7 +1060,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0240 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation, @@ -1084,7 +1078,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* NameServer Rsp Error */ lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0241 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation, @@ -1113,14 +1107,13 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * current driver state. */ if (vport->port_state >= LPFC_DISC_AUTH) { - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { + lpfc_els_flush_rscn(vport); + /* RSCN still */ + set_bit(FC_RSCN_MODE, &vport->fc_flag); + } else { lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ - spin_unlock_irq(shost->host_lock); } - else - lpfc_els_flush_rscn(vport); } lpfc_disc_start(vport); @@ -1136,7 +1129,6 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_dmabuf *outp; struct lpfc_dmabuf *inp; struct lpfc_sli_ct_request *CTrsp; @@ -1168,7 +1160,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Skip processing response on pport if unloading */ if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); goto out; } @@ -1176,7 +1168,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_chk_latt(vport)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "4108 Link event during NS query\n"); - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out; @@ -1184,22 +1176,18 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_error_lost_link(vport, ulp_status, ulp_word4)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "4166 NS query failed due to link event: " - "ulp_status x%x ulp_word4 x%x fc_flag x%x " + "ulp_status x%x ulp_word4 x%x fc_flag x%lx " "port_state x%x gidft_inp x%x\n", ulp_status, ulp_word4, vport->fc_flag, vport->port_state, vport->gidft_inp); - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); if (vport->gidft_inp) vport->gidft_inp--; goto out; } - spin_lock_irq(shost->host_lock); - if (vport->fc_flag & FC_RSCN_DEFERRED) { - vport->fc_flag &= ~FC_RSCN_DEFERRED; - spin_unlock_irq(shost->host_lock); - + if (test_and_clear_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) { /* This is a GID_PT completing so the gidft_inp counter was * incremented before the GID_PT was issued to the wire. */ @@ -1211,13 +1199,12 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * Re-issue the NS cmd */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "4167 Process Deferred RSCN Data: x%x x%x\n", + "4167 Process Deferred RSCN Data: x%lx x%x\n", vport->fc_flag, vport->fc_rscn_id_cnt); lpfc_els_handle_rscn(vport); goto out; } - spin_unlock_irq(shost->host_lock); if (ulp_status) { /* Check for retry */ @@ -1237,7 +1224,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, vport->gidft_inp--; } } - if (vport->fc_flag & FC_RSCN_MODE) + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -1250,7 +1237,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) == SLI_CT_RESPONSE_FS_ACC) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4105 NameServer Rsp Data: x%x x%x " + "4105 NameServer Rsp Data: x%lx x%x " "x%x x%x sz x%x\n", vport->fc_flag, CTreq->un.gid.Fc4Type, @@ -1270,7 +1257,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog( vport, KERN_INFO, LOG_DISCOVERY, "4106 No NameServer Entries " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t)CTrsp->ReasonCode, (uint32_t)CTrsp->Explanation, @@ -1286,7 +1273,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog( vport, KERN_INFO, LOG_DISCOVERY, "4107 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t)CTrsp->ReasonCode, (uint32_t)CTrsp->Explanation, @@ -1303,7 +1290,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* NameServer Rsp Error */ lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4109 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%lx\n", be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp), (uint32_t)CTrsp->ReasonCode, (uint32_t)CTrsp->Explanation, @@ -1333,11 +1320,10 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * current driver state. */ if (vport->port_state >= LPFC_DISC_AUTH) { - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ - spin_unlock_irq(shost->host_lock); + /* RSCN still */ + set_bit(FC_RSCN_MODE, &vport->fc_flag); } else { lpfc_els_flush_rscn(vport); } @@ -1355,7 +1341,6 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf; struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf; struct lpfc_sli_ct_request *CTrsp; @@ -1445,7 +1430,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0267 NameServer GFF Rsp " - "x%x Error (%d %d) Data: x%x x%x\n", + "x%x Error (%d %d) Data: x%lx x%x\n", did, ulp_status, ulp_word4, vport->fc_flag, vport->fc_rscn_id_cnt); } @@ -1455,13 +1440,13 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0242 Process x%x GFF " - "NameServer Rsp Data: x%x x%x x%x\n", + "NameServer Rsp Data: x%x x%lx x%x\n", did, ndlp->nlp_flag, vport->fc_flag, vport->fc_rscn_id_cnt); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0243 Skip x%x GFF " - "NameServer Rsp Data: x%x x%x\n", did, + "NameServer Rsp Data: x%lx x%x\n", did, vport->fc_flag, vport->fc_rscn_id_cnt); } out: @@ -1480,14 +1465,13 @@ out: * current driver state. */ if (vport->port_state >= LPFC_DISC_AUTH) { - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { + lpfc_els_flush_rscn(vport); + /* RSCN still */ + set_bit(FC_RSCN_MODE, &vport->fc_flag); + } else { lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ - spin_unlock_irq(shost->host_lock); } - else - lpfc_els_flush_rscn(vport); } lpfc_disc_start(vport); } @@ -1949,7 +1933,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, /* NameServer Req */ lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY, - "0236 NameServer Req Data: x%x x%x x%x x%x\n", + "0236 NameServer Req Data: x%x x%lx x%x x%x\n", cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt, context); @@ -2166,7 +2150,8 @@ ns_cmd_free_mp: kfree(mp); ns_cmd_exit: lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, - "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n", + "0266 Issue NameServer Req x%x err %d Data: x%lx " + "x%x\n", cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt); return 1; } @@ -2452,7 +2437,7 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) return; /* Must be connected to a Fabric */ - if (!(vport->fc_flag & FC_FABRIC)) + if (!test_bit(FC_FABRIC, &vport->fc_flag)) return; ndlp = lpfc_findnode_did(vport, FDMI_DID); @@ -3232,7 +3217,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* FDMI request */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0218 FDMI Request x%x mask x%x Data: x%x x%x x%x\n", + "0218 FDMI Request x%x mask x%x Data: x%x x%lx x%x\n", cmdcode, new_mask, vport->fdmi_port_mask, vport->fc_flag, vport->port_state); @@ -3469,15 +3454,8 @@ lpfc_delayed_disc_tmo(struct timer_list *t) void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - if (!(vport->fc_flag & FC_DISC_DELAYED)) { - spin_unlock_irq(shost->host_lock); + if (!test_and_clear_bit(FC_DISC_DELAYED, &vport->fc_flag)) return; - } - vport->fc_flag &= ~FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); lpfc_do_scr_ns_plogi(vport->phba, vport); } @@ -3728,7 +3706,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport, INIT_LIST_HEAD(&bmp->list); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "3275 VMID Request Data: x%x x%x x%x\n", + "3275 VMID Request Data: x%lx x%x x%x\n", vport->fc_flag, vport->port_state, cmdcode); ctreq = (struct lpfc_sli_ct_request *)mp->virt; data = mp->virt; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e01583e2690b..4c2666494e49 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -93,7 +93,6 @@ static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid); int lpfc_els_chk_latt(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; uint32_t ha_copy; @@ -121,9 +120,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) * will cleanup any left over in-progress discovery * events. */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_ABORT_DISCOVERY; - spin_unlock_irq(shost->host_lock); + set_bit(FC_ABORT_DISCOVERY, &vport->fc_flag); if (phba->link_state != LPFC_CLEAR_LA) lpfc_issue_clear_la(phba, vport); @@ -301,7 +298,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0116 Xmit ELS command x%x to remote " "NPORT x%x I/O tag: x%x, port state:x%x " - "rpi x%x fc_flag:x%x\n", + "rpi x%x fc_flag:x%lx\n", elscmd, did, elsiocb->iotag, vport->port_state, ndlp->nlp_rpi, vport->fc_flag); @@ -310,7 +307,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0117 Xmit ELS response x%x to remote " "NPORT x%x I/O tag: x%x, size: x%x " - "port_state x%x rpi x%x fc_flag x%x\n", + "port_state x%x rpi x%x fc_flag x%lx\n", elscmd, ndlp->nlp_DID, elsiocb->iotag, cmd_size, vport->port_state, ndlp->nlp_rpi, vport->fc_flag); @@ -452,7 +449,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ if ((phba->sli_rev == LPFC_SLI_REV4) && !(phba->link_flag & LS_LOOPBACK_MODE) && - !(vport->fc_flag & FC_PT2PT)) { + !test_bit(FC_PT2PT, &vport->fc_flag)) { ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { rc = -ENODEV; @@ -467,7 +464,8 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) } /* Supply CSP's only if we are fabric connect or pt-to-pt connect */ - if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) { + if (test_bit(FC_FABRIC, &vport->fc_flag) || + test_bit(FC_PT2PT, &vport->fc_flag)) { rc = lpfc_mbox_rsrc_prep(phba, mboxq); if (rc) { rc = -ENOMEM; @@ -520,7 +518,6 @@ int lpfc_issue_unreg_vfi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost; LPFC_MBOXQ_t *mboxq; int rc; @@ -546,10 +543,7 @@ lpfc_issue_unreg_vfi(struct lpfc_vport *vport) return -EIO; } - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VFI_REGISTERED, &vport->fc_flag); return 0; } @@ -577,7 +571,6 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport, { struct lpfc_hba *phba = vport->phba; uint8_t fabric_param_changed = 0; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if ((vport->fc_prevDID != vport->fc_myDID) || memcmp(&vport->fabric_portname, &sp->portName, @@ -599,11 +592,8 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport, * - lpfc_delay_discovery module parameter is set. */ if (fabric_param_changed && !sp->cmn.clean_address_bit && - (vport->fc_prevDID || phba->cfg_delay_discovery)) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); - } + (vport->fc_prevDID || phba->cfg_delay_discovery)) + set_bit(FC_DISC_DELAYED, &vport->fc_flag); return fabric_param_changed; } @@ -633,15 +623,12 @@ static int lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct serv_parm *sp, uint32_t ulp_word4) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *np; struct lpfc_nodelist *next_np; uint8_t fabric_param_changed; - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_FABRIC; - spin_unlock_irq(shost->host_lock); + set_bit(FC_FABRIC, &vport->fc_flag); phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov); if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ @@ -650,11 +637,8 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_edtovResol = sp->cmn.edtovResolution; phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PUBLIC_LOOP; - spin_unlock_irq(shost->host_lock); - } + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) + set_bit(FC_PUBLIC_LOOP, &vport->fc_flag); vport->fc_myDID = ulp_word4 & Mask_DID; memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name)); @@ -728,12 +712,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_unregister_fcf_prep(phba); /* This should just update the VFI CSPs*/ - if (vport->fc_flag & FC_VFI_REGISTERED) + if (test_bit(FC_VFI_REGISTERED, &vport->fc_flag)) lpfc_issue_reg_vfi(vport); } if (fabric_param_changed && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + !test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) { /* If our NportID changed, we need to ensure all * remaining NPORTs get unreg_login'ed. @@ -753,20 +737,16 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev == LPFC_SLI_REV4) { lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); } /* * For SLI3 and SLI4, the VPI needs to be reregistered in * response to this fabric parameter change event. */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); } else if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + !test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) { /* * Driver needs to re-reg VPI in order for f/w * to update the MAC address. @@ -779,18 +759,18 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev < LPFC_SLI_REV4) { lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && - vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) lpfc_register_new_vport(phba, vport, ndlp); else lpfc_issue_fabric_reglogin(vport); } else { ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) && - (vport->vpi_state & LPFC_VPI_REGISTERED)) { + if ((!test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) && + (vport->vpi_state & LPFC_VPI_REGISTERED)) { lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); - } else if (vport->fc_flag & FC_VFI_REGISTERED) + } else if (test_bit(FC_VFI_REGISTERED, &vport->fc_flag)) lpfc_issue_init_vpi(vport); else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -826,15 +806,13 @@ static int lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct serv_parm *sp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mbox; int rc; - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - vport->fc_flag |= FC_PT2PT; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); + set_bit(FC_PT2PT, &vport->fc_flag); /* If we are pt2pt with another NPort, force NPIV off! */ phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; @@ -842,10 +820,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) { lpfc_unregister_fcf_prep(phba); - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VFI_REGISTERED, &vport->fc_flag); phba->fc_topology_changed = 0; } @@ -854,9 +829,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (rc >= 0) { /* This side will initiate the PLOGI */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT_PLOGI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_PT2PT_PLOGI, &vport->fc_flag); /* * N_Port ID cannot be 0, set our Id to LocalID @@ -953,7 +926,6 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = cmdiocb->ndlp; IOCB_t *irsp; struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf, *prsp; @@ -1069,10 +1041,9 @@ stop_rr_fcf_flogi: } /* FLOGI failed, so there is no fabric */ - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP | - FC_PT2PT_NO_NVME); - spin_unlock_irq(shost->host_lock); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); + clear_bit(FC_PT2PT_NO_NVME, &vport->fc_flag); /* If private loop, then allow max outstanding els to be * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no @@ -1081,15 +1052,14 @@ stop_rr_fcf_flogi: if (phba->alpa_map[0] == 0) vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; if ((phba->sli_rev == LPFC_SLI_REV4) && - (!(vport->fc_flag & FC_VFI_REGISTERED) || + (!test_bit(FC_VFI_REGISTERED, &vport->fc_flag) || (vport->fc_prevDID != vport->fc_myDID) || phba->fc_topology_changed)) { - if (vport->fc_flag & FC_VFI_REGISTERED) { + if (test_bit(FC_VFI_REGISTERED, &vport->fc_flag)) { if (phba->fc_topology_changed) { lpfc_unregister_fcf_prep(phba); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VFI_REGISTERED, + &vport->fc_flag); phba->fc_topology_changed = 0; } else { lpfc_sli4_unreg_all_rpis(vport); @@ -1104,10 +1074,8 @@ stop_rr_fcf_flogi: } goto flogifail; } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_CVL_RCVD; - vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VPORT_CVL_RCVD, &vport->fc_flag); + clear_bit(FC_VPORT_LOGO_RCVD, &vport->fc_flag); /* * The FLOGI succeeded. Sync the data for the CPU before @@ -1123,7 +1091,7 @@ stop_rr_fcf_flogi: /* FLOGI completes successfully */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0101 FLOGI completes successfully, I/O tag:x%x " - "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x %d\n", + "xri x%x Data: x%x x%x x%x x%x x%x x%lx x%x %d\n", cmdiocb->iotag, cmdiocb->sli4_xritag, ulp_word4, sp->cmn.e_d_tov, sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution, @@ -1202,7 +1170,7 @@ stop_rr_fcf_flogi: goto out; } } else if (vport->port_state > LPFC_FLOGI && - vport->fc_flag & FC_PT2PT) { + test_bit(FC_PT2PT, &vport->fc_flag)) { /* * In a p2p topology, it is possible that discovery has * already progressed, and this completion can be ignored. @@ -1506,8 +1474,9 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) if (ulp_command == CMD_ELS_REQUEST64_CR) { ndlp = iocb->ndlp; if (ndlp && ndlp->nlp_DID == Fabric_DID) { - if ((phba->pport->fc_flag & FC_PT2PT) && - !(phba->pport->fc_flag & FC_PT2PT_PLOGI)) + if (test_bit(FC_PT2PT, &phba->pport->fc_flag) && + !test_bit(FC_PT2PT_PLOGI, + &phba->pport->fc_flag)) iocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; lpfc_sli_issue_abort_iotag(phba, pring, iocb, @@ -1562,7 +1531,7 @@ lpfc_initial_flogi(struct lpfc_vport *vport) } /* Reset the Fabric flag, topology change may have happened */ - vport->fc_flag &= ~FC_FABRIC; + clear_bit(FC_FABRIC, &vport->fc_flag); if (lpfc_issue_els_flogi(vport, ndlp, 0)) { /* A node reference should be retained while registered with a * transport or dev-loss-evt work is pending. @@ -1645,12 +1614,12 @@ lpfc_more_plogi(struct lpfc_vport *vport) /* Continue discovery with PLOGIs to go */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0232 Continue discovery with %d PLOGIs to go " - "Data: x%x x%x x%x\n", + "Data: x%x x%lx x%x\n", vport->num_disc_nodes, atomic_read(&vport->fc_plogi_cnt), vport->fc_flag, vport->port_state); /* Check to see if there are more PLOGIs to be sent */ - if (vport->fc_flag & FC_NLP_MORE) + if (test_bit(FC_NLP_MORE, &vport->fc_flag)) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ lpfc_els_disc_plogi(vport); @@ -1769,7 +1738,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, * would have updated nlp_fc4_type in ndlp, so we must ensure * new_ndlp has the right value. */ - if (vport->fc_flag & FC_FABRIC) { + if (test_bit(FC_FABRIC, &vport->fc_flag)) { keep_nlp_fc4_type = new_ndlp->nlp_fc4_type; new_ndlp->nlp_fc4_type = ndlp->nlp_fc4_type; } @@ -1930,21 +1899,17 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, void lpfc_end_rscn(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { /* * Check to see if more RSCNs came in while we were * processing this one. */ if (vport->fc_rscn_id_cnt || - (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) + test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) lpfc_els_handle_rscn(vport); - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } + else + clear_bit(FC_RSCN_MODE, &vport->fc_flag); } } @@ -2031,7 +1996,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_nodelist *ndlp, *free_ndlp; struct lpfc_dmabuf *prsp; @@ -2178,9 +2142,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); lpfc_can_disctmo(vport); lpfc_end_rscn(vport); @@ -2242,7 +2204,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) */ if ((ndlp->nlp_flag & (NLP_IGNR_REG_CMPL | NLP_UNREG_INP)) && ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && - !(vport->fc_flag & FC_OFFLINE_MODE)) { + !test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "4110 Issue PLOGI x%x deferred " "on NPort x%x rpi x%x flg x%x Data:" @@ -2274,7 +2236,8 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) * If we are a N-port connected to a Fabric, fix-up paramm's so logins * to device on remote loops work. */ - if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP)) + if (test_bit(FC_FABRIC, &vport->fc_flag) && + !test_bit(FC_PUBLIC_LOOP, &vport->fc_flag)) sp->cmn.altBbCredit = 1; if (sp->cmn.fcphLow < FC_PH_4_3) @@ -2398,8 +2361,8 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* If we don't send GFT_ID to Fabric, a PRLI error * could be expected. */ - if ((vport->fc_flag & FC_FABRIC) || - (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) { + if (test_bit(FC_FABRIC, &vport->fc_flag) || + vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH) { mode = KERN_ERR; loglevel = LOG_TRACE_EVENT; } else { @@ -2440,7 +2403,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * For P2P topology, retain the node so that PLOGI can be * attempted on it again. */ - if (vport->fc_flag & FC_PT2PT) + if (test_bit(FC_PT2PT, &vport->fc_flag)) goto out; /* As long as this node is not registered with the SCSI @@ -2516,7 +2479,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * the remote NPort beng a NVME Target. */ if (phba->sli_rev == LPFC_SLI_REV4 && - vport->fc_flag & FC_RSCN_MODE && + test_bit(FC_RSCN_MODE, &vport->fc_flag) && vport->nvmei_support) ndlp->nlp_fc4_type |= NLP_FC4_NVME; local_nlp_type = ndlp->nlp_fc4_type; @@ -2713,7 +2676,6 @@ lpfc_rscn_disc(struct lpfc_vport *vport) static void lpfc_adisc_done(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* @@ -2721,7 +2683,7 @@ lpfc_adisc_done(struct lpfc_vport *vport) * and continue discovery. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_RSCN_MODE) && + !test_bit(FC_RSCN_MODE, &vport->fc_flag) && (phba->sli_rev < LPFC_SLI_REV4)) { /* @@ -2750,15 +2712,13 @@ lpfc_adisc_done(struct lpfc_vport *vport) if (vport->port_state < LPFC_VPORT_READY) { /* If we get here, there is nothing to ADISC */ lpfc_issue_clear_la(phba, vport); - if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { + if (!test_bit(FC_ABORT_DISCOVERY, &vport->fc_flag)) { vport->num_disc_nodes = 0; /* go thru NPR list, issue ELS PLOGIs */ if (atomic_read(&vport->fc_npr_cnt)) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); lpfc_can_disctmo(vport); lpfc_end_rscn(vport); } @@ -2785,12 +2745,12 @@ lpfc_more_adisc(struct lpfc_vport *vport) /* Continue discovery with ADISCs to go */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0210 Continue discovery with %d ADISCs to go " - "Data: x%x x%x x%x\n", + "Data: x%x x%lx x%x\n", vport->num_disc_nodes, atomic_read(&vport->fc_adisc_cnt), vport->fc_flag, vport->port_state); /* Check to see if there are more ADISCs to be sent */ - if (vport->fc_flag & FC_NLP_MORE) { + if (test_bit(FC_NLP_MORE, &vport->fc_flag)) { lpfc_set_disctmo(vport); /* go thru NPR nodes and issue any remaining ELS ADISCs */ lpfc_els_disc_adisc(vport); @@ -3635,10 +3595,10 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) /* Not supported for private loop */ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && - !(vport->fc_flag & FC_PUBLIC_LOOP)) + !test_bit(FC_PUBLIC_LOOP, &vport->fc_flag)) return 1; - if (vport->fc_flag & FC_PT2PT) { + if (test_bit(FC_PT2PT, &vport->fc_flag)) { /* find any mapped nport - that would be the other nport */ ndlp = lpfc_findnode_mapped(vport); if (!ndlp) @@ -4416,7 +4376,6 @@ try_rdf: void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_work_evt *evtp; if (!(nlp->nlp_flag & NLP_DELAY_TMO)) @@ -4444,9 +4403,8 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) /* Check if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, + &vport->fc_flag); lpfc_can_disctmo(vport); lpfc_end_rscn(vport); } @@ -4563,7 +4521,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) } break; case ELS_CMD_FDISC: - if (!(vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)) + if (!test_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag)) lpfc_issue_els_fdisc(vport, ndlp, retry); break; } @@ -4801,7 +4759,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Added for Vendor specifc support * Just keep retrying for these Rsn / Exp codes */ - if ((vport->fc_flag & FC_PT2PT) && + if (test_bit(FC_PT2PT, &vport->fc_flag) && cmd == ELS_CMD_NVMEPRLI) { switch (stat.un.b.lsRjtRsnCode) { case LSRJT_UNABLE_TPC: @@ -4814,7 +4772,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "support NVME, disabling NVME\n", stat.un.b.lsRjtRsnCode); retry = 0; - vport->fc_flag |= FC_PT2PT_NO_NVME; + set_bit(FC_PT2PT_NO_NVME, &vport->fc_flag); goto out_retry; } } @@ -5037,7 +4995,7 @@ out_retry: /* If discovery / RSCN timer is running, reset it */ if (timer_pending(&vport->fc_disctmo) || - (vport->fc_flag & FC_RSCN_MODE)) + test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_set_disctmo(vport); } @@ -5423,7 +5381,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ulp_status == 0 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && - (!(vport->fc_flag & FC_PT2PT))) { + !test_bit(FC_PT2PT, &vport->fc_flag)) { if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) { @@ -5795,7 +5753,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " - "RPI: x%x, fc_flag x%x refcnt %d\n", + "RPI: x%x, fc_flag x%lx refcnt %d\n", rc, elsiocb->iotag, elsiocb->sli4_xritag, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, vport->fc_flag, kref_read(&ndlp->kref)); @@ -6001,7 +5959,7 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0152 Xmit EDC ACC response Status: x%x, IoTag: x%x, " "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " - "RPI: x%x, fc_flag x%x\n", + "RPI: x%x, fc_flag x%lx\n", rc, elsiocb->iotag, elsiocb->sli4_xritag, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, vport->fc_flag); @@ -6568,7 +6526,6 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, int lpfc_els_disc_adisc(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp, *next_ndlp; int sentadisc = 0; @@ -6603,18 +6560,13 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) vport->num_disc_nodes++; if (vport->num_disc_nodes >= vport->cfg_discovery_threads) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); + set_bit(FC_NLP_MORE, &vport->fc_flag); break; } } - if (sentadisc == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - } + if (sentadisc == 0) + clear_bit(FC_NLP_MORE, &vport->fc_flag); return sentadisc; } @@ -6640,7 +6592,6 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) int lpfc_els_disc_plogi(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp, *next_ndlp; int sentplogi = 0; @@ -6657,26 +6608,20 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) vport->num_disc_nodes++; if (vport->num_disc_nodes >= vport->cfg_discovery_threads) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); + set_bit(FC_NLP_MORE, &vport->fc_flag); break; } } } lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "6452 Discover PLOGI %d flag x%x\n", + "6452 Discover PLOGI %d flag x%lx\n", sentplogi, vport->fc_flag); - if (sentplogi) { + if (sentplogi) lpfc_set_disctmo(vport); - } - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - } + else + clear_bit(FC_NLP_MORE, &vport->fc_flag); return sentplogi; } @@ -7087,7 +7032,7 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, { desc->tag = cpu_to_be32(RDP_PORT_NAMES_DESC_TAG); - if (vport->fc_flag & FC_FABRIC) { + if (test_bit(FC_FABRIC, &vport->fc_flag)) { memcpy(desc->port_names.wwnn, &vport->fabric_nodename, sizeof(desc->port_names.wwnn)); @@ -7871,9 +7816,10 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport) lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]); vport->fc_rscn_id_list[i] = NULL; } + clear_bit(FC_RSCN_MODE, &vport->fc_flag); + clear_bit(FC_RSCN_DISCOVERY, &vport->fc_flag); spin_lock_irq(shost->host_lock); vport->fc_rscn_id_cnt = 0; - vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY); spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); /* Indicate we are done walking this fc_rscn_id_list */ @@ -7908,7 +7854,7 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) return 0; /* If we are doing a FULL RSCN rediscovery, match everything */ - if (vport->fc_flag & FC_RSCN_DISCOVERY) + if (test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) return did; spin_lock_irq(shost->host_lock); @@ -8087,7 +8033,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, payload_len -= sizeof(uint32_t); /* take off word 0 */ /* RSCN received */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0214 RSCN received Data: x%x x%x x%x x%x\n", + "0214 RSCN received Data: x%lx x%x x%x x%x\n", vport->fc_flag, payload_len, *lp, vport->fc_rscn_id_cnt); @@ -8099,10 +8045,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, FCH_EVT_RSCN, lp[i]); /* Check if RSCN is coming from a direct-connected remote NPort */ - if (vport->fc_flag & FC_PT2PT) { + if (test_bit(FC_PT2PT, &vport->fc_flag)) { /* If so, just ACC it, no other action needed for now */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2024 pt2pt RSCN %08x Data: x%x x%x\n", + "2024 pt2pt RSCN %08x Data: x%lx x%x\n", *lp, vport->fc_flag, payload_len); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); @@ -8146,7 +8092,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* ALL NPortIDs in RSCN are on HBA */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0219 Ignore RSCN " - "Data: x%x x%x x%x x%x\n", + "Data: x%lx x%x x%x x%x\n", vport->fc_flag, payload_len, *lp, vport->fc_rscn_id_cnt); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8157,7 +8103,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); /* Restart disctmo if its already running */ - if (vport->fc_flag & FC_DISC_TMO) { + if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { tmo = ((phba->fc_ratov * 3) + 3); mod_timer(&vport->fc_disctmo, jiffies + @@ -8170,8 +8116,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); if (vport->fc_rscn_flush) { /* Another thread is walking fc_rscn_id_list on this vport */ - vport->fc_flag |= FC_RSCN_DISCOVERY; spin_unlock_irq(shost->host_lock); + set_bit(FC_RSCN_DISCOVERY, &vport->fc_flag); /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return 0; @@ -8184,24 +8130,23 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* If we are already processing an RSCN, save the received * RSCN payload buffer, cmdiocb->cmd_dmabuf to process later. */ - if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag) || + test_bit(FC_NDISC_ACTIVE, &vport->fc_flag)) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV RSCN defer: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_DEFERRED; + set_bit(FC_RSCN_DEFERRED, &vport->fc_flag); /* Restart disctmo if its already running */ - if (vport->fc_flag & FC_DISC_TMO) { + if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { tmo = ((phba->fc_ratov * 3) + 3); mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo)); } if ((rscn_cnt < FC_MAX_HOLD_RSCN) && - !(vport->fc_flag & FC_RSCN_DISCOVERY)) { - vport->fc_flag |= FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); + !test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) { + set_bit(FC_RSCN_MODE, &vport->fc_flag); if (rscn_cnt) { cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt; length = be32_to_cpu(*cmd & ~ELS_CMD_MASK); @@ -8223,16 +8168,15 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Deferred RSCN */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0235 Deferred RSCN " - "Data: x%x x%x x%x\n", + "Data: x%x x%lx x%x\n", vport->fc_rscn_id_cnt, vport->fc_flag, vport->port_state); } else { - vport->fc_flag |= FC_RSCN_DISCOVERY; - spin_unlock_irq(shost->host_lock); + set_bit(FC_RSCN_DISCOVERY, &vport->fc_flag); /* ReDiscovery RSCN */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0234 ReDiscovery RSCN " - "Data: x%x x%x x%x\n", + "Data: x%x x%lx x%x\n", vport->fc_rscn_id_cnt, vport->fc_flag, vport->port_state); } @@ -8248,9 +8192,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "RCV RSCN: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); + set_bit(FC_RSCN_MODE, &vport->fc_flag); vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd; /* Indicate we are done walking fc_rscn_id_list on this vport */ vport->fc_rscn_flush = 0; @@ -8300,7 +8242,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* RSCN processed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0215 RSCN processed Data: x%x x%x x%x x%x x%x x%x\n", + "0215 RSCN processed Data: x%lx x%x x%x x%x x%x x%x\n", vport->fc_flag, 0, vport->fc_rscn_id_cnt, vport->port_state, vport->num_disc_nodes, vport->gidft_inp); @@ -8389,7 +8331,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, LPFC_MBOXQ_t *mbox; uint32_t cmd, did; int rc; - uint32_t fc_flag = 0; + unsigned long fc_flag = 0; uint32_t port_state = 0; /* Clear external loopback plug detected flag */ @@ -8459,9 +8401,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 0; } else if (rc > 0) { /* greater than */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT_PLOGI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_PT2PT_PLOGI, &vport->fc_flag); /* If we have the high WWPN we can assign our own * myDID; otherwise, we have to WAIT for a PLOGI @@ -8480,17 +8420,17 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); fc_flag = vport->fc_flag; port_state = vport->port_state; - vport->fc_flag |= FC_PT2PT; - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - /* Acking an unsol FLOGI. Count 1 for link bounce * work-around. */ vport->rcv_flogi_cnt++; spin_unlock_irq(shost->host_lock); + set_bit(FC_PT2PT, &vport->fc_flag); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3311 Rcv Flogi PS x%x new PS x%x " - "fc_flag x%x new fc_flag x%x\n", + "fc_flag x%lx new fc_flag x%lx\n", port_state, vport->port_state, fc_flag, vport->fc_flag); @@ -10428,8 +10368,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; /* If NPort discovery is delayed drop incoming ELS */ - if ((vport->fc_flag & FC_DISC_DELAYED) && - (cmd != ELS_CMD_PLOGI)) + if (test_bit(FC_DISC_DELAYED, &vport->fc_flag) && + cmd != ELS_CMD_PLOGI) goto dropit; ndlp = lpfc_findnode_did(vport, did); @@ -10473,14 +10413,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ELS command received from NPORT */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0112 ELS command x%x received from NPORT x%x " - "refcnt %d Data: x%x x%x x%x x%x\n", + "refcnt %d Data: x%x x%lx x%x x%x\n", cmd, did, kref_read(&ndlp->kref), vport->port_state, vport->fc_flag, vport->fc_myDID, vport->fc_prevDID); /* reject till our FLOGI completes or PLOGI assigned DID via PT2PT */ if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && (cmd != ELS_CMD_FLOGI) && - !((cmd == ELS_CMD_PLOGI) && (vport->fc_flag & FC_PT2PT))) { + !((cmd == ELS_CMD_PLOGI) && test_bit(FC_PT2PT, &vport->fc_flag))) { rjt_err = LSRJT_LOGICAL_BSY; rjt_exp = LSEXP_NOTHING_MORE; goto lsrjt; @@ -10495,7 +10435,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvPLOGI++; ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); if (phba->sli_rev == LPFC_SLI_REV4 && - (phba->pport->fc_flag & FC_PT2PT)) { + test_bit(FC_PT2PT, &phba->pport->fc_flag)) { vport->fc_prevDID = vport->fc_myDID; /* Our DID needs to be updated before registering * the vfi. This is done in lpfc_rcv_plogi but @@ -10513,15 +10453,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_send_els_event(vport, ndlp, payload); /* If Nport discovery is delayed, reject PLOGIs */ - if (vport->fc_flag & FC_DISC_DELAYED) { + if (test_bit(FC_DISC_DELAYED, &vport->fc_flag)) { rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_NOTHING_MORE; break; } if (vport->port_state < LPFC_DISC_AUTH) { - if (!(phba->pport->fc_flag & FC_PT2PT) || - (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { + if (!test_bit(FC_PT2PT, &phba->pport->fc_flag) || + test_bit(FC_PT2PT_PLOGI, &phba->pport->fc_flag)) { rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_NOTHING_MORE; break; @@ -10547,7 +10487,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * bounce the link. There is some descrepancy. */ if (vport->port_state >= LPFC_LOCAL_CFG_LINK && - vport->fc_flag & FC_PT2PT && + test_bit(FC_PT2PT, &vport->fc_flag) && vport->rcv_flogi_cnt >= 1) { rjt_err = LSRJT_LOGICAL_BSY; rjt_exp = LSEXP_NOTHING_MORE; @@ -10670,7 +10610,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvPRLI++; if ((vport->port_state < LPFC_DISC_AUTH) && - (vport->fc_flag & FC_FABRIC)) { + test_bit(FC_FABRIC, &vport->fc_flag)) { rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_NOTHING_MORE; break; @@ -10999,16 +10939,13 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) { struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); /* * If lpfc_delay_discovery parameter is set and the clean address * bit is cleared and fc fabric parameters chenged, delay FC NPort * discovery. */ - spin_lock_irq(shost->host_lock); - if (vport->fc_flag & FC_DISC_DELAYED) { - spin_unlock_irq(shost->host_lock); + if (test_bit(FC_DISC_DELAYED, &vport->fc_flag)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3334 Delay fc port discovery for %d secs\n", phba->fc_ratov); @@ -11016,7 +10953,6 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); return; } - spin_unlock_irq(shost->host_lock); ndlp = lpfc_findnode_did(vport, NameServer_DID); if (!ndlp) { @@ -11066,14 +11002,12 @@ static void lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = pmb->ctx_ndlp; MAILBOX_t *mb = &pmb->u.mb; int rc; - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); if (mb->mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -11090,16 +11024,13 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) case 0x9602: /* Link event since CLEAR_LA */ /* giving up on vport registration */ lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); lpfc_can_disctmo(vport); break; /* If reg_vpi fail with invalid VPI status, re-init VPI */ case 0x20: - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); lpfc_init_vpi(phba, pmb, vport->vpi); pmb->vport = vport; pmb->mbox_cmpl = lpfc_init_vpi_cmpl; @@ -11120,13 +11051,11 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev == LPFC_SLI_REV4) lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); if (mb->mbxStatus == MBX_NOT_FINISHED) break; if ((vport->port_type == LPFC_PHYSICAL_PORT) && - !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) { + !test_bit(FC_LOGO_RCVD_DID_CHNG, &vport->fc_flag)) { if (phba->sli_rev == LPFC_SLI_REV4) lpfc_issue_init_vfi(vport); else @@ -11187,7 +11116,6 @@ void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LPFC_MBOXQ_t *mbox; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -11222,9 +11150,7 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, mbox_err_exit: lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); return; } @@ -11339,7 +11265,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_nodelist *np; struct lpfc_nodelist *next_np; @@ -11387,13 +11312,11 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_check_nlp_post_devloss(vport, ndlp); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_CVL_RCVD; - vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; - vport->fc_flag |= FC_FABRIC; + clear_bit(FC_VPORT_CVL_RCVD, &vport->fc_flag); + clear_bit(FC_VPORT_LOGO_RCVD, &vport->fc_flag); + set_bit(FC_FABRIC, &vport->fc_flag); if (vport->phba->fc_topology == LPFC_TOPOLOGY_LOOP) - vport->fc_flag |= FC_PUBLIC_LOOP; - spin_unlock_irq(shost->host_lock); + set_bit(FC_PUBLIC_LOOP, &vport->fc_flag); vport->fc_myDID = ulp_word4 & Mask_DID; lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); @@ -11410,7 +11333,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, memcpy(&vport->fabric_nodename, &sp->nodeName, sizeof(struct lpfc_name)); if (fabric_param_changed && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + !test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) { /* If our NportID changed, we need to ensure all * remaining NPORTs get unreg_login'ed so we can * issue unreg_vpi. @@ -11431,15 +11354,13 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); if (phba->sli_rev == LPFC_SLI_REV4) - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + set_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); else - vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG; - spin_unlock_irq(shost->host_lock); + set_bit(FC_LOGO_RCVD_DID_CHNG, &vport->fc_flag); } else if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + !test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) { /* * Driver needs to re-reg VPI in order for f/w * to update the MAC address. @@ -11449,9 +11370,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } - if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) + if (test_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag)) lpfc_issue_init_vpi(vport); - else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + else if (test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) lpfc_register_new_vport(phba, vport, ndlp); else lpfc_do_scr_ns_plogi(phba, vport); @@ -11604,7 +11525,6 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; IOCB_t *irsp; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); u32 ulp_status, ulp_word4, did, tmo; ndlp = cmdiocb->ndlp; @@ -11635,10 +11555,8 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->fc4_xpt_flags); if (ulp_status == IOSTAT_SUCCESS) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - vport->fc_flag &= ~FC_FABRIC; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); + clear_bit(FC_FABRIC, &vport->fc_flag); lpfc_can_disctmo(vport); } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 08acd5d398aa..42695159f697 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1149,7 +1149,6 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; @@ -1180,9 +1179,7 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) if (phba->sli_rev == LPFC_SLI_REV4) lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); } } @@ -1210,7 +1207,7 @@ void lpfc_linkdown_port(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) fc_host_post_event(shost, fc_get_event_number(), @@ -1223,9 +1220,7 @@ lpfc_linkdown_port(struct lpfc_vport *vport) lpfc_port_link_failure(vport); /* Stop delayed Nport discovery */ - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_DISC_DELAYED, &vport->fc_flag); del_timer_sync(&vport->delayed_disc_tmo); if (phba->sli_rev == LPFC_SLI_REV4 && @@ -1240,7 +1235,7 @@ int lpfc_linkdown(struct lpfc_hba *phba) { struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_vport **vports; LPFC_MBOXQ_t *mb; int i; @@ -1273,9 +1268,7 @@ lpfc_linkdown(struct lpfc_hba *phba) phba->sli4_hba.link_state.logical_speed = LPFC_LINK_SPEED_UNKNOWN; } - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_LBIT; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_LBIT, &phba->pport->fc_flag); } vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { @@ -1313,7 +1306,7 @@ lpfc_linkdown(struct lpfc_hba *phba) skip_unreg_did: /* Setup myDID for link up if we are in pt2pt mode */ - if (phba->pport->fc_flag & FC_PT2PT) { + if (test_bit(FC_PT2PT, &phba->pport->fc_flag)) { mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_config_link(phba, mb); @@ -1324,8 +1317,9 @@ lpfc_linkdown(struct lpfc_hba *phba) mempool_free(mb, phba->mbox_mem_pool); } } + clear_bit(FC_PT2PT, &phba->pport->fc_flag); + clear_bit(FC_PT2PT_PLOGI, &phba->pport->fc_flag); spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); phba->pport->rcv_flogi_cnt = 0; spin_unlock_irq(shost->host_lock); } @@ -1376,19 +1370,22 @@ lpfc_linkup_port(struct lpfc_vport *vport) (vport != phba->pport)) return; - if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) - fc_host_post_event(shost, fc_get_event_number(), - FCH_EVT_LINKUP, 0); + if (phba->defer_flogi_acc_flag) { + clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag); + clear_bit(FC_RSCN_MODE, &vport->fc_flag); + clear_bit(FC_NLP_MORE, &vport->fc_flag); + clear_bit(FC_RSCN_DISCOVERY, &vport->fc_flag); + } else { + clear_bit(FC_PT2PT, &vport->fc_flag); + clear_bit(FC_PT2PT_PLOGI, &vport->fc_flag); + clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag); + clear_bit(FC_RSCN_MODE, &vport->fc_flag); + clear_bit(FC_NLP_MORE, &vport->fc_flag); + clear_bit(FC_RSCN_DISCOVERY, &vport->fc_flag); + } + set_bit(FC_NDISC_ACTIVE, &vport->fc_flag); spin_lock_irq(shost->host_lock); - if (phba->defer_flogi_acc_flag) - vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_RSCN_MODE | - FC_NLP_MORE | FC_RSCN_DISCOVERY); - else - vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | - FC_ABORT_DISCOVERY | FC_RSCN_MODE | - FC_NLP_MORE | FC_RSCN_DISCOVERY); - vport->fc_flag |= FC_NDISC_ACTIVE; vport->fc_ns_retry = 0; spin_unlock_irq(shost->host_lock); lpfc_setup_fdmi_mask(vport); @@ -1439,7 +1436,6 @@ static void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_sli *psli = &phba->sli; MAILBOX_t *mb = &pmb->u.mb; uint32_t control; @@ -1478,9 +1474,7 @@ out: "0225 Device Discovery completes\n"); mempool_free(pmb, phba->mbox_mem_pool); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_ABORT_DISCOVERY; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag); lpfc_can_disctmo(vport); @@ -1517,8 +1511,8 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && - vport->fc_flag & FC_PUBLIC_LOOP && - !(vport->fc_flag & FC_LBIT)) { + test_bit(FC_PUBLIC_LOOP, &vport->fc_flag) && + !test_bit(FC_LBIT, &vport->fc_flag)) { /* Need to wait for FAN - use discovery timer * for timeout. port_state is identically * LPFC_LOCAL_CFG_LINK while waiting for FAN @@ -1560,7 +1554,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_initial_flogi(vport); } } else { - if (vport->fc_flag & FC_PT2PT) + if (test_bit(FC_PT2PT, &vport->fc_flag)) lpfc_disc_start(vport); } return; @@ -1884,7 +1878,7 @@ lpfc_register_fcf(struct lpfc_hba *phba) phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); phba->hba_flag &= ~FCF_TS_INPROG; if (phba->pport->port_state != LPFC_FLOGI && - phba->pport->fc_flag & FC_FABRIC) { + test_bit(FC_FABRIC, &phba->pport->fc_flag)) { phba->hba_flag |= FCF_RR_INPROG; spin_unlock_irq(&phba->hbalock); lpfc_initial_flogi(phba->pport); @@ -2742,7 +2736,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2836 New FCF matches in-use " "FCF (x%x), port_state:x%x, " - "fc_flag:x%x\n", + "fc_flag:x%lx\n", phba->fcf.current_rec.fcf_indx, phba->pport->port_state, phba->pport->fc_flag); @@ -3218,7 +3212,6 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -3228,9 +3221,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); /* If this port is physical port or FDISC is done, do reg_vpi */ if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) { @@ -3328,7 +3319,8 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) FC_VPORT_LINKDOWN); continue; } - if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { + if (test_bit(FC_VPORT_NEEDS_INIT_VPI, + &vports[i]->fc_flag)) { lpfc_issue_init_vpi(vports[i]); continue; } @@ -3380,17 +3372,17 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) * Unless this was a VFI update and we are in PT2PT mode, then * we should drop through to set the port state to ready. */ - if (vport->fc_flag & FC_VFI_REGISTERED) + if (test_bit(FC_VFI_REGISTERED, &vport->fc_flag)) if (!(phba->sli_rev == LPFC_SLI_REV4 && - vport->fc_flag & FC_PT2PT)) + test_bit(FC_PT2PT, &vport->fc_flag))) goto out_free_mem; /* The VPI is implicitly registered when the VFI is registered */ + set_bit(FC_VFI_REGISTERED, &vport->fc_flag); + clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); + clear_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); spin_lock_irq(shost->host_lock); vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag |= FC_VFI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); /* In case SLI4 FC loopback test, we are ready */ @@ -3401,8 +3393,8 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "3313 cmpl reg vfi port_state:%x fc_flag:%x myDid:%x " - "alpacnt:%d LinkState:%x topology:%x\n", + "3313 cmpl reg vfi port_state:%x fc_flag:%lx " + "myDid:%x alpacnt:%d LinkState:%x topology:%x\n", vport->port_state, vport->fc_flag, vport->fc_myDID, vport->phba->alpa_map[0], phba->link_state, phba->fc_topology); @@ -3412,14 +3404,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) * For private loop or for NPort pt2pt, * just start discovery and we are done. */ - if ((vport->fc_flag & FC_PT2PT) || - ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - !(vport->fc_flag & FC_PUBLIC_LOOP))) { + if (test_bit(FC_PT2PT, &vport->fc_flag) || + (phba->fc_topology == LPFC_TOPOLOGY_LOOP && + !test_bit(FC_PUBLIC_LOOP, &vport->fc_flag))) { /* Use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); /* Start discovery */ - if (vport->fc_flag & FC_PT2PT) + if (test_bit(FC_PT2PT, &vport->fc_flag)) vport->port_state = LPFC_VPORT_READY; else lpfc_disc_start(vport); @@ -3496,11 +3488,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; - struct Scsi_Host *shost; int i; int rc; struct fcf_record *fcf_record; - uint32_t fc_flags = 0; unsigned long iflags; spin_lock_irqsave(&phba->hbalock, iflags); @@ -3537,7 +3527,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); phba->link_flag &= ~(LS_NPIV_FAB_SUPPORTED | LS_CT_VEN_RPA); - shost = lpfc_shost_from_vport(vport); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; @@ -3550,7 +3539,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) "topology\n"); /* Get Loop Map information */ if (bf_get(lpfc_mbx_read_top_il, la)) - fc_flags |= FC_LBIT; + set_bit(FC_LBIT, &vport->fc_flag); vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la); i = la->lilpBde64.tus.f.bdeSize; @@ -3599,16 +3588,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; } vport->fc_myDID = phba->fc_pref_DID; - fc_flags |= FC_LBIT; + set_bit(FC_LBIT, &vport->fc_flag); } spin_unlock_irqrestore(&phba->hbalock, iflags); - if (fc_flags) { - spin_lock_irqsave(shost->host_lock, iflags); - vport->fc_flag |= fc_flags; - spin_unlock_irqrestore(shost->host_lock, iflags); - } - lpfc_linkup(phba); sparam_mbox = NULL; @@ -3751,13 +3734,11 @@ void lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_mbx_read_top *la; struct lpfc_sli_ring *pring; MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); uint8_t attn_type; - unsigned long iflags; /* Unblock ELS traffic */ pring = lpfc_phba_elsring(phba); @@ -3779,12 +3760,10 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memcpy(&phba->alpa_map[0], mp->virt, 128); - spin_lock_irqsave(shost->host_lock, iflags); if (bf_get(lpfc_mbx_read_top_pb, la)) - vport->fc_flag |= FC_BYPASSED_MODE; + set_bit(FC_BYPASSED_MODE, &vport->fc_flag); else - vport->fc_flag &= ~FC_BYPASSED_MODE; - spin_unlock_irqrestore(shost->host_lock, iflags); + clear_bit(FC_BYPASSED_MODE, &vport->fc_flag); if (phba->fc_eventTag <= la->eventTag) { phba->fc_stat.LinkMultiEvent++; @@ -3832,20 +3811,20 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1308 Link Down Event in loop back mode " "x%x received " - "Data: x%x x%x x%x\n", + "Data: x%x x%x x%lx\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag); else if (attn_type == LPFC_ATT_UNEXP_WWPN) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1313 Link Down Unexpected FA WWPN Event x%x " - "received Data: x%x x%x x%x x%x\n", + "received Data: x%x x%x x%lx x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_fa, la)); else lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1305 Link Down Event x%x received " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%lx x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_fa, la)); @@ -3949,9 +3928,10 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_workq_post_event(phba, NULL, NULL, LPFC_EVT_RESET_HBA); } + + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); spin_lock_irq(shost->host_lock); vport->vpi_state &= ~LPFC_VPI_REGISTERED; - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); mempool_free(pmb, phba->mbox_mem_pool); lpfc_cleanup_vports_rrqs(vport, NULL); @@ -4002,9 +3982,8 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) "0912 cmpl_reg_vpi, mb status = 0x%x\n", mb->mbxStatus); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); vport->fc_myDID = 0; if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || @@ -4017,9 +3996,9 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto out; } + clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); spin_lock_irq(shost->host_lock); vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ @@ -4027,9 +4006,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); lpfc_can_disctmo(vport); } vport->port_state = LPFC_VPORT_READY; @@ -4193,7 +4170,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; MAILBOX_t *mb = &pmb->u.mb; struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - struct Scsi_Host *shost; pmb->ctx_ndlp = NULL; @@ -4232,14 +4208,8 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (vport->port_state == LPFC_FABRIC_CFG_LINK) { /* when physical port receive logo donot start * vport discovery */ - if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) + if (!test_and_clear_bit(FC_LOGO_RCVD_DID_CHNG, &vport->fc_flag)) lpfc_start_fdiscs(phba); - else { - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ; - spin_unlock_irq(shost->host_lock); - } lpfc_do_scr_ns_plogi(phba, vport); } @@ -4998,7 +4968,6 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) void lpfc_set_disctmo(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; uint32_t tmo; @@ -5020,9 +4989,7 @@ lpfc_set_disctmo(struct lpfc_vport *vport) } mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo)); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_DISC_TMO; - spin_unlock_irq(shost->host_lock); + set_bit(FC_DISC_TMO, &vport->fc_flag); /* Start Discovery Timer state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -5042,7 +5009,6 @@ lpfc_set_disctmo(struct lpfc_vport *vport) int lpfc_can_disctmo(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); unsigned long iflags; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -5050,11 +5016,9 @@ lpfc_can_disctmo(struct lpfc_vport *vport) vport->port_state, vport->fc_ns_retry, vport->fc_flag); /* Turn off discovery timer if its running */ - if (vport->fc_flag & FC_DISC_TMO || + if (test_bit(FC_DISC_TMO, &vport->fc_flag) || timer_pending(&vport->fc_disctmo)) { - spin_lock_irqsave(shost->host_lock, iflags); - vport->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irqrestore(shost->host_lock, iflags); + clear_bit(FC_DISC_TMO, &vport->fc_flag); del_timer_sync(&vport->fc_disctmo); spin_lock_irqsave(&vport->work_port_lock, iflags); vport->work_port_events &= ~WORKER_DISC_TMO; @@ -5064,7 +5028,7 @@ lpfc_can_disctmo(struct lpfc_vport *vport) /* Cancel Discovery Timer state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0248 Cancel Discovery Timer state x%x " - "Data: x%x x%x x%x\n", + "Data: x%lx x%x x%x\n", vport->port_state, vport->fc_flag, atomic_read(&vport->fc_plogi_cnt), atomic_read(&vport->fc_adisc_cnt)); @@ -5353,7 +5317,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) acc_plogi = 0; if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && - (!(vport->fc_flag & FC_OFFLINE_MODE))) + (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag))) ndlp->nlp_flag |= NLP_UNREG_INP; lpfc_printf_vlog(vport, KERN_INFO, @@ -5725,7 +5689,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (!ndlp) { if (vport->phba->nvmet_support) return NULL; - if ((vport->fc_flag & FC_RSCN_MODE) != 0 && + if (test_bit(FC_RSCN_MODE, &vport->fc_flag) && lpfc_rscn_payload_check(vport, did) == 0) return NULL; ndlp = lpfc_nlp_init(vport, did); @@ -5735,7 +5699,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6453 Setup New Node 2B_DISC x%x " - "Data:x%x x%x x%x\n", + "Data:x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); @@ -5749,8 +5713,8 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) * The goal is to allow the target to reset its state and clear * pending IO in preparation for the initiator to recover. */ - if ((vport->fc_flag & FC_RSCN_MODE) && - !(vport->fc_flag & FC_NDISC_ACTIVE)) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag) && + !test_bit(FC_NDISC_ACTIVE, &vport->fc_flag)) { if (lpfc_rscn_payload_check(vport, did)) { /* Since this node is marked for discovery, @@ -5760,7 +5724,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6455 Setup RSCN Node 2B_DISC x%x " - "Data:x%x x%x x%x\n", + "Data:x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); @@ -5784,7 +5748,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6456 Skip Setup RSCN Node x%x " - "Data:x%x x%x x%x\n", + "Data:x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); ndlp = NULL; @@ -5792,7 +5756,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6457 Setup Active Node 2B_DISC x%x " - "Data:x%x x%x x%x\n", + "Data:x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); @@ -5920,7 +5884,6 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) void lpfc_disc_start(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; uint32_t num_sent; uint32_t clear_la_pending; @@ -5948,7 +5911,7 @@ lpfc_disc_start(struct lpfc_vport *vport) /* Start Discovery state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0202 Start Discovery port state x%x " - "flg x%x Data: x%x x%x x%x\n", + "flg x%lx Data: x%x x%x x%x\n", vport->port_state, vport->fc_flag, atomic_read(&vport->fc_plogi_cnt), atomic_read(&vport->fc_adisc_cnt), @@ -5962,8 +5925,8 @@ lpfc_disc_start(struct lpfc_vport *vport) /* Register the VPI for SLI3, NPIV only. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_RSCN_MODE) && + !test_bit(FC_PT2PT, &vport->fc_flag) && + !test_bit(FC_RSCN_MODE, &vport->fc_flag) && (phba->sli_rev < LPFC_SLI_REV4)) { lpfc_issue_clear_la(phba, vport); lpfc_issue_reg_vpi(phba, vport); @@ -5978,16 +5941,14 @@ lpfc_disc_start(struct lpfc_vport *vport) /* If we get here, there is nothing to ADISC */ lpfc_issue_clear_la(phba, vport); - if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { + if (!test_bit(FC_ABORT_DISCOVERY, &vport->fc_flag)) { vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */ if (atomic_read(&vport->fc_npr_cnt)) lpfc_els_disc_plogi(vport); if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); lpfc_can_disctmo(vport); } } @@ -5999,18 +5960,17 @@ lpfc_disc_start(struct lpfc_vport *vport) if (num_sent) return; - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { /* Check to see if more RSCNs came in while we * were processing this one. */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); + if (vport->fc_rscn_id_cnt == 0 && + !test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) { + clear_bit(FC_RSCN_MODE, &vport->fc_flag); lpfc_can_disctmo(vport); - } else + } else { lpfc_els_handle_rscn(vport); + } } } return; @@ -6159,20 +6119,15 @@ lpfc_disc_timeout(struct timer_list *t) static void lpfc_disc_timeout_handler(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_sli *psli = &phba->sli; struct lpfc_nodelist *ndlp, *next_ndlp; LPFC_MBOXQ_t *initlinkmbox; int rc, clrlaerr = 0; - if (!(vport->fc_flag & FC_DISC_TMO)) + if (!test_and_clear_bit(FC_DISC_TMO, &vport->fc_flag)) return; - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irq(shost->host_lock); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "disc timeout: state:x%x rtry:x%x flg:x%x", vport->port_state, vport->fc_ns_retry, vport->fc_flag); @@ -6326,7 +6281,7 @@ restart_disc: break; case LPFC_VPORT_READY: - if (vport->fc_flag & FC_RSCN_MODE) { + if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0231 RSCN timeout Data: x%x " @@ -6758,7 +6713,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) * If dev_loss fires while we are waiting we do not want to * unreg the fcf. */ - if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) { + if (!test_bit(FC_VPORT_CVL_RCVD, &vports[i]->fc_flag)) { ret = 1; goto out; } @@ -6798,7 +6753,6 @@ void lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -6806,9 +6760,7 @@ lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) "HBA state x%x\n", mboxq->u.mb.mbxStatus, vport->port_state); } - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_VFI_REGISTERED, &phba->pport->fc_flag); mempool_free(mboxq, phba->mbox_mem_pool); return; } @@ -6872,9 +6824,9 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba) lpfc_mbx_unreg_vpi(vports[i]); shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); - vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_INIT_VPI, &vports[i]->fc_flag); } lpfc_destroy_vport_work_array(phba, vports); if (i == 0 && (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))) { @@ -6887,9 +6839,9 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba) lpfc_mbx_unreg_vpi(phba->pport); shost = lpfc_shost_from_vport(phba->pport); spin_lock_irq(shost->host_lock); - phba->pport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; phba->pport->vpi_state &= ~LPFC_VPI_REGISTERED; spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_INIT_VPI, &phba->pport->fc_flag); } /* Cleanup any outstanding ELS commands */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index c43118fab4aa..a71171669972 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1269,9 +1269,9 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) /* Check and reset heart-beat timer if necessary */ mempool_free(pmboxq, phba->mbox_mem_pool); - if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && - !(phba->link_state == LPFC_HBA_ERROR) && - !(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag) && + !(phba->link_state == LPFC_HBA_ERROR) && + !(phba->pport->load_flag & FC_UNLOADING)) mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); @@ -1302,7 +1302,7 @@ lpfc_idle_stat_delay_work(struct work_struct *work) return; if (phba->link_state == LPFC_HBA_ERROR || - phba->pport->fc_flag & FC_OFFLINE_MODE || + test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag) || phba->cmf_active_mode != LPFC_CFG_OFF) goto requeue; @@ -1363,7 +1363,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work) return; if (phba->link_state == LPFC_HBA_ERROR || - phba->pport->fc_flag & FC_OFFLINE_MODE) + test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) goto requeue; ena_delay = kcalloc(phba->sli4_hba.num_possible_cpu, sizeof(*ena_delay), @@ -1536,7 +1536,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) if ((phba->link_state == LPFC_HBA_ERROR) || (phba->pport->load_flag & FC_UNLOADING) || - (phba->pport->fc_flag & FC_OFFLINE_MODE)) + test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) return; if (phba->elsbuf_cnt && @@ -3698,7 +3698,7 @@ lpfc_online(struct lpfc_hba *phba) return 0; vport = phba->pport; - if (!(vport->fc_flag & FC_OFFLINE_MODE)) + if (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) return 0; lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -3738,20 +3738,18 @@ lpfc_online(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - struct Scsi_Host *shost; - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->fc_flag &= ~FC_OFFLINE_MODE; + clear_bit(FC_OFFLINE_MODE, &vports[i]->fc_flag); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + set_bit(FC_VPORT_NEEDS_REG_VPI, + &vports[i]->fc_flag); if (phba->sli_rev == LPFC_SLI_REV4) { - vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + set_bit(FC_VPORT_NEEDS_INIT_VPI, + &vports[i]->fc_flag); if ((vpis_cleared) && (vports[i]->port_type != LPFC_PHYSICAL_PORT)) vports[i]->vpi = 0; } - spin_unlock_irq(shost->host_lock); } } lpfc_destroy_vport_work_array(phba, vports); @@ -3806,7 +3804,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) int offline; bool hba_pci_err; - if (vport->fc_flag & FC_OFFLINE_MODE) + if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) return; lpfc_block_mgmt_io(phba, mbx_action); @@ -3825,9 +3823,9 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; - vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - vports[i]->fc_flag &= ~FC_VFI_REGISTERED; spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vports[i]->fc_flag); + clear_bit(FC_VFI_REGISTERED, &vports[i]->fc_flag); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, @@ -3910,7 +3908,7 @@ lpfc_offline(struct lpfc_hba *phba) struct lpfc_vport **vports; int i; - if (phba->pport->fc_flag & FC_OFFLINE_MODE) + if (test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) return; /* stop port and all timers associated with this hba */ @@ -3941,14 +3939,14 @@ lpfc_offline(struct lpfc_hba *phba) shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->work_port_events = 0; - vports[i]->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irq(shost->host_lock); + set_bit(FC_OFFLINE_MODE, &vports[i]->fc_flag); } lpfc_destroy_vport_work_array(phba, vports); /* If OFFLINE flag is clear (i.e. unloading), cpuhp removal is handled * in hba_unset */ - if (phba->pport->fc_flag & FC_OFFLINE_MODE) + if (test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) __lpfc_cpuhp_remove(phba); if (phba->cfg_xri_rebalancing) @@ -4767,7 +4765,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport = (struct lpfc_vport *) shost->hostdata; vport->phba = phba; vport->load_flag |= FC_LOADING; - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); vport->fc_rscn_flush = 0; atomic_set(&vport->fc_plogi_cnt, 0); atomic_set(&vport->fc_adisc_cnt, 0); @@ -6704,9 +6702,7 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) return NULL; lpfc_linkdown_port(vport); lpfc_cleanup_pending_mbox(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_CVL_RCVD; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_CVL_RCVD, &vport->fc_flag); return ndlp; } @@ -6903,9 +6899,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, if (vports) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if ((!(vports[i]->fc_flag & - FC_VPORT_CVL_RCVD)) && - (vports[i]->port_state > LPFC_FDISC)) { + if (!test_bit(FC_VPORT_CVL_RCVD, + &vports[i]->fc_flag) && + vports[i]->port_state > LPFC_FDISC) { active_vlink_present = 1; break; } @@ -12783,7 +12779,8 @@ static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) static void lpfc_cpuhp_remove(struct lpfc_hba *phba) { - if (phba->pport && (phba->pport->fc_flag & FC_OFFLINE_MODE)) + if (phba->pport && + test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) return; __lpfc_cpuhp_remove(phba); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index cadcd16494e1..162a0df8b60e 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -949,7 +949,7 @@ lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb) * Set the re-reg VPI bit for f/w to update the MAC address. */ if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) + !test_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag)) mb->un.varRegVpi.upd = 1; mb->un.varRegVpi.vpi = phba->vpi_ids[vport->vpi]; @@ -2244,7 +2244,7 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) /* Only FC supports upd bit */ if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) && - (vport->fc_flag & FC_VFI_REGISTERED) && + test_bit(FC_VFI_REGISTERED, &vport->fc_flag) && (!phba->fc_topology_changed)) bf_set(lpfc_reg_vfi_upd, reg_vfi, 1); @@ -2271,8 +2271,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) } lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX, "3134 Register VFI, mydid:x%x, fcfi:%d, " - " vfi:%d, vpi:%d, fc_pname:%x%x fc_flag:x%x" - " port_state:x%x topology chg:%d bbscn_fabric :%d\n", + "vfi:%d, vpi:%d, fc_pname:%x%x fc_flag:x%lx " + "port_state:x%x topology chg:%d bbscn_fabric :%d\n", vport->fc_myDID, phba->fcf.fcfi, phba->sli4_hba.vfi_ids[vport->vfi], diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 0bc93f346d90..ab9b3585492c 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -382,7 +382,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0114 PLOGI chkparm OK Data: x%x x%x x%x " - "x%x x%x x%x\n", + "x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi, vport->port_state, vport->fc_flag); @@ -464,8 +464,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, save_iocb = NULL; /* Check for Nport to NPort pt2pt protocol */ - if ((vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_PT2PT_PLOGI)) { + if (test_bit(FC_PT2PT, &vport->fc_flag) && + !test_bit(FC_PT2PT_PLOGI, &vport->fc_flag)) { /* rcv'ed PLOGI decides what our NPortId will be */ if (phba->sli_rev == LPFC_SLI_REV4) { vport->fc_myDID = bf_get(els_rsp64_sid, @@ -580,7 +580,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * This only applies to a fabric environment. */ if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) && - (vport->fc_flag & FC_FABRIC)) { + test_bit(FC_FABRIC, &vport->fc_flag)) { /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp); } @@ -804,7 +804,6 @@ static int lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb, uint32_t els_cmd) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_vport **vports; int i, active_vlink_present = 0 ; @@ -837,19 +836,17 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (ndlp->nlp_DID == Fabric_DID) { if (vport->port_state <= LPFC_FDISC || - vport->fc_flag & FC_PT2PT) + test_bit(FC_PT2PT, &vport->fc_flag)) goto out; lpfc_linkdown_port(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_LOGO_RCVD; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_LOGO_RCVD, &vport->fc_flag); vports = lpfc_create_vport_work_array(phba); if (vports) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if ((!(vports[i]->fc_flag & - FC_VPORT_LOGO_RCVD)) && - (vports[i]->port_state > LPFC_FDISC)) { + if (!test_bit(FC_VPORT_LOGO_RCVD, + &vports[i]->fc_flag) && + vports[i]->port_state > LPFC_FDISC) { active_vlink_present = 1; break; } @@ -876,23 +873,21 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_LOGO_RCVD_DID_CHNG, &phba->pport->fc_flag); lpfc_retry_pport_discovery(phba); } } 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", + "ntype x%x fc_flag x%lx\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)) || + test_bit(FC_PT2PT, &vport->fc_flag))) || (ndlp->nlp_state >= NLP_STE_ADISC_ISSUE || ndlp->nlp_state <= NLP_STE_PRLI_ISSUE)) { mod_timer(&ndlp->nlp_delayfunc, @@ -1057,9 +1052,10 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 0; } - if (!(vport->fc_flag & FC_PT2PT)) { + if (!test_bit(FC_PT2PT, &vport->fc_flag)) { /* Check config parameter use-adisc or FCP-2 */ - if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || + if (vport->cfg_use_adisc && + (test_bit(FC_RSCN_MODE, &vport->fc_flag) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && (ndlp->nlp_type & NLP_FCP_TARGET)))) { spin_lock_irq(&ndlp->lock); @@ -1123,7 +1119,7 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, } if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && - (!(vport->fc_flag & FC_OFFLINE_MODE))) + (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag))) ndlp->nlp_flag |= NLP_UNREG_INP; lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -1246,7 +1242,6 @@ static uint32_t lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb = arg; struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf; @@ -1281,9 +1276,7 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Check if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag); lpfc_can_disctmo(vport); lpfc_end_rscn(vport); } @@ -1423,8 +1416,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; - if ((vport->fc_flag & FC_PT2PT) && - (vport->fc_flag & FC_PT2PT_PLOGI)) { + if (test_bit(FC_PT2PT, &vport->fc_flag) && + test_bit(FC_PT2PT_PLOGI, &vport->fc_flag)) { ed_tov = be32_to_cpu(sp->cmn.e_d_tov); if (sp->cmn.edtovResolution) { /* E_D_TOV ticks are in nanoseconds */ @@ -1615,7 +1608,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, /* Don't do anything that will mess up processing of the * previous RSCN. */ - if (vport->fc_flag & FC_RSCN_DEFERRED) + if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) return ndlp->nlp_state; /* software abort outstanding PLOGI */ @@ -1801,7 +1794,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, /* Don't do anything that will mess up processing of the * previous RSCN. */ - if (vport->fc_flag & FC_RSCN_DEFERRED) + if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) return ndlp->nlp_state; /* software abort outstanding ADISC */ @@ -1991,13 +1984,13 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, * know what PRLI to send yet. Figure that out now and * call PRLI depending on the outcome. */ - if (vport->fc_flag & FC_PT2PT) { + if (test_bit(FC_PT2PT, &vport->fc_flag)) { /* If we are pt2pt, there is no Fabric to determine * the FC4 type of the remote nport. So if NVME * is configured try it. */ ndlp->nlp_fc4_type |= NLP_FC4_FCP; - if ((!(vport->fc_flag & FC_PT2PT_NO_NVME)) && + if ((!test_bit(FC_PT2PT_NO_NVME, &vport->fc_flag)) && (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH || vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { ndlp->nlp_fc4_type |= NLP_FC4_NVME; @@ -2029,7 +2022,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); } } else { - if ((vport->fc_flag & FC_PT2PT) && phba->nvmet_support) + if (test_bit(FC_PT2PT, &vport->fc_flag) && phba->nvmet_support) phba->targetport->port_id = vport->fc_myDID; /* Only Fabric ports should transition. NVME target @@ -2070,7 +2063,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, /* Don't do anything that will mess up processing of the * previous RSCN. */ - if (vport->fc_flag & FC_RSCN_DEFERRED) + if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) return ndlp->nlp_state; ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; @@ -2386,7 +2379,7 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, /* Don't do anything that will mess up processing of the * previous RSCN. */ - if (vport->fc_flag & FC_RSCN_DEFERRED) + if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) return ndlp->nlp_state; /* software abort outstanding PRLI */ @@ -2830,13 +2823,10 @@ static uint32_t lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - /* For the fabric port just clear the fc flags. */ if (ndlp->nlp_DID == Fabric_DID) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); + clear_bit(FC_FABRIC, &vport->fc_flag); + clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); } lpfc_unreg_rpi(vport, ndlp); return ndlp->nlp_state; @@ -2908,7 +2898,7 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Don't do anything that will mess up processing of the * previous RSCN. */ - if (vport->fc_flag & FC_RSCN_DEFERRED) + if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag)) return ndlp->nlp_state; lpfc_cancel_retry_delay_tmo(vport, ndlp); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 29fd2eda70d5..4b21c4d33533 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2909,8 +2909,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); + clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); } if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) { @@ -10888,7 +10888,7 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq, * all ELS pt2pt protocol traffic as well. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) || - (vport->fc_flag & FC_PT2PT)) { + test_bit(FC_PT2PT, &vport->fc_flag)) { if (expect_rsp) { bf_set(els_req64_sid, &wqe->els_req, vport->fc_myDID); @@ -18552,8 +18552,8 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, if (did == Fabric_DID) return phba->pport; - if ((phba->pport->fc_flag & FC_PT2PT) && - !(phba->link_state == LPFC_HBA_READY)) + if (test_bit(FC_PT2PT, &phba->pport->fc_flag) && + phba->link_state != LPFC_HBA_READY) return phba->pport; vports = lpfc_create_vport_work_array(phba); @@ -19507,8 +19507,8 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, * The pt2pt protocol allows for discovery frames * to be received without a registered VPI. */ - if (!(vport->fc_flag & FC_PT2PT) || - (phba->link_state == LPFC_HBA_READY)) { + if (!test_bit(FC_PT2PT, &vport->fc_flag) || + phba->link_state == LPFC_HBA_READY) { lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } @@ -22666,7 +22666,7 @@ lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job) if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { - if (job->vport->fc_flag & FC_PT2PT) { + if (test_bit(FC_PT2PT, &job->vport->fc_flag)) { bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, job->vport->fc_myDID); diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 6c7559cf1a4b..e2e0518e8387 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -238,13 +238,9 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) static void lpfc_discovery_wait(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; - uint32_t wait_flags = 0; unsigned long wait_time_max; unsigned long start_time; - wait_flags = FC_RSCN_MODE | FC_RSCN_DISCOVERY | FC_NLP_MORE | - FC_RSCN_DEFERRED | FC_NDISC_ACTIVE | FC_DISC_TMO; - /* * The time constraint on this loop is a balance between the * fabric RA_TOV value and dev_loss tmo. The driver's @@ -255,14 +251,19 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) start_time = jiffies; while (time_before(jiffies, wait_time_max)) { if ((vport->num_disc_nodes > 0) || - (vport->fc_flag & wait_flags) || + test_bit(FC_RSCN_MODE, &vport->fc_flag) || + test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag) || + test_bit(FC_NLP_MORE, &vport->fc_flag) || + test_bit(FC_RSCN_DEFERRED, &vport->fc_flag) || + test_bit(FC_NDISC_ACTIVE, &vport->fc_flag) || + test_bit(FC_DISC_TMO, &vport->fc_flag) || ((vport->port_state > LPFC_VPORT_FAILED) && (vport->port_state < LPFC_VPORT_READY))) { lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, - "1833 Vport discovery quiesce Wait:" - " state x%x fc_flags x%x" - " num_nodes x%x, waiting 1000 msecs" - " total wait msecs x%x\n", + "1833 Vport discovery quiesce Wait: " + "state x%x fc_flags x%lx " + "num_nodes x%x, waiting 1000 msecs " + "total wait msecs x%x\n", vport->port_state, vport->fc_flag, vport->num_disc_nodes, jiffies_to_msecs(jiffies - start_time)); @@ -270,9 +271,9 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) } else { /* Base case. Wait variants satisfied. Break out */ lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, - "1834 Vport discovery quiesced:" - " state x%x fc_flags x%x" - " wait msecs x%x\n", + "1834 Vport discovery quiesced: " + "state x%x fc_flags x%lx " + "wait msecs x%x\n", vport->port_state, vport->fc_flag, jiffies_to_msecs(jiffies - start_time)); @@ -283,7 +284,7 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) if (time_after(jiffies, wait_time_max)) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1835 Vport discovery quiesce failed:" - " state x%x fc_flags x%x wait msecs x%x\n", + " state x%x fc_flags x%lx wait msecs x%x\n", vport->port_state, vport->fc_flag, jiffies_to_msecs(jiffies - start_time)); } @@ -420,7 +421,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * by the port. */ if ((phba->sli_rev == LPFC_SLI_REV4) && - (pport->fc_flag & FC_VFI_REGISTERED)) { + test_bit(FC_VFI_REGISTERED, &pport->fc_flag)) { rc = lpfc_sli4_init_vpi(vport); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -435,7 +436,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * Driver cannot INIT_VPI now. Set the flags to * init_vpi when reg_vfi complete. */ - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + set_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); rc = VPORT_OK; goto out; @@ -535,7 +536,6 @@ disable_vport(struct fc_vport *fc_vport) struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); /* Can't disable during an outstanding delete. */ if (vport->load_flag & FC_UNLOADING) @@ -556,11 +556,8 @@ disable_vport(struct fc_vport *fc_vport) * scsi_host_put() to release the vport. */ lpfc_mbx_unreg_vpi(vport); - if (phba->sli_rev == LPFC_SLI_REV4) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - } + if (phba->sli_rev == LPFC_SLI_REV4) + set_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag); lpfc_vport_set_state(vport, FC_VPORT_DISABLED); lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, @@ -584,14 +581,13 @@ enable_vport(struct fc_vport *fc_vport) spin_lock_irq(shost->host_lock); vport->load_flag |= FC_LOADING; - if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(shost->host_lock); + if (test_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag)) { lpfc_issue_init_vpi(vport); goto out; } - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); + set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); /* Use the Physical nodes Fabric NDLP to determine if the link is * up and ready to FDISC. From e39811bec6b17dd36794381d839abffab61abfcf Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:10 -0800 Subject: [PATCH 204/814] scsi: lpfc: Change lpfc_vport load_flag member into a bitmask In attempt to reduce the amount of unnecessary shost_lock acquisitions in the lpfc driver, change load_flag into an unsigned long bitmask and use clear_bit/test_bit bitwise atomic APIs instead of reliance on shost_lock for synchronization. Also, correct the test for FC_UNLOADING in lpfc_ct_handle_mibreq, which incorrectly tests vport->fc_flag rather than vport->load_flag. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-16-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 15 ++++--- drivers/scsi/lpfc/lpfc_ct.c | 11 ++--- drivers/scsi/lpfc/lpfc_els.c | 22 +++++----- drivers/scsi/lpfc/lpfc_hbadisc.c | 26 ++++++------ drivers/scsi/lpfc/lpfc_init.c | 64 +++++++++++++----------------- drivers/scsi/lpfc/lpfc_nportdisc.c | 13 +++--- drivers/scsi/lpfc/lpfc_nvme.c | 18 ++++----- drivers/scsi/lpfc/lpfc_nvmet.c | 12 +++--- drivers/scsi/lpfc/lpfc_sli.c | 24 +++++------ drivers/scsi/lpfc/lpfc_vport.c | 23 +++++------ 10 files changed, 108 insertions(+), 120 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 18c0adceaa6f..b863f87ff9e7 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -565,6 +565,14 @@ enum lpfc_fc_flag { FC_DISC_DELAYED, /* Delay NPort discovery */ }; +enum lpfc_load_flag { + FC_LOADING, /* HBA in process of loading drvr */ + FC_UNLOADING, /* HBA in process of unloading drvr */ + FC_ALLOW_FDMI, /* port is ready for FDMI requests */ + FC_ALLOW_VMID, /* Allow VMID I/Os */ + FC_DEREGISTER_ALL_APP_ID /* Deregister all VMIDs */ +}; + struct lpfc_vport { struct lpfc_hba *phba; struct list_head listentry; @@ -647,12 +655,7 @@ struct lpfc_vport { struct timer_list els_tmofunc; struct timer_list delayed_disc_tmo; - uint8_t load_flag; -#define FC_LOADING 0x1 /* HBA in process of loading drvr */ -#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ -#define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */ -#define FC_ALLOW_VMID 0x8 /* Allow VMID I/Os */ -#define FC_DEREGISTER_ALL_APP_ID 0x10 /* Deregister all VMIDs */ + unsigned long load_flag; /* Vport Config Parameters */ uint32_t cfg_scan_down; uint32_t cfg_lun_queue_depth; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 20520c7f58f6..2a0c6a4df090 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -298,7 +298,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) } /* Ignore traffic received during vport shutdown */ - if (test_bit(FC_UNLOADING, &vport->fc_flag)) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return; ndlp = lpfc_findnode_did(vport, did); @@ -943,7 +943,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* Skip processing response on pport if unloading */ - if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { + if (vport == phba->pport && test_bit(FC_UNLOADING, &vport->load_flag)) { if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); goto out; @@ -1159,7 +1159,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* Skip processing response on pport if unloading */ - if (vport == phba->pport && vport->load_flag & FC_UNLOADING) { + if (vport == phba->pport && test_bit(FC_UNLOADING, &vport->load_flag)) { if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) lpfc_els_flush_rscn(vport); goto out; @@ -3583,7 +3583,8 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (ctrsp->Explanation != SLI_CT_APP_ID_NOT_AVAILABLE)) { /* If DALLAPP_ID failed retry later */ if (cmd == SLI_CTAS_DALLAPP_ID) - vport->load_flag |= FC_DEREGISTER_ALL_APP_ID; + set_bit(FC_DEREGISTER_ALL_APP_ID, + &vport->load_flag); goto free_res; } } @@ -3639,7 +3640,7 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (!hash_empty(vport->hash_table)) hash_for_each(vport->hash_table, bucket, cur, hnode) hash_del(&cur->hnode); - vport->load_flag |= FC_ALLOW_VMID; + set_bit(FC_ALLOW_VMID, &vport->load_flag); break; default: lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4c2666494e49..143f32b63249 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4964,7 +4964,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 0; } - if ((vport->load_flag & FC_UNLOADING) != 0) + if (test_bit(FC_UNLOADING, &vport->load_flag)) retry = 0; out_retry: @@ -8232,7 +8232,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; /* Ignore RSCN if the port is being torn down. */ - if (vport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { lpfc_els_flush_rscn(vport); return 0; } @@ -9449,11 +9449,11 @@ lpfc_els_timeout(struct timer_list *t) spin_lock_irqsave(&vport->work_port_lock, iflag); tmo_posted = vport->work_port_events & WORKER_ELS_TMO; - if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING))) + if (!tmo_posted && !test_bit(FC_UNLOADING, &vport->load_flag)) vport->work_port_events |= WORKER_ELS_TMO; spin_unlock_irqrestore(&vport->work_port_lock, iflag); - if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING))) + if (!tmo_posted && !test_bit(FC_UNLOADING, &vport->load_flag)) lpfc_worker_wake_up(phba); return; } @@ -9489,7 +9489,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) if (unlikely(!pring)) return; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; spin_lock_irq(&phba->hbalock); @@ -9565,7 +9565,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) lpfc_issue_hb_tmo(phba); if (!list_empty(&pring->txcmplq)) - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) mod_timer(&vport->els_tmofunc, jiffies + msecs_to_jiffies(1000 * timeout)); } @@ -10364,7 +10364,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; /* Ignore traffic received during vport shutdown. */ - if (vport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->load_flag)) goto dropit; /* If NPort discovery is delayed drop incoming ELS */ @@ -10785,7 +10785,7 @@ lsrjt: return; dropit: - if (vport && !(vport->load_flag & FC_UNLOADING)) + if (vport && !test_bit(FC_UNLOADING, &vport->load_flag)) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0111 Dropping received ELS cmd " "Data: x%x x%x x%x x%x\n", @@ -10981,8 +10981,8 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) } if ((phba->cfg_enable_SmartSAN || - (phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT)) && - (vport->load_flag & FC_ALLOW_FDMI)) + phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT) && + test_bit(FC_ALLOW_FDMI, &vport->load_flag)) lpfc_start_fdmi(vport); } @@ -12014,7 +12014,7 @@ lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) * node and the vport is unloading, the xri aborted wcqe * likely isn't coming back. Just release the sgl. */ - if ((vport->load_flag & FC_UNLOADING) && + if (test_bit(FC_UNLOADING, &vport->load_flag) && ndlp->nlp_DID == Fabric_DID) { list_del(&sglq_entry->list); sglq_entry->state = SGL_FREED; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 42695159f697..f97817ac463d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -169,13 +169,13 @@ 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 %u state %d xpt x%x\n", + "load_flag x%lx 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. */ - if (vport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; @@ -263,7 +263,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) } else { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "3188 worker thread is stopped %s x%06x, " - " rport x%px flg x%x load_flag x%x refcnt " + " rport x%px flg x%x load_flag x%lx refcnt " "%d\n", __func__, ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, vport->load_flag, kref_read(&ndlp->kref)); @@ -911,7 +911,7 @@ lpfc_work_list_done(struct lpfc_hba *phba) free_evt = 0; break; case LPFC_EVT_RESET_HBA: - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_reset_hba(phba); break; } @@ -1358,7 +1358,7 @@ lpfc_linkup_port(struct lpfc_vport *vport) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - if ((vport->load_flag & FC_UNLOADING) != 0) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -3924,7 +3924,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", vport->vpi, mb->mbxStatus); - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_workq_post_event(phba, NULL, NULL, LPFC_EVT_RESET_HBA); } @@ -3939,7 +3939,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * This shost reference might have been taken at the beginning of * lpfc_vport_delete() */ - if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport)) + if (test_bit(FC_UNLOADING, &vport->load_flag) && vport != phba->pport) scsi_host_put(shost); } @@ -4490,7 +4490,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); /* Don't add the remote port if unloading. */ - if (vport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return; ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); @@ -5235,13 +5235,13 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, mbox->mbox_cmpl = lpfc_nlp_logo_unreg; } else if (phba->sli_rev == LPFC_SLI_REV4 && - (!(vport->load_flag & FC_UNLOADING)) && + !test_bit(FC_UNLOADING, &vport->load_flag) && (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) && (kref_read(&ndlp->kref) > 0)) { mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; } else { - if (vport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { if (phba->sli_rev == LPFC_SLI_REV4) { spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag |= NLP_RELEASE_RPI; @@ -5349,7 +5349,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * will issue a LOGO here and keep the rpi alive if * not unloading. */ - if (!(vport->load_flag & FC_UNLOADING)) { + if (!test_bit(FC_UNLOADING, &vport->load_flag)) { ndlp->nlp_flag &= ~NLP_UNREG_INP; lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = ndlp->nlp_state; @@ -6925,8 +6925,8 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) * If driver is not unloading, check if there is any other * FCF record that can be used for discovery. */ - if ((phba->pport->load_flag & FC_UNLOADING) || - (phba->link_state < LPFC_LINK_UP)) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag) || + phba->link_state < LPFC_LINK_UP) return; /* This is considered as the initial FCF discovery scan */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a71171669972..345a7d5784d8 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -892,7 +892,7 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) readl(phba->HCregaddr); /* flush */ } - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_cleanup_discovery_resources(phba->pport); else { vports = lpfc_create_vport_work_array(phba); @@ -1232,13 +1232,13 @@ lpfc_rrq_timeout(struct timer_list *t) phba = from_timer(phba, t, rrq_tmr); spin_lock_irqsave(&phba->pport->work_port_lock, iflag); - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) phba->hba_flag |= HBA_RRQ_ACTIVE; else phba->hba_flag &= ~HBA_RRQ_ACTIVE; spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_worker_wake_up(phba); } @@ -1271,7 +1271,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) mempool_free(pmboxq, phba->mbox_mem_pool); if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag) && !(phba->link_state == LPFC_HBA_ERROR) && - !(phba->pport->load_flag & FC_UNLOADING)) + !test_bit(FC_UNLOADING, &phba->pport->load_flag)) mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); @@ -1298,7 +1298,7 @@ lpfc_idle_stat_delay_work(struct work_struct *work) u32 i, idle_percent; u64 wall, wall_idle, diff_wall, diff_idle, busy_time; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; if (phba->link_state == LPFC_HBA_ERROR || @@ -1359,7 +1359,8 @@ lpfc_hb_eq_delay_work(struct work_struct *work) uint32_t usdelay; int i; - if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING) + if (!phba->cfg_auto_imax || + test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; if (phba->link_state == LPFC_HBA_ERROR || @@ -1534,9 +1535,9 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } lpfc_destroy_vport_work_array(phba, vports); - if ((phba->link_state == LPFC_HBA_ERROR) || - (phba->pport->load_flag & FC_UNLOADING) || - test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) + if (phba->link_state == LPFC_HBA_ERROR || + test_bit(FC_UNLOADING, &phba->pport->load_flag) || + test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) return; if (phba->elsbuf_cnt && @@ -1737,7 +1738,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) break; } /* If driver is unloading let the worker thread continue */ - if (phba->pport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { phba->work_hs = 0; break; } @@ -1748,7 +1749,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) * first write to the host attention register clear the * host status register. */ - if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING))) + if (!phba->work_hs && !test_bit(FC_UNLOADING, &phba->pport->load_flag)) phba->work_hs = old_host_status & ~HS_FFER1; spin_lock_irq(&phba->hbalock); @@ -3086,7 +3087,7 @@ lpfc_cleanup(struct lpfc_vport *vport) * The flush here is only when the pci slot * is offline. */ - if (vport->load_flag & FC_UNLOADING && + if (test_bit(FC_UNLOADING, &vport->load_flag) && pci_channel_offline(phba->pcidev)) lpfc_sli_flush_io_rings(vport->phba); @@ -3412,7 +3413,7 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) return; for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if (vports[i]->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vports[i]->load_flag)) continue; list_for_each_entry_safe(ndlp, next_ndlp, @@ -3612,7 +3613,7 @@ static void lpfc_destroy_multixri_pools(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) lpfc_destroy_expedite_pool(phba); - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_sli_flush_io_rings(phba); hwq_count = phba->cfg_hdw_queue; @@ -3818,7 +3819,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if (vports[i]->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vports[i]->load_flag)) continue; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); @@ -4764,7 +4765,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport = (struct lpfc_vport *) shost->hostdata; vport->phba = phba; - vport->load_flag |= FC_LOADING; + set_bit(FC_LOADING, &vport->load_flag); set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag); vport->fc_rscn_flush = 0; atomic_set(&vport->fc_plogi_cnt, 0); @@ -4928,7 +4929,7 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) spin_lock_irq(shost->host_lock); - if (vport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { stat = 1; goto finished; } @@ -5042,9 +5043,7 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) fc_host_active_fc4s(shost)[7] = 1; fc_host_max_npiv_vports(shost) = phba->max_vpi; - spin_lock_irq(shost->host_lock); - vport->load_flag &= ~FC_LOADING; - spin_unlock_irq(shost->host_lock); + clear_bit(FC_LOADING, &vport->load_flag); } /** @@ -5180,7 +5179,7 @@ lpfc_vmid_poll(struct timer_list *t) /* Is the vmid inactivity timer enabled */ if (phba->pport->vmid_inactivity_timeout || - phba->pport->load_flag & FC_DEREGISTER_ALL_APP_ID) { + test_bit(FC_DEREGISTER_ALL_APP_ID, &phba->pport->load_flag)) { wake_up = 1; phba->pport->work_port_events |= WORKER_CHECK_INACTIVE_VMID; } @@ -6914,8 +6913,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, * If we are here first then vport_delete is going to wait * for discovery to complete. */ - if (!(vport->load_flag & FC_UNLOADING) && - active_vlink_present) { + if (!test_bit(FC_UNLOADING, &vport->load_flag) && + active_vlink_present) { /* * If there are other active VLinks present, * re-instantiate the Vlink using FDISC. @@ -9093,7 +9092,7 @@ lpfc_setup_fdmi_mask(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; - vport->load_flag |= FC_ALLOW_FDMI; + set_bit(FC_ALLOW_FDMI, &vport->load_flag); if (phba->cfg_enable_SmartSAN || phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT) { /* Setup appropriate attribute masks */ @@ -12805,7 +12804,7 @@ static void lpfc_cpuhp_add(struct lpfc_hba *phba) static int __lpfc_cpuhp_checks(struct lpfc_hba *phba, int *retval) { - if (phba->pport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { *retval = -EAGAIN; return true; } @@ -13325,12 +13324,7 @@ lpfc_sli4_disable_intr(struct lpfc_hba *phba) static void lpfc_unset_hba(struct lpfc_hba *phba) { - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(shost->host_lock); + set_bit(FC_UNLOADING, &phba->pport->load_flag); kfree(phba->vpi_bmask); kfree(phba->vpi_ids); @@ -14122,9 +14116,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) struct lpfc_hba *phba = vport->phba; int i; - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); + set_bit(FC_UNLOADING, &vport->load_flag); lpfc_free_sysfs_attr(vport); @@ -14967,9 +14959,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) int i; /* Mark the device unloading flag */ - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); + set_bit(FC_UNLOADING, &vport->load_flag); if (phba->cgn_i) lpfc_unreg_congestion_buf(phba); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index ab9b3585492c..24f171045abe 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -859,8 +859,8 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * If we are here first then vport_delete is going to wait * for discovery to complete. */ - if (!(vport->load_flag & FC_UNLOADING) && - active_vlink_present) { + if (!test_bit(FC_UNLOADING, &vport->load_flag) && + active_vlink_present) { /* * If there are other active VLinks present, * re-instantiate the Vlink using FDISC. @@ -1145,9 +1145,8 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba = vport->phba; /* Release the RPI if reglogin completing */ - if (!(phba->pport->load_flag & FC_UNLOADING) && - (evt == NLP_EVT_CMPL_REG_LOGIN) && - (!pmb->u.mb.mbxStatus)) { + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag) && + evt == NLP_EVT_CMPL_REG_LOGIN && !pmb->u.mb.mbxStatus) { rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, ndlp, rpi); } @@ -1571,8 +1570,8 @@ lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, phba = vport->phba; /* Release the RPI */ - if (!(phba->pport->load_flag & FC_UNLOADING) && - !mb->mbxStatus) { + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag) && + !mb->mbxStatus) { rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, ndlp, rpi); } diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 128fc1bab586..c3daf158bc2a 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -94,7 +94,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, lport = (struct lpfc_nvme_lport *)pnvme_lport->private; vport = lport->vport; - if (!vport || vport->load_flag & FC_UNLOADING || + if (!vport || test_bit(FC_UNLOADING, &vport->load_flag) || vport->phba->hba_flag & HBA_IOQ_FLUSH) return -ENODEV; @@ -674,7 +674,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, return -EINVAL; vport = lport->vport; - if (vport->load_flag & FC_UNLOADING || + if (test_bit(FC_UNLOADING, &vport->load_flag) || vport->phba->hba_flag & HBA_IOQ_FLUSH) return -ENODEV; @@ -765,7 +765,7 @@ lpfc_nvme_xmt_ls_rsp(struct nvme_fc_local_port *localport, struct lpfc_nvme_lport *lport; int rc; - if (axchg->phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &axchg->phba->pport->load_flag)) return -ENODEV; lport = (struct lpfc_nvme_lport *)localport->private; @@ -810,7 +810,7 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, return; vport = lport->vport; - if (vport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return; ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); @@ -1567,7 +1567,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, phba = vport->phba; - if ((unlikely(vport->load_flag & FC_UNLOADING)) || + if ((unlikely(test_bit(FC_UNLOADING, &vport->load_flag))) || phba->hba_flag & HBA_IOQ_FLUSH) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6124 Fail IO, Driver unload\n"); @@ -1886,7 +1886,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, if (unlikely(!freqpriv)) return; - if (vport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return; /* Announce entry to new IO submit field. */ @@ -2263,7 +2263,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, if (!vport->localport || test_bit(HBA_PCI_ERR, &vport->phba->bit_flags) || phba->link_state == LPFC_HBA_ERROR || - vport->load_flag & FC_UNLOADING) + test_bit(FC_UNLOADING, &vport->load_flag)) return; lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -2625,7 +2625,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * return values is ignored. The upcall is a courtesy to the * transport. */ - if (vport->load_flag & FC_UNLOADING || + if (test_bit(FC_UNLOADING, &vport->load_flag) || unlikely(vport->phba->link_state == LPFC_HBA_ERROR)) (void)nvme_fc_set_remoteport_devloss(remoteport, 0); @@ -2644,7 +2644,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "port_state x%x\n", ret, remoteport->port_state); - if (vport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { /* Only 1 thread can drop the initial node * reference. Check if another thread has set * NLP_DROPPED. diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 425328d9c2d8..255189eda388 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -872,7 +872,7 @@ __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg, struct ulp_bde64 bpl; int rc; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return -ENODEV; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, @@ -984,7 +984,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, struct lpfc_nvmet_tgtport *nvmep = tgtport->private; int rc; - if (axchg->phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &axchg->phba->pport->load_flag)) return -ENODEV; rc = __lpfc_nvme_xmt_ls_rsp(axchg, ls_rsp, lpfc_nvmet_xmt_ls_rsp_cmp); @@ -1022,7 +1022,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, int id; #endif - if (phba->pport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { rc = -ENODEV; goto aerr; } @@ -1145,7 +1145,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, struct lpfc_queue *wq; unsigned long flags; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; if (!ctxp->hdwq) @@ -1317,7 +1317,7 @@ lpfc_nvmet_ls_req(struct nvmet_fc_target_port *targetport, return -EINVAL; phba = lpfc_nvmet->phba; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return -EINVAL; hstate = atomic_read(&lpfc_nvmet->state); @@ -1353,7 +1353,7 @@ lpfc_nvmet_ls_abort(struct nvmet_fc_target_port *targetport, int ret; phba = lpfc_nvmet->phba; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; ndlp = (struct lpfc_nodelist *)hosthandle; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4b21c4d33533..1aad39015ee0 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1036,7 +1036,7 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) } spin_unlock_irqrestore(&phba->hbalock, iflags); if ((!list_empty(&phba->active_rrq_list)) && - (!(phba->pport->load_flag & FC_UNLOADING))) + (!test_bit(FC_UNLOADING, &phba->pport->load_flag))) mod_timer(&phba->rrq_tmr, next_time); list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) { list_del(&rrq->list); @@ -1180,12 +1180,12 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, return -EINVAL; spin_lock_irqsave(&phba->hbalock, iflags); - if (phba->pport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { phba->hba_flag &= ~HBA_RRQ_ACTIVE; goto out; } - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) + if (ndlp->vport && test_bit(FC_UNLOADING, &ndlp->vport->load_flag)) goto out; if (!ndlp->active_rrqs_xri_bitmap) @@ -1732,7 +1732,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, (ulp_command != CMD_ABORT_XRI_CN) && (ulp_command != CMD_CLOSE_XRI_CN)) { BUG_ON(!piocb->vport); - if (!(piocb->vport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &piocb->vport->load_flag)) mod_timer(&piocb->vport->els_tmofunc, jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); @@ -2882,7 +2882,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * If a REG_LOGIN succeeded after node is destroyed or node * is in re-discovery driver need to cleanup the RPI. */ - if (!(phba->pport->load_flag & FC_UNLOADING) && + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag) && pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 && !pmb->u.mb.mbxStatus) { mp = (struct lpfc_dmabuf *)pmb->ctx_buf; @@ -2904,7 +2904,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) && - !(phba->pport->load_flag & FC_UNLOADING) && + !test_bit(FC_UNLOADING, &phba->pport->load_flag) && !pmb->u.mb.mbxStatus) { shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); @@ -2927,7 +2927,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x x%px x%x x%x\n", + "on NPort x%x Data: x%x x%x x%px x%lx x%x\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp, vport->load_flag, kref_read(&ndlp->kref)); @@ -3235,7 +3235,7 @@ lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) lpfc_nvmeio_data(phba, "NVME LS RCV: xri x%x sz %d from %06x\n", oxid, size, sid); - if (phba->pport->load_flag & FC_UNLOADING) { + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { failwhy = "Driver Unloading"; } else if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { failwhy = "NVME FC4 Disabled"; @@ -3940,7 +3940,7 @@ void lpfc_poll_eratt(struct timer_list *t) if (!(phba->hba_flag & HBA_SETUP)) return; - if (phba->pport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; /* Here we will also keep track of interrupts per sec of the hba */ @@ -12428,7 +12428,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * If we're unloading, don't abort iocb on the ELS ring, but change * the callback so that nothing happens when it finishes. */ - if ((vport->load_flag & FC_UNLOADING) && + if (test_bit(FC_UNLOADING, &vport->load_flag) && pring->ringno == LPFC_ELS_RING) { if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; @@ -14658,7 +14658,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { spin_unlock_irqrestore(&phba->hbalock, iflags); /* Handle MDS Loopback frames */ - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_sli4_handle_mds_loopback(phba->pport, dma_buf); else @@ -19457,7 +19457,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { vport = phba->pport; /* Handle MDS Loopback frames */ - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_sli4_handle_mds_loopback(vport, dmabuf); else lpfc_in_buf_free(phba, &dmabuf->dbuf); diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index e2e0518e8387..35dc6b74cb01 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -408,7 +408,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vport->fc_vport = fc_vport; /* At this point we are fully registered with SCSI Layer. */ - vport->load_flag |= FC_ALLOW_FDMI; + set_bit(FC_ALLOW_FDMI, &vport->load_flag); if (phba->cfg_enable_SmartSAN || (phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT)) { /* Setup appropriate attribute masks */ @@ -538,7 +538,7 @@ disable_vport(struct fc_vport *fc_vport) struct lpfc_nodelist *ndlp = NULL; /* Can't disable during an outstanding delete. */ - if (vport->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &vport->load_flag)) return 0; ndlp = lpfc_findnode_did(vport, Fabric_DID); @@ -571,7 +571,6 @@ enable_vport(struct fc_vport *fc_vport) struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if ((phba->link_state < LPFC_LINK_UP) || (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) { @@ -579,9 +578,7 @@ enable_vport(struct fc_vport *fc_vport) return VPORT_OK; } - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_LOADING; - spin_unlock_irq(shost->host_lock); + set_bit(FC_LOADING, &vport->load_flag); if (test_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag)) { lpfc_issue_init_vpi(vport); goto out; @@ -639,22 +636,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport) /* If the vport is a static vport fail the deletion. */ if ((vport->vport_flag & STATIC_VPORT) && - !(phba->pport->load_flag & FC_UNLOADING)) { + !test_bit(FC_UNLOADING, &phba->pport->load_flag)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1837 vport_delete failed: Cannot delete " "static vport.\n"); return VPORT_ERROR; } - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); + set_bit(FC_UNLOADING, &vport->load_flag); /* * If we are not unloading the driver then prevent the vport_delete * from happening until after this vport's discovery is finished. */ - if (!(phba->pport->load_flag & FC_UNLOADING)) { + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) { int check_count = 0; while (check_count < ((phba->fc_ratov * 3) + 3) && vport->port_state > LPFC_VPORT_FAILED && @@ -721,7 +716,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) goto skip_logo; } - if (!(phba->pport->load_flag & FC_UNLOADING)) + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) lpfc_discovery_wait(vport); skip_logo: @@ -732,7 +727,7 @@ skip_logo: lpfc_sli_host_down(vport); lpfc_stop_vport_timers(vport); - if (!(phba->pport->load_flag & FC_UNLOADING)) { + if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) { lpfc_unreg_all_rpis(vport); lpfc_unreg_default_rpis(vport); /* @@ -769,7 +764,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) return NULL; spin_lock_irq(&phba->port_list_lock); list_for_each_entry(port_iterator, &phba->port_list, listentry) { - if (port_iterator->load_flag & FC_UNLOADING) + if (test_bit(FC_UNLOADING, &port_iterator->load_flag)) continue; if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { lpfc_printf_vlog(port_iterator, KERN_ERR, From 5b22878daf484a69c299a42f04e7d209d475e9fc Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:11 -0800 Subject: [PATCH 205/814] scsi: lpfc: Update lpfc version to 14.4.0.0 Update lpfc version to 14.4.0.0. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-17-justintee8345@gmail.com Reviewed-by: Himanshu Madhani 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 aba1c1cee8c4..573c9721ea0a 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.17" +#define LPFC_DRIVER_VERSION "14.4.0.0" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From ea4044e4dd0d0cea5cc476c7d4857425e793b7e1 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 31 Jan 2024 10:51:12 -0800 Subject: [PATCH 206/814] scsi: lpfc: Copyright updates for 14.4.0.0 patches Update copyrights to 2024 for files modified in the 14.4.0.0 patch set. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20240131185112.149731-18-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 2 +- drivers/scsi/lpfc/lpfc_attr.c | 2 +- drivers/scsi/lpfc/lpfc_bsg.c | 2 +- drivers/scsi/lpfc/lpfc_ct.c | 2 +- drivers/scsi/lpfc/lpfc_debugfs.c | 2 +- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_hw4.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 2 +- drivers/scsi/lpfc/lpfc_mbox.c | 2 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- drivers/scsi/lpfc/lpfc_nvme.c | 2 +- drivers/scsi/lpfc/lpfc_nvmet.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 2 +- drivers/scsi/lpfc/lpfc_version.h | 4 ++-- drivers/scsi/lpfc/lpfc_vport.c | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index b863f87ff9e7..30d20d37554f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 55289abb6cf7..365c7e96070b 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 095914854dda..d80e6e81053b 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 2a0c6a4df090..b30765b9689a 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 03abc401c5f2..ab5af10c8a16 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 143f32b63249..28e56542e072 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f97817ac463d..a7a2309a629f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f6b1168304f3..367e6b066d42 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 345a7d5784d8..88b2e57d90c2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 162a0df8b60e..f7c41958036b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 24f171045abe..8e425be7c7c9 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-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index c3daf158bc2a..09c53b85bcb8 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 255189eda388..8258b771bd00 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 07e941da8a16..81fb766c7746 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1aad39015ee0..1f8a9b5945cb 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 573c9721ea0a..56f5889dbaf9 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * @@ -32,6 +32,6 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017-2023 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2024 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 35dc6b74cb01..0f79840b9498 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 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. * From 4dbde797b9464548258c169fb3d826a4dd3fefdf Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 15:39:00 -0300 Subject: [PATCH 207/814] scsi: fcoe: Make fcoe_bus_type const Now that the driver core can properly handle constant struct bus_type, move the fcoe_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240203-bus_cleanup-scsi-v1-1-6f552fb24f71@marliere.net Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index c64a085a7ee2..453665ac6020 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -597,7 +597,7 @@ static const struct attribute_group *fcoe_fcf_attr_groups[] = { NULL, }; -static struct bus_type fcoe_bus_type; +static const struct bus_type fcoe_bus_type; static int fcoe_bus_match(struct device *dev, struct device_driver *drv) @@ -664,7 +664,7 @@ static struct attribute *fcoe_bus_attrs[] = { }; ATTRIBUTE_GROUPS(fcoe_bus); -static struct bus_type fcoe_bus_type = { +static const struct bus_type fcoe_bus_type = { .name = "fcoe", .match = &fcoe_bus_match, .bus_groups = fcoe_bus_groups, From 824ec98b1b5557ea5f43b2ebc6afee9eab08255e Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 15:39:01 -0300 Subject: [PATCH 208/814] scsi: iscsi: Make iscsi_flashnode_bus const Now that the driver core can properly handle constant struct bus_type, move the iscsi_flashnode_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240203-bus_cleanup-scsi-v1-2-6f552fb24f71@marliere.net Reviewed-by: Lee Duncan Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 3075b2ddf7a6..af3ac6346796 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1201,7 +1201,7 @@ static const struct device_type iscsi_flashnode_conn_dev_type = { .release = iscsi_flashnode_conn_release, }; -static struct bus_type iscsi_flashnode_bus; +static const struct bus_type iscsi_flashnode_bus; int iscsi_flashnode_bus_match(struct device *dev, struct device_driver *drv) @@ -1212,7 +1212,7 @@ int iscsi_flashnode_bus_match(struct device *dev, } EXPORT_SYMBOL_GPL(iscsi_flashnode_bus_match); -static struct bus_type iscsi_flashnode_bus = { +static const struct bus_type iscsi_flashnode_bus = { .name = "iscsi_flashnode", .match = &iscsi_flashnode_bus_match, }; From ac0dd0f33adb804b8301ae415a91f56f97f40bae Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 15:39:02 -0300 Subject: [PATCH 209/814] scsi: scsi_debug: Make pseudo_lld_bus const Now that the driver core can properly handle constant struct bus_type, move the pseudo_lld_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240203-bus_cleanup-scsi-v1-3-6f552fb24f71@marliere.net Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d03d66f11493..914d9c12e741 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -899,7 +899,7 @@ static int poll_queues; /* iouring iopoll interface.*/ static char sdebug_proc_name[] = MY_NAME; static const char *my_name = MY_NAME; -static struct bus_type pseudo_lld_bus; +static const struct bus_type pseudo_lld_bus; static struct device_driver sdebug_driverfs_driver = { .name = sdebug_proc_name, @@ -8405,7 +8405,7 @@ static void sdebug_driver_remove(struct device *dev) scsi_host_put(sdbg_host->shost); } -static struct bus_type pseudo_lld_bus = { +static const struct bus_type pseudo_lld_bus = { .name = "pseudo", .probe = sdebug_driver_probe, .remove = sdebug_driver_remove, From 4ad9465365378d696545a337c4b1a28277de84d7 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 17:48:26 -0300 Subject: [PATCH 210/814] scsi: target: tcm_loop: Make tcm_loop_lld_bus const Now that the driver core can properly handle constant struct bus_type, move the tcm_loop_lld_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240204-bus_cleanup-target-v1-1-96106936c4ab@marliere.net Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/target/loopback/tcm_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 8e4035ff3674..761c511aea07 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -83,7 +83,7 @@ static int tcm_loop_show_info(struct seq_file *m, struct Scsi_Host *host) static int tcm_loop_driver_probe(struct device *); static void tcm_loop_driver_remove(struct device *); -static struct bus_type tcm_loop_lld_bus = { +static const struct bus_type tcm_loop_lld_bus = { .name = "tcm_loop_bus", .probe = tcm_loop_driver_probe, .remove = tcm_loop_driver_remove, From 3d75b8aa5c29058a512db29da7cbee8052724157 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:15:30 -0800 Subject: [PATCH 211/814] KVM: Always flush async #PF workqueue when vCPU is being destroyed Always flush the per-vCPU async #PF workqueue when a vCPU is clearing its completion queue, e.g. when a VM and all its vCPUs is being destroyed. KVM must ensure that none of its workqueue callbacks is running when the last reference to the KVM _module_ is put. Gifting a reference to the associated VM prevents the workqueue callback from dereferencing freed vCPU/VM memory, but does not prevent the KVM module from being unloaded before the callback completes. Drop the misguided VM refcount gifting, as calling kvm_put_kvm() from async_pf_execute() if kvm_put_kvm() flushes the async #PF workqueue will result in deadlock. async_pf_execute() can't return until kvm_put_kvm() finishes, and kvm_put_kvm() can't return until async_pf_execute() finishes: WARNING: CPU: 8 PID: 251 at virt/kvm/kvm_main.c:1435 kvm_put_kvm+0x2d/0x320 [kvm] Modules linked in: vhost_net vhost vhost_iotlb tap kvm_intel kvm irqbypass CPU: 8 PID: 251 Comm: kworker/8:1 Tainted: G W 6.6.0-rc1-e7af8d17224a-x86/gmem-vm #119 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 Workqueue: events async_pf_execute [kvm] RIP: 0010:kvm_put_kvm+0x2d/0x320 [kvm] Call Trace: async_pf_execute+0x198/0x260 [kvm] process_one_work+0x145/0x2d0 worker_thread+0x27e/0x3a0 kthread+0xba/0xe0 ret_from_fork+0x2d/0x50 ret_from_fork_asm+0x11/0x20 ---[ end trace 0000000000000000 ]--- INFO: task kworker/8:1:251 blocked for more than 120 seconds. Tainted: G W 6.6.0-rc1-e7af8d17224a-x86/gmem-vm #119 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:kworker/8:1 state:D stack:0 pid:251 ppid:2 flags:0x00004000 Workqueue: events async_pf_execute [kvm] Call Trace: __schedule+0x33f/0xa40 schedule+0x53/0xc0 schedule_timeout+0x12a/0x140 __wait_for_common+0x8d/0x1d0 __flush_work.isra.0+0x19f/0x2c0 kvm_clear_async_pf_completion_queue+0x129/0x190 [kvm] kvm_arch_destroy_vm+0x78/0x1b0 [kvm] kvm_put_kvm+0x1c1/0x320 [kvm] async_pf_execute+0x198/0x260 [kvm] process_one_work+0x145/0x2d0 worker_thread+0x27e/0x3a0 kthread+0xba/0xe0 ret_from_fork+0x2d/0x50 ret_from_fork_asm+0x11/0x20 If kvm_clear_async_pf_completion_queue() actually flushes the workqueue, then there's no need to gift async_pf_execute() a reference because all invocations of async_pf_execute() will be forced to complete before the vCPU and its VM are destroyed/freed. And that in turn fixes the module unloading bug as __fput() won't do module_put() on the last vCPU reference until the vCPU has been freed, e.g. if closing the vCPU file also puts the last reference to the KVM module. Note that kvm_check_async_pf_completion() may also take the work item off the completion queue and so also needs to flush the work queue, as the work will not be seen by kvm_clear_async_pf_completion_queue(). Waiting on the workqueue could theoretically delay a vCPU due to waiting for the work to complete, but that's a very, very small chance, and likely a very small delay. kvm_arch_async_page_present_queued() unconditionally makes a new request, i.e. will effectively delay entering the guest, so the remaining work is really just: trace_kvm_async_pf_completed(addr, cr2_or_gpa); __kvm_vcpu_wake_up(vcpu); mmput(mm); and mmput() can't drop the last reference to the page tables if the vCPU is still alive, i.e. the vCPU won't get stuck tearing down page tables. Add a helper to do the flushing, specifically to deal with "wakeup all" work items, as they aren't actually work items, i.e. are never placed in a workqueue. Trying to flush a bogus workqueue entry rightly makes __flush_work() complain (kudos to whoever added that sanity check). Note, commit 5f6de5cbebee ("KVM: Prevent module exit until all VMs are freed") *tried* to fix the module refcounting issue by having VMs grab a reference to the module, but that only made the bug slightly harder to hit as it gave async_pf_execute() a bit more time to complete before the KVM module could be unloaded. Fixes: af585b921e5d ("KVM: Halt vcpu if page it tries to access is swapped out") Cc: stable@vger.kernel.org Cc: David Matlack Reviewed-by: Xu Yilun Reviewed-by: Vitaly Kuznetsov Link: https://lore.kernel.org/r/20240110011533.503302-2-seanjc@google.com Signed-off-by: Sean Christopherson --- virt/kvm/async_pf.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index e033c79d528e..28658b9e0d96 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -87,7 +87,27 @@ static void async_pf_execute(struct work_struct *work) __kvm_vcpu_wake_up(vcpu); mmput(mm); - kvm_put_kvm(vcpu->kvm); +} + +static void kvm_flush_and_free_async_pf_work(struct kvm_async_pf *work) +{ + /* + * The async #PF is "done", but KVM must wait for the work item itself, + * i.e. async_pf_execute(), to run to completion. If KVM is a module, + * KVM must ensure *no* code owned by the KVM (the module) can be run + * after the last call to module_put(). Note, flushing the work item + * is always required when the item is taken off the completion queue. + * E.g. even if the vCPU handles the item in the "normal" path, the VM + * could be terminated before async_pf_execute() completes. + * + * Wake all events skip the queue and go straight done, i.e. don't + * need to be flushed (but sanity check that the work wasn't queued). + */ + if (work->wakeup_all) + WARN_ON_ONCE(work->work.func); + else + flush_work(&work->work); + kmem_cache_free(async_pf_cache, work); } void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) @@ -114,7 +134,6 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) #else if (cancel_work_sync(&work->work)) { mmput(work->mm); - kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */ kmem_cache_free(async_pf_cache, work); } #endif @@ -126,7 +145,10 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) list_first_entry(&vcpu->async_pf.done, typeof(*work), link); list_del(&work->link); - kmem_cache_free(async_pf_cache, work); + + spin_unlock(&vcpu->async_pf.lock); + kvm_flush_and_free_async_pf_work(work); + spin_lock(&vcpu->async_pf.lock); } spin_unlock(&vcpu->async_pf.lock); @@ -151,7 +173,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) list_del(&work->queue); vcpu->async_pf.queued--; - kmem_cache_free(async_pf_cache, work); + kvm_flush_and_free_async_pf_work(work); } } @@ -186,7 +208,6 @@ bool kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, work->arch = *arch; work->mm = current->mm; mmget(work->mm); - kvm_get_kvm(work->vcpu->kvm); INIT_WORK(&work->work, async_pf_execute); From 422eeb543ac99ea24b80c19492c3359696500a47 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:15:31 -0800 Subject: [PATCH 212/814] KVM: Put mm immediately after async #PF worker completes remote gup() Put the async #PF worker's reference to the VM's address space as soon as the worker is done with the mm. This will allow deferring getting a reference to the worker itself without having to track whether or not getting a reference succeeded. Note, if the vCPU is still alive, there is no danger of the worker getting stuck with tearing down the host page tables, as userspace also holds a reference (obviously), i.e. there is no risk of delaying the page-present notification due to triggering the slow path in mmput(). Reviewed-by: Vitaly Kuznetsov Reviewed-by: Xu Yilun Link: https://lore.kernel.org/r/20240110011533.503302-3-seanjc@google.com Signed-off-by: Sean Christopherson --- virt/kvm/async_pf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 28658b9e0d96..85acc9e824b9 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -64,6 +64,7 @@ static void async_pf_execute(struct work_struct *work) get_user_pages_remote(mm, addr, 1, FOLL_WRITE, NULL, &locked); if (locked) mmap_read_unlock(mm); + mmput(mm); if (IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC)) kvm_arch_async_page_present(vcpu, apf); @@ -85,8 +86,6 @@ static void async_pf_execute(struct work_struct *work) trace_kvm_async_pf_completed(addr, cr2_or_gpa); __kvm_vcpu_wake_up(vcpu); - - mmput(mm); } static void kvm_flush_and_free_async_pf_work(struct kvm_async_pf *work) From 8284765f03b7a0b18968cefeb5e78aca647b8f8b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:15:32 -0800 Subject: [PATCH 213/814] KVM: Get reference to VM's address space in the async #PF worker Get a reference to the target VM's address space in async_pf_execute() instead of gifting a reference from kvm_setup_async_pf(). Keeping the address space alive just to service an async #PF is counter-productive, i.e. if the process is exiting and all vCPUs are dead, then NOT doing get_user_pages_remote() and freeing the address space asap is desirable. Handling the mm reference entirely within async_pf_execute() also simplifies the async #PF flows as a whole, e.g. it's not immediately obvious when the worker task vs. the vCPU task is responsible for putting the gifted mm reference. Reviewed-by: Vitaly Kuznetsov Reviewed-by: Xu Yilun Link: https://lore.kernel.org/r/20240110011533.503302-4-seanjc@google.com Signed-off-by: Sean Christopherson --- include/linux/kvm_host.h | 1 - virt/kvm/async_pf.c | 32 ++++++++++++++++++-------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7e7fd25b09b3..bbfefd7e612f 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -238,7 +238,6 @@ struct kvm_async_pf { struct list_head link; struct list_head queue; struct kvm_vcpu *vcpu; - struct mm_struct *mm; gpa_t cr2_or_gpa; unsigned long addr; struct kvm_arch_async_pf arch; diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 85acc9e824b9..628f6df7609f 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -46,8 +46,8 @@ static void async_pf_execute(struct work_struct *work) { struct kvm_async_pf *apf = container_of(work, struct kvm_async_pf, work); - struct mm_struct *mm = apf->mm; struct kvm_vcpu *vcpu = apf->vcpu; + struct mm_struct *mm = vcpu->kvm->mm; unsigned long addr = apf->addr; gpa_t cr2_or_gpa = apf->cr2_or_gpa; int locked = 1; @@ -56,16 +56,24 @@ static void async_pf_execute(struct work_struct *work) might_sleep(); /* - * This work is run asynchronously to the task which owns - * mm and might be done in another context, so we must - * access remotely. + * Attempt to pin the VM's host address space, and simply skip gup() if + * acquiring a pin fail, i.e. if the process is exiting. Note, KVM + * holds a reference to its associated mm_struct until the very end of + * kvm_destroy_vm(), i.e. the struct itself won't be freed before this + * work item is fully processed. */ - mmap_read_lock(mm); - get_user_pages_remote(mm, addr, 1, FOLL_WRITE, NULL, &locked); - if (locked) - mmap_read_unlock(mm); - mmput(mm); + if (mmget_not_zero(mm)) { + mmap_read_lock(mm); + get_user_pages_remote(mm, addr, 1, FOLL_WRITE, NULL, &locked); + if (locked) + mmap_read_unlock(mm); + mmput(mm); + } + /* + * Notify and kick the vCPU even if faulting in the page failed, e.g. + * so that the vCPU can retry the fault synchronously. + */ if (IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC)) kvm_arch_async_page_present(vcpu, apf); @@ -131,10 +139,8 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) #ifdef CONFIG_KVM_ASYNC_PF_SYNC flush_work(&work->work); #else - if (cancel_work_sync(&work->work)) { - mmput(work->mm); + if (cancel_work_sync(&work->work)) kmem_cache_free(async_pf_cache, work); - } #endif spin_lock(&vcpu->async_pf.lock); } @@ -205,8 +211,6 @@ bool kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, work->cr2_or_gpa = cr2_or_gpa; work->addr = hva; work->arch = *arch; - work->mm = current->mm; - mmget(work->mm); INIT_WORK(&work->work, async_pf_execute); From c2744ed2230a92636f04cde48f2f7d8d3486e194 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:15:33 -0800 Subject: [PATCH 214/814] KVM: Nullify async #PF worker's "apf" pointer as soon as it might be freed Nullify the async #PF worker's local "apf" pointer immediately after the point where the structure can be freed by the vCPU. The existing comment is helpful, but easy to overlook as there is no associated code. Update the comment to clarify that it can be freed by as soon as the lock is dropped, as "after this point" isn't strictly accurate, nor does it help understand what prevents the structure from being freed earlier. Reviewed-by: Xu Yilun Reviewed-by: Vitaly Kuznetsov Link: https://lore.kernel.org/r/20240110011533.503302-5-seanjc@google.com Signed-off-by: Sean Christopherson --- virt/kvm/async_pf.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 628f6df7609f..99a63bad0306 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -83,14 +83,15 @@ static void async_pf_execute(struct work_struct *work) apf->vcpu = NULL; spin_unlock(&vcpu->async_pf.lock); + /* + * The apf struct may be freed by kvm_check_async_pf_completion() as + * soon as the lock is dropped. Nullify it to prevent improper usage. + */ + apf = NULL; + if (!IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC) && first) kvm_arch_async_page_present_queued(vcpu); - /* - * apf may be freed by kvm_check_async_pf_completion() after - * this point - */ - trace_kvm_async_pf_completed(addr, cr2_or_gpa); __kvm_vcpu_wake_up(vcpu); From d03f030115fe930de1222fef294730ba21b93045 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 16:56:34 -0300 Subject: [PATCH 215/814] Input: gameport - make gameport_bus const Now that the driver core can properly handle constant struct bus_type, move the gameport_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240204-bus_cleanup-input-v1-1-74c2438801cf@marliere.net Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 34f416a3ebcb..cfcc81c47b50 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -38,7 +38,7 @@ static DEFINE_MUTEX(gameport_mutex); static LIST_HEAD(gameport_list); -static struct bus_type gameport_bus; +static const struct bus_type gameport_bus; static void gameport_add_port(struct gameport *gameport); static void gameport_attach_driver(struct gameport_driver *drv); @@ -813,7 +813,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv) return !gameport_drv->ignore; } -static struct bus_type gameport_bus = { +static const struct bus_type gameport_bus = { .name = "gameport", .dev_groups = gameport_device_groups, .drv_groups = gameport_driver_groups, From 6284d33d1749e492596c54a590603d61fb7afc98 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 Feb 2024 08:58:05 +0100 Subject: [PATCH 216/814] dt-bindings: trivial-devices: sort entries alphanumerically Sort entries alphanumerically. This was a semi manual job with help of: cat Documentation/devicetree/bindings/trivial-devices.yaml | grep ' - ' > old cat old | sort -n > new diff -ubB old new Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Acked-by: Guenter Roeck Link: https://lore.kernel.org/r/20240201075805.7492-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/trivial-devices.yaml | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 5b52950e6bfc..41982a41398a 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -28,6 +28,7 @@ properties: compatible: items: + # Entries are sorted alphanumerically by the compatible - enum: # Acbel fsg032 power supply - acbel,fsg032 @@ -49,12 +50,12 @@ properties: - ams,iaq-core # i2c serial eeprom (24cxx) - at,24c08 + # i2c h/w elliptic curve crypto module + - atmel,atecc508a # ATSHA204 - i2c h/w symmetric crypto module - atmel,atsha204 # ATSHA204A - i2c h/w symmetric crypto module - atmel,atsha204a - # i2c h/w elliptic curve crypto module - - atmel,atecc508a # BPA-RS600: Power Supply - blutek,bpa-rs600 # Bosch Sensortec pressure, temperature, humididty and VOC sensor @@ -115,20 +116,6 @@ properties: - fsl,mpl3115 # MPR121: Proximity Capacitive Touch Sensor Controller - fsl,mpr121 - # Monolithic Power Systems Inc. multi-phase controller mp2856 - - mps,mp2856 - # Monolithic Power Systems Inc. multi-phase controller mp2857 - - mps,mp2857 - # Monolithic Power Systems Inc. multi-phase controller mp2888 - - mps,mp2888 - # Monolithic Power Systems Inc. multi-phase controller mp2971 - - mps,mp2971 - # Monolithic Power Systems Inc. multi-phase controller mp2973 - - mps,mp2973 - # Monolithic Power Systems Inc. multi-phase controller mp2975 - - mps,mp2975 - # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5990 - - mps,mp5990 # Honeywell Humidicon HIH-6130 humidity/temperature sensor - honeywell,hi6130 # IBM Common Form Factor Power Supply Versions (all versions) @@ -197,6 +184,8 @@ properties: - maxim,max1237 # Temperature Sensor, I2C interface - maxim,max1619 + # 3-Channel Remote Temperature Sensor + - maxim,max31730 # 10-bit 10 kOhm linear programmable voltage divider - maxim,max5481 # 10-bit 50 kOhm linear programmable voltage divider @@ -209,8 +198,6 @@ properties: - maxim,max6621 # 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface - maxim,max6625 - # 3-Channel Remote Temperature Sensor - - maxim,max31730 # mCube 3-axis 8-bit digital accelerometer - mcube,mc3230 # Measurement Specialities I2C temperature and humidity sensor @@ -241,8 +228,6 @@ properties: - memsic,mxc6655 # Menlo on-board CPLD trivial SPI device - menlo,m53cpld - # Micron SPI NOR Authenta - - micron,spi-authenta # Microchip differential I2C ADC, 1 Channel, 18 bit - microchip,mcp3421 # Microchip differential I2C ADC, 2 Channel, 18 bit @@ -259,40 +244,56 @@ properties: - microchip,mcp3427 # Microchip differential I2C ADC, 4 Channel, 16 bit - microchip,mcp3428 - # Microchip 7-bit Single I2C Digital POT (5k) - - microchip,mcp4017-502 # Microchip 7-bit Single I2C Digital POT (10k) - microchip,mcp4017-103 - # Microchip 7-bit Single I2C Digital POT (50k) - - microchip,mcp4017-503 # Microchip 7-bit Single I2C Digital POT (100k) - microchip,mcp4017-104 # Microchip 7-bit Single I2C Digital POT (5k) - - microchip,mcp4018-502 + - microchip,mcp4017-502 + # Microchip 7-bit Single I2C Digital POT (50k) + - microchip,mcp4017-503 # Microchip 7-bit Single I2C Digital POT (10k) - microchip,mcp4018-103 - # Microchip 7-bit Single I2C Digital POT (50k) - - microchip,mcp4018-503 # Microchip 7-bit Single I2C Digital POT (100k) - microchip,mcp4018-104 # Microchip 7-bit Single I2C Digital POT (5k) - - microchip,mcp4019-502 + - microchip,mcp4018-502 + # Microchip 7-bit Single I2C Digital POT (50k) + - microchip,mcp4018-503 # Microchip 7-bit Single I2C Digital POT (10k) - microchip,mcp4019-103 - # Microchip 7-bit Single I2C Digital POT (50k) - - microchip,mcp4019-503 # Microchip 7-bit Single I2C Digital POT (100k) - microchip,mcp4019-104 + # Microchip 7-bit Single I2C Digital POT (5k) + - microchip,mcp4019-502 + # Microchip 7-bit Single I2C Digital POT (50k) + - microchip,mcp4019-503 # PWM Fan Speed Controller With Fan Fault Detection - microchip,tc654 # PWM Fan Speed Controller With Fan Fault Detection - microchip,tc655 + # Micron SPI NOR Authenta + - micron,spi-authenta # MiraMEMS DA226 2-axis 14-bit digital accelerometer - miramems,da226 # MiraMEMS DA280 3-axis 14-bit digital accelerometer - miramems,da280 # MiraMEMS DA311 3-axis 12-bit digital accelerometer - miramems,da311 + # Monolithic Power Systems Inc. multi-phase controller mp2856 + - mps,mp2856 + # Monolithic Power Systems Inc. multi-phase controller mp2857 + - mps,mp2857 + # Monolithic Power Systems Inc. multi-phase controller mp2888 + - mps,mp2888 + # Monolithic Power Systems Inc. multi-phase controller mp2971 + - mps,mp2971 + # Monolithic Power Systems Inc. multi-phase controller mp2973 + - mps,mp2973 + # Monolithic Power Systems Inc. multi-phase controller mp2975 + - mps,mp2975 + # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5990 + - mps,mp5990 # Temperature sensor with integrated fan control - national,lm63 # Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor @@ -323,12 +324,12 @@ properties: - samsung,exynos-sataphy-i2c # Semtech sx1301 baseband processor - semtech,sx1301 - # Sensirion low power multi-pixel gas sensor with I2C interface - - sensirion,sgpc3 # Sensirion multi-pixel gas sensor with I2C interface - sensirion,sgp30 # Sensirion gas sensor with I2C interface - sensirion,sgp40 + # Sensirion low power multi-pixel gas sensor with I2C interface + - sensirion,sgpc3 # Sensirion temperature & humidity sensor with I2C interface - sensirion,sht4x # Sensortek 3 axis accelerometer @@ -374,8 +375,6 @@ properties: - ti,lm74 # Temperature sensor with integrated fan control - ti,lm96000 - # I2C Touch-Screen Controller - - ti,tsc2003 # Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface - ti,tmp103 # Thermometer with SPI interface @@ -397,10 +396,12 @@ properties: - ti,tps544b25 - ti,tps544c20 - ti,tps544c25 - # Winbond/Nuvoton H/W Monitor - - winbond,w83793 + # I2C Touch-Screen Controller + - ti,tsc2003 # Vicor Corporation Digital Supervisor - vicor,pli1209bc + # Winbond/Nuvoton H/W Monitor + - winbond,w83793 required: - compatible From 4c3b386c46065c0d26ae5503e73d6634f24e2d36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Feb 2024 05:37:19 +0000 Subject: [PATCH 217/814] of: property: add missing kerneldoc for of_graph_get_endpoint_count() of_graph_get_endpoint_count() doesn't have kerneldoc. Add it. Signed-off-by: Kuninori Morimoto Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/87r0hrcvzk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Rob Herring --- drivers/of/property.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/of/property.c b/drivers/of/property.c index a02a985c13ba..455dda225556 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -812,6 +812,12 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) } EXPORT_SYMBOL(of_graph_get_remote_port); +/** + * of_graph_get_endpoint_count() - get the number of endpoints in a device node + * @np: parent device node containing ports and endpoints + * + * Return: count of endpoint of this device node + */ int of_graph_get_endpoint_count(const struct device_node *np) { struct device_node *endpoint; From 574849054d97cee5be78d6c149d84685647fe774 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Feb 2024 05:37:28 +0000 Subject: [PATCH 218/814] of: property: use unsigned int return on of_graph_get_endpoint_count() Because of of_graph_get_endpoint_count() doesn't report error, just return count of endpoint, the return type should be unsigned. Tidyup it. Signed-off-by: Kuninori Morimoto Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/87plxbcvzb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Rob Herring --- drivers/of/property.c | 4 ++-- include/linux/of_graph.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/of/property.c b/drivers/of/property.c index 455dda225556..470d1eb5e56d 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -818,10 +818,10 @@ EXPORT_SYMBOL(of_graph_get_remote_port); * * Return: count of endpoint of this device node */ -int of_graph_get_endpoint_count(const struct device_node *np) +unsigned int of_graph_get_endpoint_count(const struct device_node *np) { struct device_node *endpoint; - int num = 0; + unsigned int num = 0; for_each_endpoint_of_node(np, endpoint) num++; diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index 4d7756087b6b..a4bea62bfa29 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -41,7 +41,7 @@ struct of_endpoint { bool of_graph_is_present(const struct device_node *node); int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); -int of_graph_get_endpoint_count(const struct device_node *np); +unsigned int of_graph_get_endpoint_count(const struct device_node *np); struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); @@ -68,7 +68,7 @@ static inline int of_graph_parse_endpoint(const struct device_node *node, return -ENOSYS; } -static inline int of_graph_get_endpoint_count(const struct device_node *np) +static inline unsigned int of_graph_get_endpoint_count(const struct device_node *np) { return 0; } From b0bcec86f47b44c98a23c31d54dd3963e27761a2 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 31 Jan 2024 12:37:24 +0530 Subject: [PATCH 219/814] dt-bindings: phy: qmp-ufs: Fix PHY clocks All QMP UFS PHYs except MSM8996 require 3 clocks: * ref - 19.2MHz reference clock from RPMh * ref_aux - Auxiliary reference clock from GCC * qref - QREF clock from GCC or TCSR (since SM8550) MSM8996 only requires 'ref' and 'qref' clocks. Hence, fix the binding to reflect the actual clock topology. This change obviously breaks the ABI, but it is inevitable since the clock topology needs to be accurately described in the binding. Reviewed-by: Conor Dooley Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20240131-ufs-phy-clock-v3-1-58a49d2f4605@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) 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 5faa1cb3a12e..91a6cc38ff7f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -39,15 +39,12 @@ properties: maxItems: 1 clocks: - minItems: 1 + minItems: 2 maxItems: 3 clock-names: - minItems: 1 - items: - - const: ref - - const: ref_aux - - const: qref + minItems: 2 + maxItems: 3 power-domains: maxItems: 1 @@ -87,23 +84,9 @@ allOf: compatible: contains: enum: + - qcom,msm8998-qmp-ufs-phy - qcom,sa8775p-qmp-ufs-phy - qcom,sc7280-qmp-ufs-phy - - qcom,sm8450-qmp-ufs-phy - then: - properties: - clocks: - minItems: 3 - clock-names: - minItems: 3 - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8998-qmp-ufs-phy - - qcom,sc7180-qmp-ufs-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy - qcom,sdm845-qmp-ufs-phy @@ -114,14 +97,19 @@ allOf: - 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 - qcom,sm8650-qmp-ufs-phy then: properties: clocks: - maxItems: 2 + minItems: 3 + maxItems: 3 clock-names: - maxItems: 2 + items: + - const: ref + - const: ref_aux + - const: qref - if: properties: @@ -132,22 +120,28 @@ allOf: then: properties: clocks: - maxItems: 1 + minItems: 2 + maxItems: 2 clock-names: - maxItems: 1 + items: + - const: ref + - const: qref additionalProperties: false examples: - | #include + #include ufs_mem_phy: phy@1d87000 { compatible = "qcom,sc8280xp-qmp-ufs-phy"; reg = <0x01d87000 0x1000>; - clocks = <&gcc GCC_UFS_REF_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; - clock-names = "ref", "ref_aux"; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&gcc GCC_UFS_REF_CLKREF_CLK>; + + clock-names = "ref", "ref_aux", "qref"; power-domains = <&gcc UFS_PHY_GDSC>; From 2668cae8b64bf25c4c7a39eb2cb0012c92153c11 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 31 Jan 2024 12:37:25 +0530 Subject: [PATCH 220/814] phy: qcom-qmp-ufs: Switch to devm_clk_bulk_get_all() API Device drivers should just rely on the clocks provided by the devicetree and enable/disable them based on the requirement. There is no need to validate the clocks provided by devicetree in the driver. That's the job of DT schema. So let's switch to devm_clk_bulk_get_all() API that just gets the clocks provided by devicetree and remove hardcoded clocks info. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240131-ufs-phy-clock-v3-2-58a49d2f4605@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 63 +++---------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 38c4a4cc670a..590432d581f9 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -923,9 +923,6 @@ struct qmp_phy_cfg { /* Additional sequence for different HS Gears */ const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; - /* clock ids to be requested */ - const char * const *clk_list; - int num_clks; /* regulators to be requested */ const char * const *vreg_list; int num_vregs; @@ -951,6 +948,7 @@ struct qmp_ufs { void __iomem *rx2; struct clk_bulk_data *clks; + int num_clks; struct regulator_bulk_data *vregs; struct reset_control *ufs_reset; @@ -983,20 +981,6 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* list of clocks required by phy */ -static const char * const msm8996_ufs_phy_clk_l[] = { - "ref", -}; - -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const sm8450_ufs_phy_clk_l[] = { - "qref", "ref", "ref_aux", -}; - -static const char * const sdm845_ufs_phy_clk_l[] = { - "ref", "ref_aux", -}; - /* list of regulators */ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", @@ -1035,9 +1019,6 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx), }, - .clk_list = msm8996_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l), - .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), @@ -1075,8 +1056,6 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1111,8 +1090,6 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1147,8 +1124,6 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1174,8 +1149,6 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1203,8 +1176,6 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .serdes = sm6115_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v2_regs_layout, @@ -1232,8 +1203,6 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1270,8 +1239,6 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1306,8 +1273,6 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1342,8 +1307,6 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1378,8 +1341,6 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1425,8 +1386,6 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs), .max_gear = UFS_HS_G5, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v6_regs_layout, @@ -1448,8 +1407,6 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .pcs = sm8650_ufsphy_pcs, .pcs_num = ARRAY_SIZE(sm8650_ufsphy_pcs), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v6_regs_layout, @@ -1541,7 +1498,7 @@ static int qmp_ufs_com_init(struct qmp_ufs *qmp) return ret; } - ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); if (ret) goto err_disable_regulators; @@ -1561,7 +1518,7 @@ static int qmp_ufs_com_exit(struct qmp_ufs *qmp) reset_control_assert(qmp->ufs_reset); - 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); @@ -1737,19 +1694,13 @@ static int qmp_ufs_vreg_init(struct qmp_ufs *qmp) static int qmp_ufs_clk_init(struct qmp_ufs *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; + qmp->num_clks = devm_clk_bulk_get_all(dev, &qmp->clks); + if (qmp->num_clks < 0) + return qmp->num_clks; - for (i = 0; i < num; i++) - qmp->clks[i].id = cfg->clk_list[i]; - - return devm_clk_bulk_get(dev, num, qmp->clks); + return 0; } static void qmp_ufs_clk_release_provider(void *res) From 088de1293c84d0c08f0f4c30d2dd7cb14888aa6c Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Jan 2024 14:30:09 +0100 Subject: [PATCH 221/814] dt-bindings: phy: cadence-torrent: Add optional input reference clock for PLL1 Add a new optional input reference clock (pll1_refclk) for PLL1. Update bindings to support dual reference clock multilink configurations. Signed-off-by: Swapnil Jakhade Acked-by: Krzysztof Kozlowski Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240104133013.2911035-2-sjakhade@cadence.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-cadence-torrent.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index dfb31314face..3893800f81b4 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -35,14 +35,18 @@ properties: minItems: 1 maxItems: 2 description: - PHY reference clock for 1 item. Must contain an entry in clock-names. - Optional Parent to enable output reference clock. + PHY input reference clocks - refclk (for PLL0) & pll1_refclk (for PLL1). + pll1_refclk is optional and used for multi-protocol configurations requiring + separate reference clock for each protocol. + Same refclk is used for both PLL0 and PLL1 if no separate pll1_refclk is used. + Optional parent clock (phy_en_refclk) to enable a reference clock output feature + on some platforms to output either derived or received reference clock. clock-names: minItems: 1 items: - const: refclk - - const: phy_en_refclk + - enum: [ pll1_refclk, phy_en_refclk ] reg: minItems: 1 From b426146adc2091368dc0f908d27fd4c6b62a6f95 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Jan 2024 14:30:10 +0100 Subject: [PATCH 222/814] phy: cadence-torrent: Add PCIe(100MHz) + USXGMII(156.25MHz) multilink configuration Torrent PHY can have separate input reference clocks for PLL0 and PLL1. Add support for dual reference clock multilink configurations. Add register sequences for PCIe(100MHz) + USXGMII(156.25MHz) multilink configuration. PCIe uses PLL0 and USXGMII uses PLL1. Signed-off-by: Swapnil Jakhade Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240104133013.2911035-3-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 209 +++++++++++++++++++++- 1 file changed, 200 insertions(+), 9 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index a75c96385c57..d22ffc97bce9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -355,7 +355,9 @@ struct cdns_torrent_phy { struct reset_control *apb_rst; struct device *dev; struct clk *clk; + struct clk *clk1; enum cdns_torrent_ref_clk ref_clk_rate; + enum cdns_torrent_ref_clk ref_clk1_rate; struct cdns_torrent_inst phys[MAX_NUM_LANES]; int nsubnodes; const struct cdns_torrent_data *init_data; @@ -2460,9 +2462,11 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { const struct cdns_torrent_data *init_data = cdns_phy->init_data; struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + enum cdns_torrent_ref_clk ref_clk1 = cdns_phy->ref_clk1_rate; enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; enum cdns_torrent_phy_type phy_t1, phy_t2; + struct cdns_torrent_vals *phy_pma_cmn_vals; struct cdns_torrent_vals *pcs_cmn_vals; int i, j, node, mlane, num_lanes, ret; struct cdns_reg_pairs *reg_pairs; @@ -2489,6 +2493,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) * Get the array values as [phy_t2][phy_t1][ssc]. */ swap(phy_t1, phy_t2); + swap(ref_clk, ref_clk1); } mlane = cdns_phy->phys[node].mlane; @@ -2552,9 +2557,22 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) reg_pairs[i].val); } + /* PHY PMA common registers configurations */ + phy_pma_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_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 = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; @@ -2567,7 +2585,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) /* PMA TX lane registers configurations */ tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; @@ -2582,7 +2600,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) /* PMA RX lane registers configurations */ rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; @@ -2684,9 +2702,11 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) { struct device *dev = cdns_phy->dev; + unsigned long ref_clk1_rate; unsigned long ref_clk_rate; int ret; + /* refclk: Input reference clock for PLL0 */ cdns_phy->clk = devm_clk_get(dev, "refclk"); if (IS_ERR(cdns_phy->clk)) { dev_err(dev, "phy ref clock not found\n"); @@ -2695,15 +2715,15 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) ret = clk_prepare_enable(cdns_phy->clk); if (ret) { - dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + dev_err(cdns_phy->dev, "Failed to prepare ref clock: %d\n", ret); return ret; } ref_clk_rate = clk_get_rate(cdns_phy->clk); if (!ref_clk_rate) { dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + ret = -EINVAL; + goto disable_clk; } switch (ref_clk_rate) { @@ -2720,12 +2740,62 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) 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); - return -EINVAL; + dev_err(cdns_phy->dev, "Invalid ref clock rate\n"); + ret = -EINVAL; + goto disable_clk; + } + + /* refclk1: Input reference clock for PLL1 */ + cdns_phy->clk1 = devm_clk_get_optional(dev, "pll1_refclk"); + if (IS_ERR(cdns_phy->clk1)) { + dev_err(dev, "phy PLL1 ref clock not found\n"); + ret = PTR_ERR(cdns_phy->clk1); + goto disable_clk; + } + + if (cdns_phy->clk1) { + ret = clk_prepare_enable(cdns_phy->clk1); + if (ret) { + dev_err(cdns_phy->dev, "Failed to prepare PLL1 ref clock: %d\n", ret); + goto disable_clk; + } + + ref_clk1_rate = clk_get_rate(cdns_phy->clk1); + if (!ref_clk1_rate) { + dev_err(cdns_phy->dev, "Failed to get PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + + switch (ref_clk1_rate) { + case REF_CLK_19_2MHZ: + cdns_phy->ref_clk1_rate = CLK_19_2_MHZ; + break; + case REF_CLK_25MHZ: + cdns_phy->ref_clk1_rate = CLK_25_MHZ; + break; + case REF_CLK_100MHZ: + cdns_phy->ref_clk1_rate = CLK_100_MHZ; + break; + case REF_CLK_156_25MHZ: + cdns_phy->ref_clk1_rate = CLK_156_25_MHZ; + break; + default: + dev_err(cdns_phy->dev, "Invalid PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + } else { + cdns_phy->ref_clk1_rate = cdns_phy->ref_clk_rate; } return 0; + +disable_clk1: + clk_disable_unprepare(cdns_phy->clk1); +disable_clk: + clk_disable_unprepare(cdns_phy->clk); + return ret; } static int cdns_torrent_phy_probe(struct platform_device *pdev) @@ -2980,6 +3050,7 @@ put_lnk_rst: reset_control_put(cdns_phy->phys[i].lnk_rst); of_node_put(child); reset_control_assert(cdns_phy->apb_rst); + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); clk_cleanup: cdns_torrent_clk_cleanup(cdns_phy); @@ -2998,6 +3069,7 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev) reset_control_put(cdns_phy->phys[i].lnk_rst); } + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); cdns_torrent_clk_cleanup(cdns_phy); } @@ -3034,6 +3106,100 @@ static struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = { .num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs), }; +/* PCIe and USXGMII link configuration */ +static struct cdns_reg_pairs pcie_usxgmii_link_cmn_regs[] = { + {0x0003, PHY_PLL_CFG}, + {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}, + {0x0400, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs pcie_usxgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0012, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_reg_pairs usxgmii_pcie_xcvr_diag_ln_regs[] = { + {0x0011, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0089, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals pcie_usxgmii_link_cmn_vals = { + .reg_pairs = pcie_usxgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals pcie_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = pcie_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_xcvr_diag_ln_regs), +}; + +static struct cdns_torrent_vals usxgmii_pcie_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_pcie_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_pcie_xcvr_diag_ln_regs), +}; + +/* + * Multilink USXGMII, using PLL1, 156.25 MHz Ref clk, no SSC + */ +static struct cdns_reg_pairs ml_usxgmii_pll1_156_25_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0014, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL1_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x0138, CMN_PLL1_LOCK_REFCNT_START}, + {0x0138, CMN_PLL1_LOCK_PLLCNT_START}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_reg_pairs ml_usxgmii_156_25_no_ssc_tx_ln_regs[] = { + {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 ml_usxgmii_156_25_no_ssc_rx_ln_regs[] = { + {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 ml_usxgmii_pll1_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll1_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll1_156_25_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_tx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_rx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_rx_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}, @@ -4166,6 +4332,7 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {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_PCIE, TYPE_USXGMII), &pcie_usxgmii_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}, @@ -4182,6 +4349,7 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {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}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals}, }; static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { @@ -4194,6 +4362,7 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {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_PCIE, TYPE_USXGMII), &pcie_usxgmii_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}, @@ -4210,6 +4379,7 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {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}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals}, }; static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { @@ -4285,6 +4455,11 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = { {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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, }; static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { @@ -4352,6 +4527,11 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { {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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { @@ -4419,6 +4599,11 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { {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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, }; static const struct cdns_torrent_data cdns_map_torrent = { @@ -4452,6 +4637,7 @@ static const struct cdns_torrent_data cdns_map_torrent = { 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}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &ti_usxgmii_phy_pma_cmn_vals}, }; static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { @@ -4519,6 +4705,11 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { {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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static const struct cdns_torrent_data ti_j721e_map_torrent = { From c8369091b49766f4cf40ba11b90741074f8e6f18 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Jan 2024 14:30:11 +0100 Subject: [PATCH 223/814] phy: cadence-torrent: Add USXGMII(156.25MHz) + SGMII/QSGMII(100MHz) multilink configuration Add register sequences for USXGMII(156.25MHz) + SGMII/QSGMII(100MHz) multilink configuration. USXGMII uses PLL0 and SGMII/QSGMII uses PLL1. Signed-off-by: Swapnil Jakhade Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240104133013.2911035-4-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 101 ++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index d22ffc97bce9..d1f9ffed5bba 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -3106,6 +3106,73 @@ static struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = { .num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs), }; +/* USXGMII and SGMII/QSGMII link configuration */ +static struct cdns_reg_pairs usxgmii_sgmii_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0601, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs usxgmii_sgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0001, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_reg_pairs sgmii_usxgmii_xcvr_diag_ln_regs[] = { + {0x0111, XCVR_DIAG_HSCLK_SEL}, + {0x0103, XCVR_DIAG_HSCLK_DIV}, + {0x0A9B, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals usxgmii_sgmii_link_cmn_vals = { + .reg_pairs = usxgmii_sgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals usxgmii_sgmii_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_sgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_xcvr_diag_ln_regs), +}; + +static struct cdns_torrent_vals sgmii_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = sgmii_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_usxgmii_xcvr_diag_ln_regs), +}; + +/* Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static struct cdns_torrent_vals ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_torrent_vals ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + /* PCIe and USXGMII link configuration */ static struct cdns_reg_pairs pcie_usxgmii_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, @@ -4337,10 +4404,12 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {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_SGMII, TYPE_USXGMII), &usxgmii_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_QSGMII, TYPE_USXGMII), &usxgmii_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}, @@ -4350,6 +4419,8 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_link_cmn_vals}, }; static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { @@ -4367,10 +4438,12 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {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_SGMII, TYPE_USXGMII), &sgmii_usxgmii_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_QSGMII, TYPE_USXGMII), &sgmii_usxgmii_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}, @@ -4380,6 +4453,8 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, }; static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { @@ -4459,7 +4534,13 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = { /* Dual refclk */ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, }; static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { @@ -4531,7 +4612,13 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { /* Dual refclk */ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { @@ -4603,7 +4690,13 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { /* Dual refclk */ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, }; static const struct cdns_torrent_data cdns_map_torrent = { @@ -4638,6 +4731,8 @@ static const struct cdns_torrent_data cdns_map_torrent = { 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}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &ti_usxgmii_phy_pma_cmn_vals}, }; static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { @@ -4709,7 +4804,13 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { /* Dual refclk */ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static const struct cdns_torrent_data ti_j721e_map_torrent = { From dc44dac3a787d55c26991d56a605c606b8ec3960 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Jan 2024 14:30:12 +0100 Subject: [PATCH 224/814] dt-bindings: phy: cadence-torrent: Add a separate compatible for TI J7200 TI J7200 uses Torrent SD0805 version which is a special version derived from Torrent SD0801 with some differences in register configurations. Add a separate compatible for TI J7200 platforms. Signed-off-by: Swapnil Jakhade Acked-by: Conor Dooley Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240104133013.2911035-5-sjakhade@cadence.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index 3893800f81b4..15dc8efe6ffe 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -20,6 +20,7 @@ properties: compatible: enum: - cdns,torrent-phy + - ti,j7200-serdes-10g - ti,j721e-serdes-10g '#address-cells': From 5398be49d7c1d88ead4aba82703fef35894b36ba Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Jan 2024 14:30:13 +0100 Subject: [PATCH 225/814] phy: cadence-torrent: Add USXGMII(156.25MHz) + SGMII/QSGMII(100MHz) multilink config for TI J7200 Add a separate compatible and registers map table for TI J7200. TI J7200 uses Torrent SD0805 version which is a special version derived from Torrent SD0801 with some differences in register configurations. Add register sequences for USXGMII(156.25MHz) + SGMII/QSGMII(100MHz) multilink config for TI J7200. USXGMII uses PLL0 and SGMII/QSGMII uses PLL1. Signed-off-by: Swapnil Jakhade Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240104133013.2911035-6-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 410 ++++++++++++++++++++++ 1 file changed, 410 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index d1f9ffed5bba..95924a09960c 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -3173,6 +3173,55 @@ static struct cdns_torrent_vals ml_sgmii_pll1_100_no_ssc_cmn_vals = { .num_regs = ARRAY_SIZE(ml_sgmii_pll1_100_no_ssc_cmn_regs), }; +/* TI J7200, Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_SSM_BIAS_TMR}, + {0x0028, CMN_PLLSM0_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM0_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}, + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static struct cdns_torrent_vals j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* TI J7200, Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PLLSM1_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM1_PLLLOCK_TMR}, + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_torrent_vals j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + /* PCIe and USXGMII link configuration */ static struct cdns_reg_pairs pcie_usxgmii_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, @@ -4044,6 +4093,50 @@ static struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = { .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink SGMII */ +static struct cdns_reg_pairs j7200_sgmii_100_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}, + {0x00B3, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static struct cdns_torrent_vals j7200_sgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_tx_ln_regs), +}; + +static struct cdns_reg_pairs j7200_sgmii_100_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}, + {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}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals j7200_sgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_rx_ln_regs), +}; + /* SGMII 100 MHz Ref clk, internal SSC */ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, @@ -4177,6 +4270,51 @@ static struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = { .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink QSGMII */ +static struct cdns_reg_pairs j7200_qsgmii_100_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}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, + {0x0003, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_tx_ln_regs), +}; + +static struct cdns_reg_pairs j7200_qsgmii_100_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}, + {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}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_rx_ln_regs), +}; + /* QSGMII 100 MHz Ref clk, internal SSC */ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, @@ -4846,6 +4984,274 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }; +/* TI J7200 (Torrent SD0805) */ +static struct cdns_torrent_vals_entry ti_j7200_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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry ti_j7200_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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, +}; + +static struct cdns_torrent_vals_entry ti_j7200_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}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, +}; + +static const struct cdns_torrent_data ti_j7200_map_torrent = { + .block_offset_shift = 0x0, + .reg_offset_shift = 0x1, + .link_cmn_vals_tbl = { + .entries = link_cmn_vals_entries, + .num_entries = ARRAY_SIZE(link_cmn_vals_entries), + }, + .xcvr_diag_vals_tbl = { + .entries = xcvr_diag_vals_entries, + .num_entries = ARRAY_SIZE(xcvr_diag_vals_entries), + }, + .pcs_cmn_vals_tbl = { + .entries = pcs_cmn_vals_entries, + .num_entries = ARRAY_SIZE(pcs_cmn_vals_entries), + }, + .phy_pma_cmn_vals_tbl = { + .entries = j721e_phy_pma_cmn_vals_entries, + .num_entries = ARRAY_SIZE(j721e_phy_pma_cmn_vals_entries), + }, + .cmn_vals_tbl = { + .entries = ti_j7200_cmn_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_cmn_vals_entries), + }, + .tx_ln_vals_tbl = { + .entries = ti_j7200_tx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_tx_ln_vals_entries), + }, + .rx_ln_vals_tbl = { + .entries = ti_j7200_rx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_rx_ln_vals_entries), + }, +}; + static const struct of_device_id cdns_torrent_phy_of_match[] = { { .compatible = "cdns,torrent-phy", @@ -4855,6 +5261,10 @@ static const struct of_device_id cdns_torrent_phy_of_match[] = { .compatible = "ti,j721e-serdes-10g", .data = &ti_j721e_map_torrent, }, + { + .compatible = "ti,j7200-serdes-10g", + .data = &ti_j7200_map_torrent, + }, {} }; MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match); From a41baa4f0f7d215f4c95a053f593d9b1378963f7 Mon Sep 17 00:00:00 2001 From: Florian Sylvestre Date: Thu, 11 Jan 2024 11:14:50 +0100 Subject: [PATCH 226/814] dt-bindings: phy: add mediatek MIPI CD-PHY module v0.5 This adds the bindings, for the MIPI CD-PHY module v0.5 embedded in some Mediatek soc, such as the mt8365 Signed-off-by: Florian Sylvestre Signed-off-by: Julien Stephan Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240111101504.468169-2-jstephan@baylibre.com Signed-off-by: Vinod Koul --- .../bindings/phy/mediatek,mt8365-csi-rx.yaml | 79 +++++++++++++++++++ MAINTAINERS | 6 ++ 2 files changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml new file mode 100644 index 000000000000..2127a5732f73 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 MediaTek, BayLibre +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/mediatek,mt8365-csi-rx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek Sensor Interface MIPI CSI CD-PHY + +maintainers: + - Julien Stephan + - Andy Hsieh + +description: + The SENINF CD-PHY is a set of CD-PHY connected to the SENINF CSI-2 + receivers. The number of PHYs depends on the SoC model. + Depending on the SoC model, each PHYs can be either CD-PHY or D-PHY only + capable. + +properties: + compatible: + enum: + - mediatek,mt8365-csi-rx + + reg: + maxItems: 1 + + num-lanes: + enum: [2, 3, 4] + + '#phy-cells': + enum: [0, 1] + description: | + If the PHY doesn't support mode selection then #phy-cells must be 0 and + PHY mode is described using phy-type property. + If the PHY supports mode selection, then #phy-cells must be 1 and mode + is set in the PHY cells. Supported modes are: + - PHY_TYPE_DPHY + - PHY_TYPE_CPHY + See include/dt-bindings/phy/phy.h for constants. + + phy-type: + description: + If the PHY doesn't support mode selection then this set the operating mode. + See include/dt-bindings/phy/phy.h for constants. + const: 10 + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + - num-lanes + - '#phy-cells' + +additionalProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + csi0_rx: phy@11c10000 { + compatible = "mediatek,mt8365-csi-rx"; + reg = <0 0x11c10000 0 0x2000>; + num-lanes = <2>; + #phy-cells = <1>; + }; + + csi1_rx: phy@11c12000 { + compatible = "mediatek,mt8365-csi-rx"; + reg = <0 0x11c12000 0 0x2000>; + phy-type = ; + num-lanes = <2>; + #phy-cells = <0>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a69..074182e6ab3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13741,6 +13741,12 @@ F: Documentation/devicetree/bindings/media/mediatek-vpu.txt F: drivers/media/platform/mediatek/vcodec/ F: drivers/media/platform/mediatek/vpu/ +MEDIATEK MIPI-CSI CDPHY DRIVER +M: Julien Stephan +M: Andy Hsieh +S: Supported +F: Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml + MEDIATEK MMC/SD/SDIO DRIVER M: Chaotian Jing S: Maintained From 442f34ede7afd23e0fa1d838790f531d5e59d697 Mon Sep 17 00:00:00 2001 From: Phi-bang Nguyen Date: Thu, 11 Jan 2024 11:17:30 +0100 Subject: [PATCH 227/814] phy: mtk-mipi-csi: add driver for CSI phy This is a new driver that supports the MIPI CSI CD-PHY version 0.5 The number of PHYs depend on the SoC. Each PHY can support D-PHY only or CD-PHY configuration. The driver supports only D-PHY mode, so CD-PHY compatible PHY are configured in D-PHY mode. [Julien Stephan: simplify driver model: one instance per phy vs one instance for all phys] Signed-off-by: Louis Kuo Signed-off-by: Phi-bang Nguyen [Julien Stephan: refactor code] Co-developed-by: Julien Stephan Signed-off-by: Julien Stephan Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240111101738.468916-1-jstephan@baylibre.com Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + drivers/phy/mediatek/Kconfig | 12 + drivers/phy/mediatek/Makefile | 2 + .../mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h | 62 ++++ drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c | 294 ++++++++++++++++++ 5 files changed, 371 insertions(+) create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c diff --git a/MAINTAINERS b/MAINTAINERS index 074182e6ab3a..2214330853ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13746,6 +13746,7 @@ M: Julien Stephan M: Andy Hsieh S: Supported F: Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml +F: drivers/phy/mediatek/phy-mtk-mipi-csi-0-5* MEDIATEK MMC/SD/SDIO DRIVER M: Chaotian Jing diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 3125ecb5d119..3849b7c87d28 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -58,6 +58,18 @@ config PHY_MTK_HDMI help Support HDMI PHY for Mediatek SoCs. +config PHY_MTK_MIPI_CSI_0_5 + tristate "MediaTek MIPI CSI CD-PHY v0.5 Driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Enable this to support the MIPI CSI CD-PHY receiver version 0.5. + The driver supports multiple CSI cdphy ports simultaneously. + + To compile this driver as a module, choose M here: the + module will be called phy-mtk-mipi-csi-0-5. + config PHY_MTK_MIPI_DSI tristate "MediaTek MIPI-DSI Driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index c9a50395533e..f6e24a47e081 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -15,6 +15,8 @@ phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8173.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8195.o obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o +obj-$(CONFIG_PHY_MTK_MIPI_CSI_0_5) += phy-mtk-mipi-csi-0-5.o + phy-mtk-mipi-dsi-drv-y := phy-mtk-mipi-dsi.o phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8173.o phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8183.o diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h new file mode 100644 index 000000000000..97b4c27a1699 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, MediaTek Inc. + * Copyright (c) 2023, BayLibre Inc. + */ + +#ifndef __PHY_MTK_MIPI_CSI_V_0_5_RX_REG_H__ +#define __PHY_MTK_MIPI_CSI_V_0_5_RX_REG_H__ + +/* + * CSI1 and CSI2 are identical, and similar to CSI0. All CSIX macros are + * applicable to the three PHYs. Where differences exist, they are denoted by + * macro names using CSI0 and CSI1, the latter being applicable to CSI1 and + * CSI2 alike. + */ + +#define MIPI_RX_ANA00_CSIXA 0x0000 +#define RG_CSI0A_CPHY_EN BIT(0) +#define RG_CSIXA_EQ_PROTECT_EN BIT(1) +#define RG_CSIXA_BG_LPF_EN BIT(2) +#define RG_CSIXA_BG_CORE_EN BIT(3) +#define RG_CSIXA_DPHY_L0_CKMODE_EN BIT(5) +#define RG_CSIXA_DPHY_L0_CKSEL BIT(6) +#define RG_CSIXA_DPHY_L1_CKMODE_EN BIT(8) +#define RG_CSIXA_DPHY_L1_CKSEL BIT(9) +#define RG_CSIXA_DPHY_L2_CKMODE_EN BIT(11) +#define RG_CSIXA_DPHY_L2_CKSEL BIT(12) + +#define MIPI_RX_ANA18_CSIXA 0x0018 +#define RG_CSI0A_L0_T0AB_EQ_IS GENMASK(5, 4) +#define RG_CSI0A_L0_T0AB_EQ_BW GENMASK(7, 6) +#define RG_CSI0A_L1_T1AB_EQ_IS GENMASK(21, 20) +#define RG_CSI0A_L1_T1AB_EQ_BW GENMASK(23, 22) +#define RG_CSI0A_L2_T1BC_EQ_IS GENMASK(21, 20) +#define RG_CSI0A_L2_T1BC_EQ_BW GENMASK(23, 22) +#define RG_CSI1A_L0_EQ_IS GENMASK(5, 4) +#define RG_CSI1A_L0_EQ_BW GENMASK(7, 6) +#define RG_CSI1A_L1_EQ_IS GENMASK(21, 20) +#define RG_CSI1A_L1_EQ_BW GENMASK(23, 22) +#define RG_CSI1A_L2_EQ_IS GENMASK(5, 4) +#define RG_CSI1A_L2_EQ_BW GENMASK(7, 6) + +#define MIPI_RX_ANA1C_CSIXA 0x001c +#define MIPI_RX_ANA20_CSI0A 0x0020 + +#define MIPI_RX_ANA24_CSIXA 0x0024 +#define RG_CSIXA_RESERVE GENMASK(31, 24) + +#define MIPI_RX_ANA40_CSIXA 0x0040 +#define RG_CSIXA_CPHY_FMCK_SEL GENMASK(1, 0) +#define RG_CSIXA_ASYNC_OPTION GENMASK(7, 4) +#define RG_CSIXA_CPHY_SPARE GENMASK(31, 16) + +#define MIPI_RX_WRAPPER80_CSIXA 0x0080 +#define CSR_CSI_RST_MODE GENMASK(17, 16) + +#define MIPI_RX_ANAA8_CSIXA 0x00a8 +#define RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT BIT(0) +#define RG_CSIXA_DPHY_L1_BYTECK_INVERT BIT(1) +#define RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT BIT(2) + +#endif diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c new file mode 100644 index 000000000000..972c129185f7 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek MIPI CSI v0.5 driver + * + * Copyright (c) 2023, MediaTek Inc. + * Copyright (c) 2023, BayLibre Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-mtk-io.h" +#include "phy-mtk-mipi-csi-0-5-rx-reg.h" + +#define CSIXB_OFFSET 0x1000 + +struct mtk_mipi_cdphy_port { + struct device *dev; + void __iomem *base; + struct phy *phy; + u32 type; + u32 mode; + u32 num_lanes; +}; + +enum PHY_TYPE { + DPHY = 0, + CPHY, + CDPHY, +}; + +static void mtk_phy_csi_cdphy_ana_eq_tune(void __iomem *base) +{ + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); +} + +static void mtk_phy_csi_dphy_ana_eq_tune(void __iomem *base) +{ + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); +} + +static int mtk_mipi_phy_power_on(struct phy *phy) +{ + struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); + void __iomem *base = port->base; + + /* + * The driver currently supports DPHY and CD-PHY phys, + * but the only mode supported is DPHY, + * so CD-PHY capable phys must be configured in DPHY mode + */ + if (port->type == CDPHY) { + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSI0A_CPHY_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSI0A_CPHY_EN, 0); + } + + /* + * Lane configuration: + * + * Only 4 data + 1 clock is supported for now with the following mapping: + * + * CSIXA_LNR0 --> D2 + * CSIXA_LNR1 --> D0 + * CSIXA_LNR2 --> C + * CSIXB_LNR0 --> D1 + * CSIXB_LNR1 --> D3 + */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKMODE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKMODE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKMODE_EN, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L0_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L1_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L2_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); + + /* Byte clock invert */ + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); + + /* Start ANA EQ tuning */ + if (port->type == CDPHY) + mtk_phy_csi_cdphy_ana_eq_tune(base); + else + mtk_phy_csi_dphy_ana_eq_tune(base); + + /* End ANA EQ tuning */ + mtk_phy_set_bits(base + MIPI_RX_ANA40_CSIXA, 0x90); + + mtk_phy_update_field(base + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); + mtk_phy_update_field(base + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); + /* ANA power on */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); + usleep_range(20, 40); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); + + return 0; +} + +static int mtk_mipi_phy_power_off(struct phy *phy) +{ + struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); + void __iomem *base = port->base; + + /* Disable MIPI BG. */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); + + return 0; +} + +static struct phy *mtk_mipi_cdphy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct mtk_mipi_cdphy_port *priv = dev_get_drvdata(dev); + + /* + * If PHY is CD-PHY then we need to get the operating mode + * For now only D-PHY mode is supported + */ + if (priv->type == CDPHY) { + if (args->args_count != 1) { + dev_err(dev, "invalid number of arguments\n"); + return ERR_PTR(-EINVAL); + } + switch (args->args[0]) { + case PHY_TYPE_DPHY: + priv->mode = DPHY; + if (priv->num_lanes != 4) { + dev_err(dev, "Only 4D1C mode is supported for now!\n"); + return ERR_PTR(-EINVAL); + } + break; + default: + dev_err(dev, "Unsupported PHY type: %i\n", args->args[0]); + return ERR_PTR(-EINVAL); + } + } else { + if (args->args_count) { + dev_err(dev, "invalid number of arguments\n"); + return ERR_PTR(-EINVAL); + } + priv->mode = DPHY; + } + + return priv->phy; +} + +static const struct phy_ops mtk_cdphy_ops = { + .power_on = mtk_mipi_phy_power_on, + .power_off = mtk_mipi_phy_power_off, + .owner = THIS_MODULE, +}; + +static int mtk_mipi_cdphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct mtk_mipi_cdphy_port *port; + struct phy *phy; + int ret; + u32 phy_type; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + dev_set_drvdata(dev, port); + + port->dev = dev; + + port->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + + ret = of_property_read_u32(dev->of_node, "num-lanes", &port->num_lanes); + if (ret) { + dev_err(dev, "Failed to read num-lanes property: %i\n", ret); + return ret; + } + + /* + * phy-type is optional, if not present, PHY is considered to be CD-PHY + */ + if (device_property_present(dev, "phy-type")) { + ret = of_property_read_u32(dev->of_node, "phy-type", &phy_type); + if (ret) { + dev_err(dev, "Failed to read phy-type property: %i\n", ret); + return ret; + } + switch (phy_type) { + case PHY_TYPE_DPHY: + port->type = DPHY; + break; + default: + dev_err(dev, "Unsupported PHY type: %i\n", phy_type); + return -EINVAL; + } + } else { + port->type = CDPHY; + } + + phy = devm_phy_create(dev, NULL, &mtk_cdphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create PHY: %ld\n", PTR_ERR(phy)); + return PTR_ERR(phy); + } + + port->phy = phy; + phy_set_drvdata(phy, port); + + phy_provider = devm_of_phy_provider_register(dev, mtk_mipi_cdphy_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "Failed to register PHY provider: %ld\n", + PTR_ERR(phy_provider)); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static const struct of_device_id mtk_mipi_cdphy_of_match[] = { + { .compatible = "mediatek,mt8365-csi-rx" }, + { /* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, mtk_mipi_cdphy_of_match); + +static struct platform_driver mipi_cdphy_pdrv = { + .probe = mtk_mipi_cdphy_probe, + .driver = { + .name = "mtk-mipi-csi-0-5", + .of_match_table = mtk_mipi_cdphy_of_match, + }, +}; +module_platform_driver(mipi_cdphy_pdrv); + +MODULE_DESCRIPTION("MediaTek MIPI CSI CD-PHY v0.5 Driver"); +MODULE_AUTHOR("Louis Kuo "); +MODULE_LICENSE("GPL"); From bc25f0b57133ae6157c98e38f0eea7de6dc2a114 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Thu, 25 Jan 2024 18:17:54 +0100 Subject: [PATCH 228/814] phy: ti: gmii-sel: add resume support The resume callback restores the submode of each PHY. It uses the submode stored in struct phy_gmii_sel_phy_priv (variable phy_if_mode). The submode was saved by the set_mode PHY operation. Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20240125171754.773909-1-thomas.richard@bootlin.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-gmii-sel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 0f4818adb440..81dd1c3449d9 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -494,11 +494,35 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) return 0; } +static int phy_gmii_sel_resume_noirq(struct device *dev) +{ + struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); + struct phy_gmii_sel_phy_priv *if_phys = priv->if_phys; + int ret, i; + + for (i = 0; i < priv->num_ports; i++) { + if (if_phys[i].phy_if_mode) { + ret = phy_gmii_sel_mode(if_phys[i].if_phy, + PHY_MODE_ETHERNET, if_phys[i].phy_if_mode); + if (ret) { + dev_err(dev, "port%u: restore mode fail %d\n", + if_phys[i].if_phy->id, ret); + return ret; + } + } + } + + return 0; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(phy_gmii_sel_pm_ops, NULL, phy_gmii_sel_resume_noirq); + static struct platform_driver phy_gmii_sel_driver = { .probe = phy_gmii_sel_probe, .driver = { .name = "phy-gmii-sel", .of_match_table = phy_gmii_sel_id_table, + .pm = pm_sleep_ptr(&phy_gmii_sel_pm_ops), }, }; module_platform_driver(phy_gmii_sel_driver); From d7f0a00e438d2275d398536d78aab4097a3aa25e Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 29 Dec 2023 10:26:52 +0800 Subject: [PATCH 229/814] KVM: VMX: Report up-to-date exit qualification to userspace Use vmx_get_exit_qual() to read the exit qualification. vcpu->arch.exit_qualification is cached for EPT violation only and even for EPT violation, it is stale at this point because the up-to-date value is cached later in handle_ept_violation(). Fixes: 70bcd708dfd1 ("KVM: vmx: expose more information for KVM_INTERNAL_ERROR_DELIVERY_EV exits") Signed-off-by: Chao Gao Link: https://lore.kernel.org/r/20231229022652.300095-1-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e262bc2ba4e5..d4e6625e0a9a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6509,7 +6509,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV; vcpu->run->internal.data[0] = vectoring_info; vcpu->run->internal.data[1] = exit_reason.full; - vcpu->run->internal.data[2] = vcpu->arch.exit_qualification; + vcpu->run->internal.data[2] = vmx_get_exit_qual(vcpu); if (exit_reason.basic == EXIT_REASON_EPT_MISCONFIG) { vcpu->run->internal.data[ndata++] = vmcs_read64(GUEST_PHYSICAL_ADDRESS); From 03f6298c7cf6d2c1ccd0961ab9b340502d63840a Mon Sep 17 00:00:00 2001 From: Thomas Prescher Date: Tue, 12 Dec 2023 10:59:37 +0100 Subject: [PATCH 230/814] KVM: x86/emulator: emulate movbe with operand-size prefix The MOVBE instruction can come with an operand-size prefix (66h). In this, case the x86 emulation code returns EMULATION_FAILED. It turns out that em_movbe can already handle this case and all that is missing is an entry in respective opcode tables to populate gprefix->pfx_66. Signed-off-by: Thomas Prescher Signed-off-by: Julian Stecklina Acked-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20231212095938.26731-1-julian.stecklina@cyberus-technology.de Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e223043ef5b2..c75924f4f737 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4505,11 +4505,11 @@ static const struct instr_dual instr_dual_0f_38_f1 = { }; static const struct gprefix three_byte_0f_38_f0 = { - ID(0, &instr_dual_0f_38_f0), N, N, N + ID(0, &instr_dual_0f_38_f0), ID(0, &instr_dual_0f_38_f0), N, N }; static const struct gprefix three_byte_0f_38_f1 = { - ID(0, &instr_dual_0f_38_f1), N, N, N + ID(0, &instr_dual_0f_38_f1), ID(0, &instr_dual_0f_38_f1), N, N }; /* From 6fd1e3963f20e850d7b3c89485e58d1ae79c309a Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Mon, 9 Oct 2023 11:20:53 +0200 Subject: [PATCH 231/814] KVM: x86: Clean up partially uninitialized integer in emulate_pop() Explicitly zero out variables passed to emulate_pop() as output params to harden against consuming uninitialized data, and to make sanitizers happy. Many flows that use emulate_pop() pass an "unsigned long" so as to be able to hold the largest possible operand, but the actual number of bytes written is usually the word with of the vCPU. E.g. if the vCPU is in 16-bit or 32-bit mode (on a 64-bit host), the upper portion of the output param will be uninitialized. Passing around the uninitialized data is benign, as actual KVM usage of the output is also tied to the word width, but passing around uninitialized data makes some sanitizers rightly complain. Note, initializing the data in emulate_pop() is not a safe alternative, e.g. it would result in em_leave() clobbering RBP[31:16] if LEAVE were emulated with a 16-bit stack. Signed-off-by: Julian Stecklina Link: https://lore.kernel.org/r/20231009092054.556935-1-julian.stecklina@cyberus-technology.de [sean: massage changelog, drop em_popa() variable size change]] Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c75924f4f737..711b3250ebaa 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1863,7 +1863,8 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt, void *dest, int len) { int rc; - unsigned long val, change_mask; + unsigned long val = 0; + unsigned long change_mask; int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> X86_EFLAGS_IOPL_BIT; int cpl = ctxt->ops->cpl(ctxt); @@ -1954,7 +1955,7 @@ static int em_push_sreg(struct x86_emulate_ctxt *ctxt) static int em_pop_sreg(struct x86_emulate_ctxt *ctxt) { int seg = ctxt->src2.val; - unsigned long selector; + unsigned long selector = 0; int rc; rc = emulate_pop(ctxt, &selector, 2); @@ -2000,7 +2001,7 @@ static int em_popa(struct x86_emulate_ctxt *ctxt) { int rc = X86EMUL_CONTINUE; int reg = VCPU_REGS_RDI; - u32 val; + u32 val = 0; while (reg >= VCPU_REGS_RAX) { if (reg == VCPU_REGS_RSP) { @@ -2229,7 +2230,7 @@ static int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt) static int em_ret(struct x86_emulate_ctxt *ctxt) { int rc; - unsigned long eip; + unsigned long eip = 0; rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) @@ -2241,7 +2242,8 @@ static int em_ret(struct x86_emulate_ctxt *ctxt) static int em_ret_far(struct x86_emulate_ctxt *ctxt) { int rc; - unsigned long eip, cs; + unsigned long eip = 0; + unsigned long cs = 0; int cpl = ctxt->ops->cpl(ctxt); struct desc_struct new_desc; @@ -3184,7 +3186,7 @@ fail: static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) { int rc; - unsigned long eip; + unsigned long eip = 0; rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) From 64435aaa4a6aca019fabca7df45e0782d98a477b Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Mon, 9 Oct 2023 11:20:54 +0200 Subject: [PATCH 232/814] KVM: x86: rename push to emulate_push for consistency push and emulate_pop are counterparts. Rename push to emulate_push and harmonize its function signature with emulate_pop. This should remove a bit of cognitive load when reading this code. Signed-off-by: Julian Stecklina Link: https://lore.kernel.org/r/20231009092054.556935-2-julian.stecklina@cyberus-technology.de Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 711b3250ebaa..eafb48f0b745 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1820,22 +1820,22 @@ static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op) return X86EMUL_CONTINUE; } -static int push(struct x86_emulate_ctxt *ctxt, void *data, int bytes) +static int emulate_push(struct x86_emulate_ctxt *ctxt, const void *data, int len) { struct segmented_address addr; - rsp_increment(ctxt, -bytes); + rsp_increment(ctxt, -len); addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt); addr.seg = VCPU_SREG_SS; - return segmented_write(ctxt, addr, data, bytes); + return segmented_write(ctxt, addr, data, len); } static int em_push(struct x86_emulate_ctxt *ctxt) { /* Disable writeback. */ ctxt->dst.type = OP_NONE; - return push(ctxt, &ctxt->src.val, ctxt->op_bytes); + return emulate_push(ctxt, &ctxt->src.val, ctxt->op_bytes); } static int emulate_pop(struct x86_emulate_ctxt *ctxt, @@ -1921,7 +1921,7 @@ static int em_enter(struct x86_emulate_ctxt *ctxt) return X86EMUL_UNHANDLEABLE; rbp = reg_read(ctxt, VCPU_REGS_RBP); - rc = push(ctxt, &rbp, stack_size(ctxt)); + rc = emulate_push(ctxt, &rbp, stack_size(ctxt)); if (rc != X86EMUL_CONTINUE) return rc; assign_masked(reg_rmw(ctxt, VCPU_REGS_RBP), reg_read(ctxt, VCPU_REGS_RSP), From 3c7a8e190bc580813ddd9259f62971c8d2a6b5ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 12 Dec 2023 11:15:28 -0500 Subject: [PATCH 233/814] uapi: introduce uapi-friendly macros for GENMASK Move __GENMASK and __GENMASK_ULL from include/ to include/uapi/ so that they can be used to define masks in userspace API headers. Compared to what is already in include/linux/bits.h, the definitions need to use the uglified versions of UL(), ULL(), BITS_PER_LONG and BITS_PER_LONG_LONG (which did not even exist), but otherwise expand to the same content. Signed-off-by: Paolo Bonzini --- include/linux/bits.h | 8 +------- include/uapi/asm-generic/bitsperlong.h | 4 ++++ include/uapi/linux/bits.h | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 include/uapi/linux/bits.h diff --git a/include/linux/bits.h b/include/linux/bits.h index 7c0cf5031abe..0eb24d21aac2 100644 --- a/include/linux/bits.h +++ b/include/linux/bits.h @@ -4,6 +4,7 @@ #include #include +#include #include #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) @@ -30,15 +31,8 @@ #define GENMASK_INPUT_CHECK(h, l) 0 #endif -#define __GENMASK(h, l) \ - (((~UL(0)) - (UL(1) << (l)) + 1) & \ - (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK(h, l) \ (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l)) - -#define __GENMASK_ULL(h, l) \ - (((~ULL(0)) - (ULL(1) << (l)) + 1) & \ - (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h)))) #define GENMASK_ULL(h, l) \ (GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l)) diff --git a/include/uapi/asm-generic/bitsperlong.h b/include/uapi/asm-generic/bitsperlong.h index 352cb81947b8..fadb3f857f28 100644 --- a/include/uapi/asm-generic/bitsperlong.h +++ b/include/uapi/asm-generic/bitsperlong.h @@ -24,4 +24,8 @@ #endif #endif +#ifndef __BITS_PER_LONG_LONG +#define __BITS_PER_LONG_LONG 64 +#endif + #endif /* _UAPI__ASM_GENERIC_BITS_PER_LONG */ diff --git a/include/uapi/linux/bits.h b/include/uapi/linux/bits.h new file mode 100644 index 000000000000..3c2a101986a3 --- /dev/null +++ b/include/uapi/linux/bits.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* bits.h: Macros for dealing with bitmasks. */ + +#ifndef _UAPI_LINUX_BITS_H +#define _UAPI_LINUX_BITS_H + +#define __GENMASK(h, l) \ + (((~_UL(0)) - (_UL(1) << (l)) + 1) & \ + (~_UL(0) >> (__BITS_PER_LONG - 1 - (h)))) + +#define __GENMASK_ULL(h, l) \ + (((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \ + (~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h)))) + +#endif /* _UAPI_LINUX_BITS_H */ From 882dd4aee36bcf4e734b9c7fb5c17b387d71241d Mon Sep 17 00:00:00 2001 From: Dionna Glaze Date: Thu, 7 Dec 2023 00:11:32 +0000 Subject: [PATCH 234/814] kvm: x86: use a uapi-friendly macro for BIT Change uapi header uses of BIT to instead use the uapi/linux/const.h bit macros, since BIT is not defined in uapi headers. The PMU mask uses _BITUL since it targets a 32 bit flag field, whereas the longmode definition is meant for a 64 bit flag field. Cc: Sean Christophersen Cc: Paolo Bonzini Signed-off-by: Dionna Glaze Message-Id: <20231207001142.3617856-1-dionnaglaze@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/uapi/asm/kvm.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index a448d0964fc0..9ae91a21ffea 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -7,6 +7,7 @@ * */ +#include #include #include #include @@ -526,7 +527,7 @@ struct kvm_pmu_event_filter { #define KVM_PMU_EVENT_ALLOW 0 #define KVM_PMU_EVENT_DENY 1 -#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS BIT(0) +#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS _BITUL(0) #define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS) /* @@ -552,7 +553,7 @@ struct kvm_pmu_event_filter { (GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32)) #define KVM_PMU_MASKED_ENTRY_UMASK_MASK (GENMASK_ULL(63, 56)) #define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (GENMASK_ULL(15, 8)) -#define KVM_PMU_MASKED_ENTRY_EXCLUDE (BIT_ULL(55)) +#define KVM_PMU_MASKED_ENTRY_EXCLUDE (_BITULL(55)) #define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT (56) /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ @@ -560,7 +561,7 @@ struct kvm_pmu_event_filter { #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ /* x86-specific KVM_EXIT_HYPERCALL flags. */ -#define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0) +#define KVM_EXIT_HYPERCALL_LONG_MODE _BITULL(0) #define KVM_X86_DEFAULT_VM 0 #define KVM_X86_SW_PROTECTED_VM 1 From 458822416a88c66455eec884649eee12bdc53cb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 12 Dec 2023 11:26:53 -0500 Subject: [PATCH 235/814] kvm: x86: use a uapi-friendly macro for GENMASK Change uapi header uses of GENMASK to instead use the uapi/linux/bits.h bit macros, since GENMASK is not defined in uapi headers. Signed-off-by: Paolo Bonzini --- arch/arm64/include/uapi/asm/kvm.h | 8 ++++---- arch/x86/include/uapi/asm/kvm.h | 7 ++++--- arch/x86/include/uapi/asm/kvm_para.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 89d2fc872d9f..6b8b57b97228 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -76,11 +76,11 @@ struct kvm_regs { /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ #define KVM_ARM_DEVICE_TYPE_SHIFT 0 -#define KVM_ARM_DEVICE_TYPE_MASK GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \ - KVM_ARM_DEVICE_TYPE_SHIFT) +#define KVM_ARM_DEVICE_TYPE_MASK __GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \ + KVM_ARM_DEVICE_TYPE_SHIFT) #define KVM_ARM_DEVICE_ID_SHIFT 16 -#define KVM_ARM_DEVICE_ID_MASK GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \ - KVM_ARM_DEVICE_ID_SHIFT) +#define KVM_ARM_DEVICE_ID_MASK __GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \ + KVM_ARM_DEVICE_ID_SHIFT) /* Supported device IDs */ #define KVM_ARM_DEVICE_VGIC_V2 0 diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 9ae91a21ffea..bd36d74b593b 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -550,9 +551,9 @@ struct kvm_pmu_event_filter { ((__u64)(!!(exclude)) << 55)) #define KVM_PMU_MASKED_ENTRY_EVENT_SELECT \ - (GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32)) -#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (GENMASK_ULL(63, 56)) -#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (GENMASK_ULL(15, 8)) + (__GENMASK_ULL(7, 0) | __GENMASK_ULL(35, 32)) +#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (__GENMASK_ULL(63, 56)) +#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (__GENMASK_ULL(15, 8)) #define KVM_PMU_MASKED_ENTRY_EXCLUDE (_BITULL(55)) #define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT (56) diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h index 6e64b27b2c1e..6bc3456a8ebf 100644 --- a/arch/x86/include/uapi/asm/kvm_para.h +++ b/arch/x86/include/uapi/asm/kvm_para.h @@ -92,7 +92,7 @@ struct kvm_clock_pairing { #define KVM_ASYNC_PF_DELIVERY_AS_INT (1 << 3) /* MSR_KVM_ASYNC_PF_INT */ -#define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0) +#define KVM_ASYNC_PF_VEC_MASK __GENMASK(7, 0) /* MSR_KVM_MIGRATION_CONTROL */ #define KVM_MIGRATION_READY (1 << 0) From c0a411904e1548d287dc4a031ff19d00e0569202 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Jan 2024 18:20:47 -0500 Subject: [PATCH 236/814] KVM: remove more traces of device assignment UAPI Signed-off-by: Paolo Bonzini --- include/uapi/linux/kvm.h | 50 ---------------------------------------- 1 file changed, 50 deletions(-) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index c3308536482b..e107ea953585 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1965,56 +1965,6 @@ struct kvm_sev_receive_update_data { __u32 trans_len; }; -#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) -#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) -#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) - -struct kvm_assigned_pci_dev { - __u32 assigned_dev_id; - __u32 busnr; - __u32 devfn; - __u32 flags; - __u32 segnr; - union { - __u32 reserved[11]; - }; -}; - -#define KVM_DEV_IRQ_HOST_INTX (1 << 0) -#define KVM_DEV_IRQ_HOST_MSI (1 << 1) -#define KVM_DEV_IRQ_HOST_MSIX (1 << 2) - -#define KVM_DEV_IRQ_GUEST_INTX (1 << 8) -#define KVM_DEV_IRQ_GUEST_MSI (1 << 9) -#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10) - -#define KVM_DEV_IRQ_HOST_MASK 0x00ff -#define KVM_DEV_IRQ_GUEST_MASK 0xff00 - -struct kvm_assigned_irq { - __u32 assigned_dev_id; - __u32 host_irq; /* ignored (legacy field) */ - __u32 guest_irq; - __u32 flags; - union { - __u32 reserved[12]; - }; -}; - -struct kvm_assigned_msix_nr { - __u32 assigned_dev_id; - __u16 entry_nr; - __u16 padding; -}; - -#define KVM_MAX_MSIX_PER_DEV 256 -struct kvm_assigned_msix_entry { - __u32 assigned_dev_id; - __u32 gsi; - __u16 entry; /* The index of entry in the MSI-X table */ - __u16 padding[3]; -}; - #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) From bcac0477277e44b0b4b5c93b24159d86eeff566a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:19:08 -0500 Subject: [PATCH 237/814] KVM: x86: move x86-specific structs to uapi/asm/kvm.h Several capabilities that exist only on x86 nevertheless have their structs defined in include/uapi/linux/kvm.h. Move them to arch/x86/include/uapi/asm/kvm.h for cleanliness. Signed-off-by: Paolo Bonzini --- arch/x86/include/uapi/asm/kvm.h | 262 +++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 265 -------------------------------- 2 files changed, 262 insertions(+), 265 deletions(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index bd36d74b593b..bf68e56fd484 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -531,6 +531,268 @@ struct kvm_pmu_event_filter { #define KVM_PMU_EVENT_FLAG_MASKED_EVENTS _BITUL(0) #define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS) +/* for KVM_CAP_MCE */ +struct kvm_x86_mce { + __u64 status; + __u64 addr; + __u64 misc; + __u64 mcg_status; + __u8 bank; + __u8 pad1[7]; + __u64 pad2[3]; +}; + +/* for KVM_CAP_XEN_HVM */ +#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0) +#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1) +#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) +#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) +#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) +#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) +#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) +#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7) + +struct kvm_xen_hvm_config { + __u32 flags; + __u32 msr; + __u64 blob_addr_32; + __u64 blob_addr_64; + __u8 blob_size_32; + __u8 blob_size_64; + __u8 pad2[30]; +}; + +struct kvm_xen_hvm_attr { + __u16 type; + __u16 pad[3]; + union { + __u8 long_mode; + __u8 vector; + __u8 runstate_update_flag; + struct { + __u64 gfn; +#define KVM_XEN_INVALID_GFN ((__u64)-1) + } shared_info; + struct { + __u32 send_port; + __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */ + __u32 flags; +#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0) +#define KVM_XEN_EVTCHN_UPDATE (1 << 1) +#define KVM_XEN_EVTCHN_RESET (1 << 2) + /* + * Events sent by the guest are either looped back to + * the guest itself (potentially on a different port#) + * or signalled via an eventfd. + */ + union { + struct { + __u32 port; + __u32 vcpu; + __u32 priority; + } port; + struct { + __u32 port; /* Zero for eventfd */ + __s32 fd; + } eventfd; + __u32 padding[4]; + } deliver; + } evtchn; + __u32 xen_version; + __u64 pad[8]; + } u; +}; + + +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ +#define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0 +#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1 +#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3 +#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */ +#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5 + +struct kvm_xen_vcpu_attr { + __u16 type; + __u16 pad[3]; + union { + __u64 gpa; +#define KVM_XEN_INVALID_GPA ((__u64)-1) + __u64 pad[8]; + struct { + __u64 state; + __u64 state_entry_time; + __u64 time_running; + __u64 time_runnable; + __u64 time_blocked; + __u64 time_offline; + } runstate; + __u32 vcpu_id; + struct { + __u32 port; + __u32 priority; + __u64 expires_ns; + } timer; + __u8 vector; + } u; +}; + +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0 +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6 +#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7 +#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8 + +/* Secure Encrypted Virtualization command */ +enum sev_cmd_id { + /* Guest initialization commands */ + KVM_SEV_INIT = 0, + KVM_SEV_ES_INIT, + /* Guest launch commands */ + KVM_SEV_LAUNCH_START, + KVM_SEV_LAUNCH_UPDATE_DATA, + KVM_SEV_LAUNCH_UPDATE_VMSA, + KVM_SEV_LAUNCH_SECRET, + KVM_SEV_LAUNCH_MEASURE, + KVM_SEV_LAUNCH_FINISH, + /* Guest migration commands (outgoing) */ + KVM_SEV_SEND_START, + KVM_SEV_SEND_UPDATE_DATA, + KVM_SEV_SEND_UPDATE_VMSA, + KVM_SEV_SEND_FINISH, + /* Guest migration commands (incoming) */ + KVM_SEV_RECEIVE_START, + KVM_SEV_RECEIVE_UPDATE_DATA, + KVM_SEV_RECEIVE_UPDATE_VMSA, + KVM_SEV_RECEIVE_FINISH, + /* Guest status and debug commands */ + KVM_SEV_GUEST_STATUS, + KVM_SEV_DBG_DECRYPT, + KVM_SEV_DBG_ENCRYPT, + /* Guest certificates commands */ + KVM_SEV_CERT_EXPORT, + /* Attestation report */ + KVM_SEV_GET_ATTESTATION_REPORT, + /* Guest Migration Extension */ + KVM_SEV_SEND_CANCEL, + + KVM_SEV_NR_MAX, +}; + +struct kvm_sev_cmd { + __u32 id; + __u64 data; + __u32 error; + __u32 sev_fd; +}; + +struct kvm_sev_launch_start { + __u32 handle; + __u32 policy; + __u64 dh_uaddr; + __u32 dh_len; + __u64 session_uaddr; + __u32 session_len; +}; + +struct kvm_sev_launch_update_data { + __u64 uaddr; + __u32 len; +}; + + +struct kvm_sev_launch_secret { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 guest_uaddr; + __u32 guest_len; + __u64 trans_uaddr; + __u32 trans_len; +}; + +struct kvm_sev_launch_measure { + __u64 uaddr; + __u32 len; +}; + +struct kvm_sev_guest_status { + __u32 handle; + __u32 policy; + __u32 state; +}; + +struct kvm_sev_dbg { + __u64 src_uaddr; + __u64 dst_uaddr; + __u32 len; +}; + +struct kvm_sev_attestation_report { + __u8 mnonce[16]; + __u64 uaddr; + __u32 len; +}; + +struct kvm_sev_send_start { + __u32 policy; + __u64 pdh_cert_uaddr; + __u32 pdh_cert_len; + __u64 plat_certs_uaddr; + __u32 plat_certs_len; + __u64 amd_certs_uaddr; + __u32 amd_certs_len; + __u64 session_uaddr; + __u32 session_len; +}; + +struct kvm_sev_send_update_data { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 guest_uaddr; + __u32 guest_len; + __u64 trans_uaddr; + __u32 trans_len; +}; + +struct kvm_sev_receive_start { + __u32 handle; + __u32 policy; + __u64 pdh_uaddr; + __u32 pdh_len; + __u64 session_uaddr; + __u32 session_len; +}; + +struct kvm_sev_receive_update_data { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 guest_uaddr; + __u32 guest_len; + __u64 trans_uaddr; + __u32 trans_len; +}; + +#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) +#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) + +struct kvm_hyperv_eventfd { + __u32 conn_id; + __s32 fd; + __u32 flags; + __u32 padding[3]; +}; + +#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff +#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0) + /* * Masked event layout. * Bits Description diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index e107ea953585..9744e1891c16 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1224,40 +1224,6 @@ struct kvm_irq_routing { #endif -#ifdef KVM_CAP_MCE -/* x86 MCE */ -struct kvm_x86_mce { - __u64 status; - __u64 addr; - __u64 misc; - __u64 mcg_status; - __u8 bank; - __u8 pad1[7]; - __u64 pad2[3]; -}; -#endif - -#ifdef KVM_CAP_XEN_HVM -#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0) -#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1) -#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) -#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) -#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) -#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) -#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) -#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7) - -struct kvm_xen_hvm_config { - __u32 flags; - __u32 msr; - __u64 blob_addr_32; - __u64 blob_addr_64; - __u8 blob_size_32; - __u8 blob_size_64; - __u8 pad2[30]; -}; -#endif - #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0) /* * Available with KVM_CAP_IRQFD_RESAMPLE @@ -1737,58 +1703,6 @@ struct kvm_pv_cmd { #define KVM_XEN_HVM_GET_ATTR _IOWR(KVMIO, 0xc8, struct kvm_xen_hvm_attr) #define KVM_XEN_HVM_SET_ATTR _IOW(KVMIO, 0xc9, struct kvm_xen_hvm_attr) -struct kvm_xen_hvm_attr { - __u16 type; - __u16 pad[3]; - union { - __u8 long_mode; - __u8 vector; - __u8 runstate_update_flag; - struct { - __u64 gfn; -#define KVM_XEN_INVALID_GFN ((__u64)-1) - } shared_info; - struct { - __u32 send_port; - __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */ - __u32 flags; -#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0) -#define KVM_XEN_EVTCHN_UPDATE (1 << 1) -#define KVM_XEN_EVTCHN_RESET (1 << 2) - /* - * Events sent by the guest are either looped back to - * the guest itself (potentially on a different port#) - * or signalled via an eventfd. - */ - union { - struct { - __u32 port; - __u32 vcpu; - __u32 priority; - } port; - struct { - __u32 port; /* Zero for eventfd */ - __s32 fd; - } eventfd; - __u32 padding[4]; - } deliver; - } evtchn; - __u32 xen_version; - __u64 pad[8]; - } u; -}; - - -/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ -#define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0 -#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1 -#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2 -/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ -#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3 -#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 -/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */ -#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5 - /* Per-vCPU Xen attributes */ #define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr) #define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr) @@ -1799,175 +1713,6 @@ struct kvm_xen_hvm_attr { #define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) #define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2) -struct kvm_xen_vcpu_attr { - __u16 type; - __u16 pad[3]; - union { - __u64 gpa; -#define KVM_XEN_INVALID_GPA ((__u64)-1) - __u64 pad[8]; - struct { - __u64 state; - __u64 state_entry_time; - __u64 time_running; - __u64 time_runnable; - __u64 time_blocked; - __u64 time_offline; - } runstate; - __u32 vcpu_id; - struct { - __u32 port; - __u32 priority; - __u64 expires_ns; - } timer; - __u8 vector; - } u; -}; - -/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ -#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0 -#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1 -#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2 -#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3 -#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4 -#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5 -/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ -#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6 -#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7 -#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8 - -/* Secure Encrypted Virtualization command */ -enum sev_cmd_id { - /* Guest initialization commands */ - KVM_SEV_INIT = 0, - KVM_SEV_ES_INIT, - /* Guest launch commands */ - KVM_SEV_LAUNCH_START, - KVM_SEV_LAUNCH_UPDATE_DATA, - KVM_SEV_LAUNCH_UPDATE_VMSA, - KVM_SEV_LAUNCH_SECRET, - KVM_SEV_LAUNCH_MEASURE, - KVM_SEV_LAUNCH_FINISH, - /* Guest migration commands (outgoing) */ - KVM_SEV_SEND_START, - KVM_SEV_SEND_UPDATE_DATA, - KVM_SEV_SEND_UPDATE_VMSA, - KVM_SEV_SEND_FINISH, - /* Guest migration commands (incoming) */ - KVM_SEV_RECEIVE_START, - KVM_SEV_RECEIVE_UPDATE_DATA, - KVM_SEV_RECEIVE_UPDATE_VMSA, - KVM_SEV_RECEIVE_FINISH, - /* Guest status and debug commands */ - KVM_SEV_GUEST_STATUS, - KVM_SEV_DBG_DECRYPT, - KVM_SEV_DBG_ENCRYPT, - /* Guest certificates commands */ - KVM_SEV_CERT_EXPORT, - /* Attestation report */ - KVM_SEV_GET_ATTESTATION_REPORT, - /* Guest Migration Extension */ - KVM_SEV_SEND_CANCEL, - - KVM_SEV_NR_MAX, -}; - -struct kvm_sev_cmd { - __u32 id; - __u64 data; - __u32 error; - __u32 sev_fd; -}; - -struct kvm_sev_launch_start { - __u32 handle; - __u32 policy; - __u64 dh_uaddr; - __u32 dh_len; - __u64 session_uaddr; - __u32 session_len; -}; - -struct kvm_sev_launch_update_data { - __u64 uaddr; - __u32 len; -}; - - -struct kvm_sev_launch_secret { - __u64 hdr_uaddr; - __u32 hdr_len; - __u64 guest_uaddr; - __u32 guest_len; - __u64 trans_uaddr; - __u32 trans_len; -}; - -struct kvm_sev_launch_measure { - __u64 uaddr; - __u32 len; -}; - -struct kvm_sev_guest_status { - __u32 handle; - __u32 policy; - __u32 state; -}; - -struct kvm_sev_dbg { - __u64 src_uaddr; - __u64 dst_uaddr; - __u32 len; -}; - -struct kvm_sev_attestation_report { - __u8 mnonce[16]; - __u64 uaddr; - __u32 len; -}; - -struct kvm_sev_send_start { - __u32 policy; - __u64 pdh_cert_uaddr; - __u32 pdh_cert_len; - __u64 plat_certs_uaddr; - __u32 plat_certs_len; - __u64 amd_certs_uaddr; - __u32 amd_certs_len; - __u64 session_uaddr; - __u32 session_len; -}; - -struct kvm_sev_send_update_data { - __u64 hdr_uaddr; - __u32 hdr_len; - __u64 guest_uaddr; - __u32 guest_len; - __u64 trans_uaddr; - __u32 trans_len; -}; - -struct kvm_sev_receive_start { - __u32 handle; - __u32 policy; - __u64 pdh_uaddr; - __u32 pdh_len; - __u64 session_uaddr; - __u32 session_len; -}; - -struct kvm_sev_receive_update_data { - __u64 hdr_uaddr; - __u32 hdr_len; - __u64 guest_uaddr; - __u32 guest_len; - __u64 trans_uaddr; - __u32 trans_len; -}; - -#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) -#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) - /* Available with KVM_CAP_ARM_USER_IRQ */ /* Bits for run->s.regs.device_irq_level */ @@ -1975,16 +1720,6 @@ struct kvm_sev_receive_update_data { #define KVM_ARM_DEV_EL1_PTIMER (1 << 1) #define KVM_ARM_DEV_PMU (1 << 2) -struct kvm_hyperv_eventfd { - __u32 conn_id; - __s32 fd; - __u32 flags; - __u32 padding[3]; -}; - -#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff -#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0) - #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) #define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1) From d750951c9ed78804d775784af9f159354d9804d4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:19:08 -0500 Subject: [PATCH 238/814] KVM: powerpc: move powerpc-specific structs to uapi/asm/kvm.h While this in principle breaks the appearance of KVM_PPC_* ioctls on architectures other than powerpc, this seems unlikely to be a problem considering that there are already many "struct kvm_ppc_*" definitions in arch/powerpc/include/uapi. Signed-off-by: Paolo Bonzini --- arch/powerpc/include/uapi/asm/kvm.h | 44 +++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 44 ----------------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 9f18fa090f1f..a96ef6b36bba 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -733,4 +733,48 @@ struct kvm_ppc_xive_eq { #define KVM_XIVE_TIMA_PAGE_OFFSET 0 #define KVM_XIVE_ESB_PAGE_OFFSET 4 +/* for KVM_PPC_GET_PVINFO */ + +#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0) + +struct kvm_ppc_pvinfo { + /* out */ + __u32 flags; + __u32 hcall[4]; + __u8 pad[108]; +}; + +/* for KVM_PPC_GET_SMMU_INFO */ +#define KVM_PPC_PAGE_SIZES_MAX_SZ 8 + +struct kvm_ppc_one_page_size { + __u32 page_shift; /* Page shift (or 0) */ + __u32 pte_enc; /* Encoding in the HPTE (>>12) */ +}; + +struct kvm_ppc_one_seg_page_size { + __u32 page_shift; /* Base page shift of segment (or 0) */ + __u32 slb_enc; /* SLB encoding for BookS */ + struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ]; +}; + +#define KVM_PPC_PAGE_SIZES_REAL 0x00000001 +#define KVM_PPC_1T_SEGMENTS 0x00000002 +#define KVM_PPC_NO_HASH 0x00000004 + +struct kvm_ppc_smmu_info { + __u64 flags; + __u32 slb_size; + __u16 data_keys; /* # storage keys supported for data */ + __u16 instr_keys; /* # storage keys supported for instructions */ + struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; +}; + +/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */ +struct kvm_ppc_resize_hpt { + __u64 flags; + __u32 shift; + __u32 pad; +}; + #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 9744e1891c16..a5458aeee018 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -810,50 +810,6 @@ struct kvm_enable_cap { __u8 pad[64]; }; -/* for KVM_PPC_GET_PVINFO */ - -#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0) - -struct kvm_ppc_pvinfo { - /* out */ - __u32 flags; - __u32 hcall[4]; - __u8 pad[108]; -}; - -/* for KVM_PPC_GET_SMMU_INFO */ -#define KVM_PPC_PAGE_SIZES_MAX_SZ 8 - -struct kvm_ppc_one_page_size { - __u32 page_shift; /* Page shift (or 0) */ - __u32 pte_enc; /* Encoding in the HPTE (>>12) */ -}; - -struct kvm_ppc_one_seg_page_size { - __u32 page_shift; /* Base page shift of segment (or 0) */ - __u32 slb_enc; /* SLB encoding for BookS */ - struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ]; -}; - -#define KVM_PPC_PAGE_SIZES_REAL 0x00000001 -#define KVM_PPC_1T_SEGMENTS 0x00000002 -#define KVM_PPC_NO_HASH 0x00000004 - -struct kvm_ppc_smmu_info { - __u64 flags; - __u32 slb_size; - __u16 data_keys; /* # storage keys supported for data */ - __u16 instr_keys; /* # storage keys supported for instructions */ - struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; -}; - -/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */ -struct kvm_ppc_resize_hpt { - __u64 flags; - __u32 shift; - __u32 pad; -}; - #define KVMIO 0xAE /* machine type bits, to be used as argument to KVM_CREATE_VM */ From 71cd774ad2f98d4c78bc868e7e55397810be3540 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:19:08 -0500 Subject: [PATCH 239/814] KVM: s390: move s390-specific structs to uapi/asm/kvm.h While this in principle breaks the appearance of KVM_S390_* ioctls on architectures other than s390, this seems unlikely to be a problem considering that there are already many "struct kvm_s390_*" definitions in arch/s390/include/uapi. Signed-off-by: Paolo Bonzini --- arch/s390/include/uapi/asm/kvm.h | 314 +++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 312 ------------------------------ 2 files changed, 314 insertions(+), 312 deletions(-) diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index abe926d43cbe..fee712ff1cf8 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -14,6 +14,320 @@ #define __KVM_S390 #define __KVM_HAVE_GUEST_DEBUG +struct kvm_s390_skeys { + __u64 start_gfn; + __u64 count; + __u64 skeydata_addr; + __u32 flags; + __u32 reserved[9]; +}; + +#define KVM_S390_CMMA_PEEK (1 << 0) + +/** + * kvm_s390_cmma_log - Used for CMMA migration. + * + * Used both for input and output. + * + * @start_gfn: Guest page number to start from. + * @count: Size of the result buffer. + * @flags: Control operation mode via KVM_S390_CMMA_* flags + * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty + * pages are still remaining. + * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set + * in the PGSTE. + * @values: Pointer to the values buffer. + * + * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls. + */ +struct kvm_s390_cmma_log { + __u64 start_gfn; + __u32 count; + __u32 flags; + union { + __u64 remaining; + __u64 mask; + }; + __u64 values; +}; + +#define KVM_S390_RESET_POR 1 +#define KVM_S390_RESET_CLEAR 2 +#define KVM_S390_RESET_SUBSYSTEM 4 +#define KVM_S390_RESET_CPU_INIT 8 +#define KVM_S390_RESET_IPL 16 + +/* for KVM_S390_MEM_OP */ +struct kvm_s390_mem_op { + /* in */ + __u64 gaddr; /* the guest address */ + __u64 flags; /* flags */ + __u32 size; /* amount of bytes */ + __u32 op; /* type of operation */ + __u64 buf; /* buffer in userspace */ + union { + struct { + __u8 ar; /* the access register number */ + __u8 key; /* access key, ignored if flag unset */ + __u8 pad1[6]; /* ignored */ + __u64 old_addr; /* ignored if cmpxchg flag unset */ + }; + __u32 sida_offset; /* offset into the sida */ + __u8 reserved[32]; /* ignored */ + }; +}; +/* types for kvm_s390_mem_op->op */ +#define KVM_S390_MEMOP_LOGICAL_READ 0 +#define KVM_S390_MEMOP_LOGICAL_WRITE 1 +#define KVM_S390_MEMOP_SIDA_READ 2 +#define KVM_S390_MEMOP_SIDA_WRITE 3 +#define KVM_S390_MEMOP_ABSOLUTE_READ 4 +#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 +#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6 + +/* flags for kvm_s390_mem_op->flags */ +#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) +#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) +#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) + +/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */ +#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0) +#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1) + +struct kvm_s390_psw { + __u64 mask; + __u64 addr; +}; + +/* valid values for type in kvm_s390_interrupt */ +#define KVM_S390_SIGP_STOP 0xfffe0000u +#define KVM_S390_PROGRAM_INT 0xfffe0001u +#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u +#define KVM_S390_RESTART 0xfffe0003u +#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u +#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u +#define KVM_S390_MCHK 0xfffe1000u +#define KVM_S390_INT_CLOCK_COMP 0xffff1004u +#define KVM_S390_INT_CPU_TIMER 0xffff1005u +#define KVM_S390_INT_VIRTIO 0xffff2603u +#define KVM_S390_INT_SERVICE 0xffff2401u +#define KVM_S390_INT_EMERGENCY 0xffff1201u +#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u +/* Anything below 0xfffe0000u is taken by INT_IO */ +#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \ + (((schid)) | \ + ((ssid) << 16) | \ + ((cssid) << 18) | \ + ((ai) << 26)) +#define KVM_S390_INT_IO_MIN 0x00000000u +#define KVM_S390_INT_IO_MAX 0xfffdffffu +#define KVM_S390_INT_IO_AI_MASK 0x04000000u + + +struct kvm_s390_interrupt { + __u32 type; + __u32 parm; + __u64 parm64; +}; + +struct kvm_s390_io_info { + __u16 subchannel_id; + __u16 subchannel_nr; + __u32 io_int_parm; + __u32 io_int_word; +}; + +struct kvm_s390_ext_info { + __u32 ext_params; + __u32 pad; + __u64 ext_params2; +}; + +struct kvm_s390_pgm_info { + __u64 trans_exc_code; + __u64 mon_code; + __u64 per_address; + __u32 data_exc_code; + __u16 code; + __u16 mon_class_nr; + __u8 per_code; + __u8 per_atmid; + __u8 exc_access_id; + __u8 per_access_id; + __u8 op_access_id; +#define KVM_S390_PGM_FLAGS_ILC_VALID 0x01 +#define KVM_S390_PGM_FLAGS_ILC_0 0x02 +#define KVM_S390_PGM_FLAGS_ILC_1 0x04 +#define KVM_S390_PGM_FLAGS_ILC_MASK 0x06 +#define KVM_S390_PGM_FLAGS_NO_REWIND 0x08 + __u8 flags; + __u8 pad[2]; +}; + +struct kvm_s390_prefix_info { + __u32 address; +}; + +struct kvm_s390_extcall_info { + __u16 code; +}; + +struct kvm_s390_emerg_info { + __u16 code; +}; + +#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01 +struct kvm_s390_stop_info { + __u32 flags; +}; + +struct kvm_s390_mchk_info { + __u64 cr14; + __u64 mcic; + __u64 failing_storage_address; + __u32 ext_damage_code; + __u32 pad; + __u8 fixed_logout[16]; +}; + +struct kvm_s390_irq { + __u64 type; + union { + struct kvm_s390_io_info io; + struct kvm_s390_ext_info ext; + struct kvm_s390_pgm_info pgm; + struct kvm_s390_emerg_info emerg; + struct kvm_s390_extcall_info extcall; + struct kvm_s390_prefix_info prefix; + struct kvm_s390_stop_info stop; + struct kvm_s390_mchk_info mchk; + char reserved[64]; + } u; +}; + +struct kvm_s390_irq_state { + __u64 buf; + __u32 flags; /* will stay unused for compatibility reasons */ + __u32 len; + __u32 reserved[4]; /* will stay unused for compatibility reasons */ +}; + +struct kvm_s390_ucas_mapping { + __u64 user_addr; + __u64 vcpu_addr; + __u64 length; +}; + +struct kvm_s390_pv_sec_parm { + __u64 origin; + __u64 length; +}; + +struct kvm_s390_pv_unp { + __u64 addr; + __u64 size; + __u64 tweak; +}; + +enum pv_cmd_dmp_id { + KVM_PV_DUMP_INIT, + KVM_PV_DUMP_CONFIG_STOR_STATE, + KVM_PV_DUMP_COMPLETE, + KVM_PV_DUMP_CPU, +}; + +struct kvm_s390_pv_dmp { + __u64 subcmd; + __u64 buff_addr; + __u64 buff_len; + __u64 gaddr; /* For dump storage state */ + __u64 reserved[4]; +}; + +enum pv_cmd_info_id { + KVM_PV_INFO_VM, + KVM_PV_INFO_DUMP, +}; + +struct kvm_s390_pv_info_dump { + __u64 dump_cpu_buffer_len; + __u64 dump_config_mem_buffer_per_1m; + __u64 dump_config_finalize_len; +}; + +struct kvm_s390_pv_info_vm { + __u64 inst_calls_list[4]; + __u64 max_cpus; + __u64 max_guests; + __u64 max_guest_addr; + __u64 feature_indication; +}; + +struct kvm_s390_pv_info_header { + __u32 id; + __u32 len_max; + __u32 len_written; + __u32 reserved; +}; + +struct kvm_s390_pv_info { + struct kvm_s390_pv_info_header header; + union { + struct kvm_s390_pv_info_dump dump; + struct kvm_s390_pv_info_vm vm; + }; +}; + +enum pv_cmd_id { + KVM_PV_ENABLE, + KVM_PV_DISABLE, + KVM_PV_SET_SEC_PARMS, + KVM_PV_UNPACK, + KVM_PV_VERIFY, + KVM_PV_PREP_RESET, + KVM_PV_UNSHARE_ALL, + KVM_PV_INFO, + KVM_PV_DUMP, + KVM_PV_ASYNC_CLEANUP_PREPARE, + KVM_PV_ASYNC_CLEANUP_PERFORM, +}; + +struct kvm_pv_cmd { + __u32 cmd; /* Command to be executed */ + __u16 rc; /* Ultravisor return code */ + __u16 rrc; /* Ultravisor return reason code */ + __u64 data; /* Data or address */ + __u32 flags; /* flags for future extensions. Must be 0 for now */ + __u32 reserved[3]; +}; + +struct kvm_s390_zpci_op { + /* in */ + __u32 fh; /* target device */ + __u8 op; /* operation to perform */ + __u8 pad[3]; + union { + /* for KVM_S390_ZPCIOP_REG_AEN */ + struct { + __u64 ibv; /* Guest addr of interrupt bit vector */ + __u64 sb; /* Guest addr of summary bit */ + __u32 flags; + __u32 noi; /* Number of interrupts */ + __u8 isc; /* Guest interrupt subclass */ + __u8 sbo; /* Offset of guest summary bit vector */ + __u16 pad; + } reg_aen; + __u64 reserved[8]; + } u; +}; + +/* types for kvm_s390_zpci_op->op */ +#define KVM_S390_ZPCIOP_REG_AEN 0 +#define KVM_S390_ZPCIOP_DEREG_AEN 1 + +/* flags for kvm_s390_zpci_op->u.reg_aen.flags */ +#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) + /* Device control API: s390-specific devices */ #define KVM_DEV_FLIC_GET_ALL_IRQS 1 #define KVM_DEV_FLIC_ENQUEUE 2 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a5458aeee018..b7c8054e9d14 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -85,43 +85,6 @@ struct kvm_pit_config { #define KVM_PIT_SPEAKER_DUMMY 1 -struct kvm_s390_skeys { - __u64 start_gfn; - __u64 count; - __u64 skeydata_addr; - __u32 flags; - __u32 reserved[9]; -}; - -#define KVM_S390_CMMA_PEEK (1 << 0) - -/** - * kvm_s390_cmma_log - Used for CMMA migration. - * - * Used both for input and output. - * - * @start_gfn: Guest page number to start from. - * @count: Size of the result buffer. - * @flags: Control operation mode via KVM_S390_CMMA_* flags - * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty - * pages are still remaining. - * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set - * in the PGSTE. - * @values: Pointer to the values buffer. - * - * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls. - */ -struct kvm_s390_cmma_log { - __u64 start_gfn; - __u32 count; - __u32 flags; - union { - __u64 remaining; - __u64 mask; - }; - __u64 values; -}; - struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 #define KVM_EXIT_HYPERV_HCALL 2 @@ -315,11 +278,6 @@ struct kvm_run { __u32 ipb; } s390_sieic; /* KVM_EXIT_S390_RESET */ -#define KVM_S390_RESET_POR 1 -#define KVM_S390_RESET_CLEAR 2 -#define KVM_S390_RESET_SUBSYSTEM 4 -#define KVM_S390_RESET_CPU_INIT 8 -#define KVM_S390_RESET_IPL 16 __u64 s390_reset_flags; /* KVM_EXIT_S390_UCONTROL */ struct { @@ -536,43 +494,6 @@ struct kvm_translation { __u8 pad[5]; }; -/* for KVM_S390_MEM_OP */ -struct kvm_s390_mem_op { - /* in */ - __u64 gaddr; /* the guest address */ - __u64 flags; /* flags */ - __u32 size; /* amount of bytes */ - __u32 op; /* type of operation */ - __u64 buf; /* buffer in userspace */ - union { - struct { - __u8 ar; /* the access register number */ - __u8 key; /* access key, ignored if flag unset */ - __u8 pad1[6]; /* ignored */ - __u64 old_addr; /* ignored if cmpxchg flag unset */ - }; - __u32 sida_offset; /* offset into the sida */ - __u8 reserved[32]; /* ignored */ - }; -}; -/* types for kvm_s390_mem_op->op */ -#define KVM_S390_MEMOP_LOGICAL_READ 0 -#define KVM_S390_MEMOP_LOGICAL_WRITE 1 -#define KVM_S390_MEMOP_SIDA_READ 2 -#define KVM_S390_MEMOP_SIDA_WRITE 3 -#define KVM_S390_MEMOP_ABSOLUTE_READ 4 -#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 -#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6 - -/* flags for kvm_s390_mem_op->flags */ -#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) -#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) -#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) - -/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */ -#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0) -#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1) - /* for KVM_INTERRUPT */ struct kvm_interrupt { /* in */ @@ -637,124 +558,6 @@ struct kvm_mp_state { __u32 mp_state; }; -struct kvm_s390_psw { - __u64 mask; - __u64 addr; -}; - -/* valid values for type in kvm_s390_interrupt */ -#define KVM_S390_SIGP_STOP 0xfffe0000u -#define KVM_S390_PROGRAM_INT 0xfffe0001u -#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u -#define KVM_S390_RESTART 0xfffe0003u -#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u -#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u -#define KVM_S390_MCHK 0xfffe1000u -#define KVM_S390_INT_CLOCK_COMP 0xffff1004u -#define KVM_S390_INT_CPU_TIMER 0xffff1005u -#define KVM_S390_INT_VIRTIO 0xffff2603u -#define KVM_S390_INT_SERVICE 0xffff2401u -#define KVM_S390_INT_EMERGENCY 0xffff1201u -#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u -/* Anything below 0xfffe0000u is taken by INT_IO */ -#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \ - (((schid)) | \ - ((ssid) << 16) | \ - ((cssid) << 18) | \ - ((ai) << 26)) -#define KVM_S390_INT_IO_MIN 0x00000000u -#define KVM_S390_INT_IO_MAX 0xfffdffffu -#define KVM_S390_INT_IO_AI_MASK 0x04000000u - - -struct kvm_s390_interrupt { - __u32 type; - __u32 parm; - __u64 parm64; -}; - -struct kvm_s390_io_info { - __u16 subchannel_id; - __u16 subchannel_nr; - __u32 io_int_parm; - __u32 io_int_word; -}; - -struct kvm_s390_ext_info { - __u32 ext_params; - __u32 pad; - __u64 ext_params2; -}; - -struct kvm_s390_pgm_info { - __u64 trans_exc_code; - __u64 mon_code; - __u64 per_address; - __u32 data_exc_code; - __u16 code; - __u16 mon_class_nr; - __u8 per_code; - __u8 per_atmid; - __u8 exc_access_id; - __u8 per_access_id; - __u8 op_access_id; -#define KVM_S390_PGM_FLAGS_ILC_VALID 0x01 -#define KVM_S390_PGM_FLAGS_ILC_0 0x02 -#define KVM_S390_PGM_FLAGS_ILC_1 0x04 -#define KVM_S390_PGM_FLAGS_ILC_MASK 0x06 -#define KVM_S390_PGM_FLAGS_NO_REWIND 0x08 - __u8 flags; - __u8 pad[2]; -}; - -struct kvm_s390_prefix_info { - __u32 address; -}; - -struct kvm_s390_extcall_info { - __u16 code; -}; - -struct kvm_s390_emerg_info { - __u16 code; -}; - -#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01 -struct kvm_s390_stop_info { - __u32 flags; -}; - -struct kvm_s390_mchk_info { - __u64 cr14; - __u64 mcic; - __u64 failing_storage_address; - __u32 ext_damage_code; - __u32 pad; - __u8 fixed_logout[16]; -}; - -struct kvm_s390_irq { - __u64 type; - union { - struct kvm_s390_io_info io; - struct kvm_s390_ext_info ext; - struct kvm_s390_pgm_info pgm; - struct kvm_s390_emerg_info emerg; - struct kvm_s390_extcall_info extcall; - struct kvm_s390_prefix_info prefix; - struct kvm_s390_stop_info stop; - struct kvm_s390_mchk_info mchk; - char reserved[64]; - } u; -}; - -struct kvm_s390_irq_state { - __u64 buf; - __u32 flags; /* will stay unused for compatibility reasons */ - __u32 len; - __u32 reserved[4]; /* will stay unused for compatibility reasons */ -}; - /* for KVM_SET_GUEST_DEBUG */ #define KVM_GUESTDBG_ENABLE 0x00000001 @@ -1364,11 +1167,6 @@ struct kvm_vfio_spapr_tce { struct kvm_userspace_memory_region2) /* enable ucontrol for s390 */ -struct kvm_s390_ucas_mapping { - __u64 user_addr; - __u64 vcpu_addr; - __u64 length; -}; #define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping) #define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping) #define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long) @@ -1563,89 +1361,6 @@ struct kvm_enc_region { #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) -struct kvm_s390_pv_sec_parm { - __u64 origin; - __u64 length; -}; - -struct kvm_s390_pv_unp { - __u64 addr; - __u64 size; - __u64 tweak; -}; - -enum pv_cmd_dmp_id { - KVM_PV_DUMP_INIT, - KVM_PV_DUMP_CONFIG_STOR_STATE, - KVM_PV_DUMP_COMPLETE, - KVM_PV_DUMP_CPU, -}; - -struct kvm_s390_pv_dmp { - __u64 subcmd; - __u64 buff_addr; - __u64 buff_len; - __u64 gaddr; /* For dump storage state */ - __u64 reserved[4]; -}; - -enum pv_cmd_info_id { - KVM_PV_INFO_VM, - KVM_PV_INFO_DUMP, -}; - -struct kvm_s390_pv_info_dump { - __u64 dump_cpu_buffer_len; - __u64 dump_config_mem_buffer_per_1m; - __u64 dump_config_finalize_len; -}; - -struct kvm_s390_pv_info_vm { - __u64 inst_calls_list[4]; - __u64 max_cpus; - __u64 max_guests; - __u64 max_guest_addr; - __u64 feature_indication; -}; - -struct kvm_s390_pv_info_header { - __u32 id; - __u32 len_max; - __u32 len_written; - __u32 reserved; -}; - -struct kvm_s390_pv_info { - struct kvm_s390_pv_info_header header; - union { - struct kvm_s390_pv_info_dump dump; - struct kvm_s390_pv_info_vm vm; - }; -}; - -enum pv_cmd_id { - KVM_PV_ENABLE, - KVM_PV_DISABLE, - KVM_PV_SET_SEC_PARMS, - KVM_PV_UNPACK, - KVM_PV_VERIFY, - KVM_PV_PREP_RESET, - KVM_PV_UNSHARE_ALL, - KVM_PV_INFO, - KVM_PV_DUMP, - KVM_PV_ASYNC_CLEANUP_PREPARE, - KVM_PV_ASYNC_CLEANUP_PERFORM, -}; - -struct kvm_pv_cmd { - __u32 cmd; /* Command to be executed */ - __u16 rc; /* Ultravisor return code */ - __u16 rrc; /* Ultravisor return reason code */ - __u64 data; /* Data or address */ - __u32 flags; /* flags for future extensions. Must be 0 for now */ - __u32 reserved[3]; -}; - /* Available with KVM_CAP_S390_PROTECTED */ #define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd) @@ -1821,33 +1536,6 @@ struct kvm_stats_desc { /* Available with KVM_CAP_S390_ZPCI_OP */ #define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op) -struct kvm_s390_zpci_op { - /* in */ - __u32 fh; /* target device */ - __u8 op; /* operation to perform */ - __u8 pad[3]; - union { - /* for KVM_S390_ZPCIOP_REG_AEN */ - struct { - __u64 ibv; /* Guest addr of interrupt bit vector */ - __u64 sb; /* Guest addr of summary bit */ - __u32 flags; - __u32 noi; /* Number of interrupts */ - __u8 isc; /* Guest interrupt subclass */ - __u8 sbo; /* Offset of guest summary bit vector */ - __u16 pad; - } reg_aen; - __u64 reserved[8]; - } u; -}; - -/* types for kvm_s390_zpci_op->op */ -#define KVM_S390_ZPCIOP_REG_AEN 0 -#define KVM_S390_ZPCIOP_DEREG_AEN 1 - -/* flags for kvm_s390_zpci_op->u.reg_aen.flags */ -#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) - /* Available with KVM_CAP_MEMORY_ATTRIBUTES */ #define KVM_SET_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd2, struct kvm_memory_attributes) From 5d9cb71642db11a5149c9a7234a9a62d387de449 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:19:08 -0500 Subject: [PATCH 240/814] KVM: arm64: move ARM-specific defines to uapi/asm/kvm.h While this in principle breaks userspace code that mentions KVM_ARM_DEV_* on architectures other than aarch64, this seems unlikely to be a problem considering that run->s.regs.device_irq_level is only defined on that architecture. Signed-off-by: Paolo Bonzini --- arch/arm64/include/uapi/asm/kvm.h | 5 +++++ include/uapi/linux/kvm.h | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 6b8b57b97228..75809c8dc2f0 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -162,6 +162,11 @@ struct kvm_sync_regs { __u64 device_irq_level; }; +/* Bits for run->s.regs.device_irq_level */ +#define KVM_ARM_DEV_EL1_VTIMER (1 << 0) +#define KVM_ARM_DEV_EL1_PTIMER (1 << 1) +#define KVM_ARM_DEV_PMU (1 << 2) + /* * PMU filter structure. Describe a range of events with a particular * action. To be used with KVM_ARM_VCPU_PMU_V3_FILTER. diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index b7c8054e9d14..00d5cecd057d 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1384,13 +1384,6 @@ struct kvm_enc_region { #define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) #define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2) -/* Available with KVM_CAP_ARM_USER_IRQ */ - -/* Bits for run->s.regs.device_irq_level */ -#define KVM_ARM_DEV_EL1_VTIMER (1 << 0) -#define KVM_ARM_DEV_EL1_PTIMER (1 << 1) -#define KVM_ARM_DEV_PMU (1 << 2) - #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) #define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1) From 8886640dade4ae2595fcdce511c8bcc716aa47d3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:00:34 -0500 Subject: [PATCH 241/814] kvm: replace __KVM_HAVE_READONLY_MEM with Kconfig symbol KVM uses __KVM_HAVE_* symbols in the architecture-dependent uapi/asm/kvm.h to mask unused definitions in include/uapi/linux/kvm.h. __KVM_HAVE_READONLY_MEM however was nothing but a misguided attempt to define KVM_CAP_READONLY_MEM only on architectures where KVM_CHECK_EXTENSION(KVM_CAP_READONLY_MEM) could possibly return nonzero. This however does not make sense, and it prevented userspace from supporting this architecture-independent feature without recompilation. Therefore, these days __KVM_HAVE_READONLY_MEM does not mask anything and is only used in virt/kvm/kvm_main.c. Userspace does not need to test it and there should be no need for it to exist. Remove it and replace it with a Kconfig symbol within Linux source code. Signed-off-by: Paolo Bonzini --- arch/arm64/include/uapi/asm/kvm.h | 1 - arch/arm64/kvm/Kconfig | 1 + arch/loongarch/include/uapi/asm/kvm.h | 2 -- arch/loongarch/kvm/Kconfig | 1 + arch/mips/include/uapi/asm/kvm.h | 2 -- arch/mips/kvm/Kconfig | 1 + arch/riscv/include/uapi/asm/kvm.h | 1 - arch/riscv/kvm/Kconfig | 1 + arch/x86/include/uapi/asm/kvm.h | 1 - arch/x86/kvm/Kconfig | 1 + virt/kvm/Kconfig | 3 +++ virt/kvm/kvm_main.c | 2 +- 12 files changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 75809c8dc2f0..9c1040dad4eb 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -39,7 +39,6 @@ #define __KVM_HAVE_GUEST_DEBUG #define __KVM_HAVE_IRQ_LINE -#define __KVM_HAVE_READONLY_MEM #define __KVM_HAVE_VCPU_EVENTS #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 6c3c8ca73e7f..114626b816f7 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -36,6 +36,7 @@ menuconfig KVM select HAVE_KVM_IRQ_ROUTING select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS + select HAVE_KVM_READONLY_MEM select HAVE_KVM_VCPU_RUN_PID_CHANGE select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index 923d0bd38294..109785922cf9 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -14,8 +14,6 @@ * Some parts derived from the x86 version of this file. */ -#define __KVM_HAVE_READONLY_MEM - #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #define KVM_DIRTY_LOG_PAGE_OFFSET 64 diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index 61f7e33b1f95..0768b45422a3 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select KVM_GENERIC_HARDWARE_ENABLING select KVM_GENERIC_MMU_NOTIFIER select KVM_MMIO + select HAVE_KVM_READONLY_MEM select KVM_XFER_TO_GUEST_WORK help Support hosting virtualized guest machines using diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index edcf717c4327..9673dc9cb315 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h @@ -20,8 +20,6 @@ * Some parts derived from the x86 version of this file. */ -#define __KVM_HAVE_READONLY_MEM - #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 /* diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index 18e7a17d5115..8474bf9c689e 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -26,6 +26,7 @@ config KVM select KVM_MMIO select KVM_GENERIC_MMU_NOTIFIER select KVM_GENERIC_HARDWARE_ENABLING + select HAVE_KVM_READONLY_MEM help Support for hosting Guest kernels. diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 7499e88a947c..fdf4ba066131 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -16,7 +16,6 @@ #include #define __KVM_HAVE_IRQ_LINE -#define __KVM_HAVE_READONLY_MEM #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index d490db943858..26d1727f0550 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -24,6 +24,7 @@ config KVM select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_MSI select HAVE_KVM_VCPU_ASYNC_IOCTL + select HAVE_KVM_READONLY_MEM select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index bf68e56fd484..c5e682ee7726 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -51,7 +51,6 @@ #define __KVM_HAVE_DEBUGREGS #define __KVM_HAVE_XSAVE #define __KVM_HAVE_XCRS -#define __KVM_HAVE_READONLY_MEM /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 87e3da7b0439..5895aee5dfef 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -32,6 +32,7 @@ config KVM select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_IRQ_ROUTING + select HAVE_KVM_READONLY_MEM select KVM_ASYNC_PF select USER_RETURN_NOTIFIER select KVM_MMIO diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 184dab4ee871..a11e9c80fac9 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -55,6 +55,9 @@ config KVM_ASYNC_PF_SYNC config HAVE_KVM_MSI bool +config HAVE_KVM_READONLY_MEM + bool + config HAVE_KVM_CPU_RELAX_INTERCEPT bool diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 10bfc88a69f7..ff588677beb7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1614,7 +1614,7 @@ static int check_memory_region_flags(struct kvm *kvm, if (mem->flags & KVM_MEM_GUEST_MEMFD) valid_flags &= ~KVM_MEM_LOG_DIRTY_PAGES; -#ifdef __KVM_HAVE_READONLY_MEM +#ifdef CONFIG_HAVE_KVM_READONLY_MEM valid_flags |= KVM_MEM_READONLY; #endif From 6bda055d625860736f7ea5b4eda816f276899d8b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:12:59 -0500 Subject: [PATCH 242/814] KVM: define __KVM_HAVE_GUEST_DEBUG unconditionally Since all architectures (for historical reasons) have to define struct kvm_guest_debug_arch, and since userspace has to check KVM_CHECK_EXTENSION(KVM_CAP_SET_GUEST_DEBUG) anyway, there is no advantage in masking the capability #define itself. Remove the #define __KVM_HAVE_GUEST_DEBUG from architecture-specific headers. Signed-off-by: Paolo Bonzini --- arch/arm64/include/uapi/asm/kvm.h | 1 - arch/powerpc/include/uapi/asm/kvm.h | 1 - arch/s390/include/uapi/asm/kvm.h | 1 - arch/x86/include/uapi/asm/kvm.h | 1 - include/uapi/linux/kvm.h | 7 +++++-- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 9c1040dad4eb..964df31da975 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -37,7 +37,6 @@ #include #include -#define __KVM_HAVE_GUEST_DEBUG #define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_VCPU_EVENTS diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index a96ef6b36bba..1691297a766a 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -28,7 +28,6 @@ #define __KVM_HAVE_PPC_SMT #define __KVM_HAVE_IRQCHIP #define __KVM_HAVE_IRQ_LINE -#define __KVM_HAVE_GUEST_DEBUG /* Not always available, but if it is, this is the correct offset. */ #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index fee712ff1cf8..05eaf6db3ad4 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -12,7 +12,6 @@ #include #define __KVM_S390 -#define __KVM_HAVE_GUEST_DEBUG struct kvm_s390_skeys { __u64 start_gfn; diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index c5e682ee7726..0ad6bda1fc39 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -42,7 +42,6 @@ #define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_MSI #define __KVM_HAVE_USER_NMI -#define __KVM_HAVE_GUEST_DEBUG #define __KVM_HAVE_MSIX #define __KVM_HAVE_MCE #define __KVM_HAVE_PIT_STATE2 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 00d5cecd057d..2ad6aa81b03f 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -16,6 +16,11 @@ #define KVM_API_VERSION 12 +/* + * Backwards-compatible definitions. + */ +#define __KVM_HAVE_GUEST_DEBUG + /* for KVM_SET_USER_MEMORY_REGION */ struct kvm_userspace_memory_region { __u32 slot; @@ -682,9 +687,7 @@ struct kvm_enable_cap { /* Bug in KVM_SET_USER_MEMORY_REGION fixed: */ #define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21 #define KVM_CAP_USER_NMI 22 -#ifdef __KVM_HAVE_GUEST_DEBUG #define KVM_CAP_SET_GUEST_DEBUG 23 -#endif #ifdef __KVM_HAVE_PIT #define KVM_CAP_REINJECT_CONTROL 24 #endif From db7d6fbc10447090bab8691a907a7c383ec66f58 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:16:47 -0500 Subject: [PATCH 243/814] KVM: remove unnecessary #ifdef KVM_CAP_IRQ_ROUTING is always defined, so there is no need to check if it is. Signed-off-by: Paolo Bonzini --- include/uapi/linux/kvm.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2ad6aa81b03f..2190adbe3002 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -918,8 +918,6 @@ struct kvm_enable_cap { #define KVM_CAP_GUEST_MEMFD 234 #define KVM_CAP_VM_TYPES 235 -#ifdef KVM_CAP_IRQ_ROUTING - struct kvm_irq_routing_irqchip { __u32 irqchip; __u32 pin; @@ -984,8 +982,6 @@ struct kvm_irq_routing { struct kvm_irq_routing_entry entries[]; }; -#endif - #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0) /* * Available with KVM_CAP_IRQFD_RESAMPLE From 61df71ee992d57ee2b7fdb802802c4268969409f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Jan 2024 03:02:05 -0500 Subject: [PATCH 244/814] kvm: move "select IRQ_BYPASS_MANAGER" to common code CONFIG_IRQ_BYPASS_MANAGER is a dependency of the common code included by CONFIG_HAVE_KVM_IRQ_BYPASS. There is no advantage in adding the corresponding "select" directive to each architecture. Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/Kconfig | 1 - arch/powerpc/kvm/Kconfig | 1 - arch/x86/kvm/Kconfig | 1 - virt/kvm/Kconfig | 1 + 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 6c3c8ca73e7f..46bdbd852857 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -34,7 +34,6 @@ menuconfig KVM select HAVE_KVM_MSI select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQ_ROUTING - select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_VCPU_RUN_PID_CHANGE select SCHED_INFO diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 074263429faf..dbfdc126bf14 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -22,7 +22,6 @@ config KVM select KVM_COMMON select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_VFIO - select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS config KVM_BOOK3S_HANDLER diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 87e3da7b0439..e7cbf011d766 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -29,7 +29,6 @@ config KVM select HAVE_KVM_PFNCACHE select HAVE_KVM_DIRTY_RING_TSO select HAVE_KVM_DIRTY_RING_ACQ_REL - select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_IRQ_ROUTING select KVM_ASYNC_PF diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 184dab4ee871..6408bc5dacd1 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -73,6 +73,7 @@ config KVM_COMPAT config HAVE_KVM_IRQ_BYPASS bool + select IRQ_BYPASS_MANAGER config HAVE_KVM_VCPU_ASYNC_IOCTL bool From a6d5433801c6629cda6cda6d8bdaefc204953abf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jan 2024 11:00:36 -0500 Subject: [PATCH 245/814] MIPS: introduce Kconfig for MIPS VZ Since MIPS/KVM only supports hardware virtualization using MIPS VZ, do not enable KVM blindly. Use a new Kconfig symbol CPU_SUPPORTS_VZ and do not enable it for R2 processors. Cc: Thomas Bogendoerfer Signed-off-by: Paolo Bonzini --- arch/mips/Kconfig | 9 +++++++++ arch/mips/kvm/Kconfig | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 797ae590ebdb..3eb3239013d9 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1250,6 +1250,7 @@ config CPU_LOONGSON64 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES select CPU_SUPPORTS_MSA + select CPU_SUPPORTS_VZ select CPU_DIEI_BROKEN if !LOONGSON3_ENHANCEMENT select CPU_MIPSR2_IRQ_VI select DMA_NONCOHERENT @@ -1389,6 +1390,7 @@ config CPU_MIPS32_R5 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA + select CPU_SUPPORTS_VZ select HAVE_KVM select MIPS_O32_FP64_SUPPORT help @@ -1405,6 +1407,7 @@ config CPU_MIPS32_R6 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA + select CPU_SUPPORTS_VZ select HAVE_KVM select MIPS_O32_FP64_SUPPORT help @@ -1459,6 +1462,7 @@ config CPU_MIPS64_R5 select CPU_SUPPORTS_HUGEPAGES select CPU_SUPPORTS_MSA select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32 + select CPU_SUPPORTS_VZ select HAVE_KVM help Choose this option to build a kernel for release 5 or later of the @@ -1477,6 +1481,7 @@ config CPU_MIPS64_R6 select CPU_SUPPORTS_HUGEPAGES select CPU_SUPPORTS_MSA select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32 + select CPU_SUPPORTS_VZ select HAVE_KVM help Choose this option to build a kernel for release 6 or later of the @@ -1492,6 +1497,7 @@ config CPU_P5600 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA select CPU_SUPPORTS_CPUFREQ + select CPU_SUPPORTS_VZ select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select HAVE_KVM @@ -1614,6 +1620,7 @@ config CPU_CAVIUM_OCTEON select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select MIPS_L1_CACHE_SHIFT_7 + select CPU_SUPPORTS_VZ select HAVE_KVM help The Cavium Octeon processor is a highly integrated chip containing @@ -1969,6 +1976,8 @@ config CPU_SUPPORTS_ADDRWINCFG config CPU_SUPPORTS_HUGEPAGES bool depends on !(32BIT && (PHYS_ADDR_T_64BIT || EVA)) +config CPU_SUPPORTS_VZ + bool config MIPS_PGD_C0_CONTEXT bool depends on 64BIT diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index 18e7a17d5115..8916b3ed0f90 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -17,7 +17,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM + depends on CPU_SUPPORTS_VZ depends on MIPS_FP_SUPPORT select EXPORT_UASM select KVM_COMMON From dcf0926e9b899eca754a07c4064de69815b85a38 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jan 2024 15:15:43 -0500 Subject: [PATCH 246/814] x86: replace CONFIG_HAVE_KVM with IS_ENABLED(CONFIG_KVM) It is more accurate to check if KVM is enabled, instead of having the architecture say so. Architectures always "have" KVM, so for example checking CONFIG_HAVE_KVM in x86 code is pointless, but if KVM is disabled in a specific build, there is no need for support code. Alternatively, many of the #ifdefs could simply be deleted. However, this would add completely dead code. For example, when KVM is disabled, there should not be any posted interrupts, i.e. NOT wiring up the "dummy" handlers and treating IRQs on those vectors as spurious is the right thing to do. Cc: x86@kernel.org Cc: kbingham@kernel.org Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/hardirq.h | 2 +- arch/x86/include/asm/idtentry.h | 2 +- arch/x86/include/asm/irq.h | 2 +- arch/x86/include/asm/irq_vectors.h | 2 +- arch/x86/kernel/idt.c | 2 +- arch/x86/kernel/irq.c | 4 ++-- scripts/gdb/linux/constants.py.in | 6 +++++- scripts/gdb/linux/interrupts.py | 2 +- tools/arch/x86/include/asm/irq_vectors.h | 2 +- 9 files changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 66837b8c67f1..fbc7722b87d1 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -15,7 +15,7 @@ typedef struct { unsigned int irq_spurious_count; unsigned int icr_read_retry_count; #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) unsigned int kvm_posted_intr_ipis; unsigned int kvm_posted_intr_wakeup_ipis; unsigned int kvm_posted_intr_nested_ipis; diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 13639e57e1f8..d9c86733d0db 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -675,7 +675,7 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work); # endif #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR, sysvec_kvm_posted_intr_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested_ipi); diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 836c170d3087..194dfff84cb1 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -29,7 +29,7 @@ struct irq_desc; extern void fixup_irqs(void); -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void)); #endif diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 3a19904c2db6..3f73ac3ed3a0 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -84,7 +84,7 @@ #define HYPERVISOR_CALLBACK_VECTOR 0xf3 /* Vector for KVM to deliver posted interrupt IPI */ -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) #define POSTED_INTR_VECTOR 0xf2 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 #define POSTED_INTR_NESTED_VECTOR 0xf0 diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 660b601f1d6c..d2bc67cbaf92 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -153,7 +153,7 @@ static const __initconst struct idt_data apic_idts[] = { #ifdef CONFIG_X86_LOCAL_APIC INTG(LOCAL_TIMER_VECTOR, asm_sysvec_apic_timer_interrupt), INTG(X86_PLATFORM_IPI_VECTOR, asm_sysvec_x86_platform_ipi), -# ifdef CONFIG_HAVE_KVM +# if IS_ENABLED(CONFIG_KVM) INTG(POSTED_INTR_VECTOR, asm_sysvec_kvm_posted_intr_ipi), INTG(POSTED_INTR_WAKEUP_VECTOR, asm_sysvec_kvm_posted_intr_wakeup_ipi), INTG(POSTED_INTR_NESTED_VECTOR, asm_sysvec_kvm_posted_intr_nested_ipi), diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 11761c124545..35fde0107901 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -164,7 +164,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) #if defined(CONFIG_X86_IO_APIC) seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count)); #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) seq_printf(p, "%*s: ", prec, "PIN"); for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis); @@ -290,7 +290,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platform_ipi) } #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) static void dummy_handler(void) {} static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler; diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index e810e0c27ff1..5cace7588e24 100644 --- a/scripts/gdb/linux/constants.py.in +++ b/scripts/gdb/linux/constants.py.in @@ -130,7 +130,11 @@ LX_CONFIG(CONFIG_X86_MCE_THRESHOLD) LX_CONFIG(CONFIG_X86_MCE_AMD) LX_CONFIG(CONFIG_X86_MCE) LX_CONFIG(CONFIG_X86_IO_APIC) -LX_CONFIG(CONFIG_HAVE_KVM) +/* + * CONFIG_KVM can be "m" but it affects common code too. Use CONFIG_KVM_COMMON + * as a proxy for IS_ENABLED(CONFIG_KVM). + */ +LX_CONFIG_KVM = IS_BUILTIN(CONFIG_KVM_COMMON) LX_CONFIG(CONFIG_NUMA) LX_CONFIG(CONFIG_ARM64) LX_CONFIG(CONFIG_ARM64_4K_PAGES) diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py index ef478e273791..66ae5c7690cf 100644 --- a/scripts/gdb/linux/interrupts.py +++ b/scripts/gdb/linux/interrupts.py @@ -151,7 +151,7 @@ def x86_show_interupts(prec): if cnt is not None: text += "%*s: %10u\n" % (prec, "MIS", cnt['counter']) - if constants.LX_CONFIG_HAVE_KVM: + if constants.LX_CONFIG_KVM: text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event') text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event') text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event') diff --git a/tools/arch/x86/include/asm/irq_vectors.h b/tools/arch/x86/include/asm/irq_vectors.h index 3a19904c2db6..3f73ac3ed3a0 100644 --- a/tools/arch/x86/include/asm/irq_vectors.h +++ b/tools/arch/x86/include/asm/irq_vectors.h @@ -84,7 +84,7 @@ #define HYPERVISOR_CALLBACK_VECTOR 0xf3 /* Vector for KVM to deliver posted interrupt IPI */ -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) #define POSTED_INTR_VECTOR 0xf2 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 #define POSTED_INTR_NESTED_VECTOR 0xf0 From 09e33b045526085fc216bfbb216d87c8da7deb4f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jan 2024 15:15:43 -0500 Subject: [PATCH 247/814] vfio: replace CONFIG_HAVE_KVM with IS_ENABLED(CONFIG_KVM) It is more accurate to Check if KVM is enabled, instead of having the architecture say so. Architectures always "have" KVM, so for example checking CONFIG_HAVE_KVM in vfio code is pointless, but if KVM is disabled in a specific build, there is no need for support code. Alternatively, the #ifdefs could simply be deleted. However, this would add dead code. For example, when KVM is disabled, there is no need to include code in VFIO that uses symbol_get, as that symbol_get would always fail. Cc: Alex Williamson Cc: x86@kernel.org Cc: kbingham@kernel.org Signed-off-by: Paolo Bonzini --- drivers/vfio/vfio.h | 2 +- drivers/vfio/vfio_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h index bde84ad344e5..50128da18bca 100644 --- a/drivers/vfio/vfio.h +++ b/drivers/vfio/vfio.h @@ -434,7 +434,7 @@ static inline void vfio_virqfd_exit(void) } #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm); void vfio_device_put_kvm(struct vfio_device *device); #else diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 1cc93aac99a2..e97d796a54fb 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -16,7 +16,7 @@ #include #include #include -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) #include #endif #include @@ -385,7 +385,7 @@ void vfio_unregister_group_dev(struct vfio_device *device) } EXPORT_SYMBOL_GPL(vfio_unregister_group_dev); -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm) { void (*pfn)(struct kvm *kvm); From f48212ee8e78f765917dc64a7ff4bd13c7e71384 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jan 2024 11:34:25 -0500 Subject: [PATCH 248/814] treewide: remove CONFIG_HAVE_KVM It has no users anymore. Signed-off-by: Paolo Bonzini --- arch/arm64/Kconfig | 1 - arch/arm64/kvm/Kconfig | 1 - arch/loongarch/Kconfig | 1 - arch/loongarch/kvm/Kconfig | 1 - arch/mips/Kconfig | 9 --------- arch/s390/Kconfig | 1 - arch/s390/kvm/Kconfig | 1 - arch/x86/Kconfig | 1 - arch/x86/kvm/Kconfig | 2 -- virt/kvm/Kconfig | 3 --- 10 files changed, 21 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index aa7c1d435139..f86383d9c771 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -216,7 +216,6 @@ config ARM64 select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IOREMAP_PROT select HAVE_IRQ_TIME_ACCOUNTING - select HAVE_KVM select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI select HAVE_PERF_EVENTS diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 46bdbd852857..99193d3b8312 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -20,7 +20,6 @@ if VIRTUALIZATION menuconfig KVM bool "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM select KVM_COMMON select KVM_GENERIC_HARDWARE_ENABLING select KVM_GENERIC_MMU_NOTIFIER diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 929f68926b34..eb2139387a54 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -133,7 +133,6 @@ config LOONGARCH select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES - select HAVE_KVM select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI select HAVE_PCI diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index 61f7e33b1f95..ac4de790dc31 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -20,7 +20,6 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on AS_HAS_LVZ_EXTENSION - depends on HAVE_KVM select HAVE_KVM_DIRTY_RING_ACQ_REL select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_COMMON diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3eb3239013d9..cf5bb1c756e6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1262,7 +1262,6 @@ config CPU_LOONGSON64 select MIPS_FP_SUPPORT select GPIOLIB select SWIOTLB - select HAVE_KVM help The Loongson GSx64(GS264/GS464/GS464E/GS464V) series of processor cores implements the MIPS64R2 instruction set with many extensions, @@ -1375,7 +1374,6 @@ config CPU_MIPS32_R2 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA - select HAVE_KVM help Choose this option to build a kernel for release 2 or later of the MIPS32 architecture. Most modern embedded systems with a 32-bit @@ -1391,7 +1389,6 @@ config CPU_MIPS32_R5 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA select CPU_SUPPORTS_VZ - select HAVE_KVM select MIPS_O32_FP64_SUPPORT help Choose this option to build a kernel for release 5 or later of the @@ -1408,7 +1405,6 @@ config CPU_MIPS32_R6 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA select CPU_SUPPORTS_VZ - select HAVE_KVM select MIPS_O32_FP64_SUPPORT help Choose this option to build a kernel for release 6 or later of the @@ -1444,7 +1440,6 @@ config CPU_MIPS64_R2 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES select CPU_SUPPORTS_MSA - select HAVE_KVM help Choose this option to build a kernel for release 2 or later of the MIPS64 architecture. Many modern embedded systems with a 64-bit @@ -1463,7 +1458,6 @@ config CPU_MIPS64_R5 select CPU_SUPPORTS_MSA select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32 select CPU_SUPPORTS_VZ - select HAVE_KVM help Choose this option to build a kernel for release 5 or later of the MIPS64 architecture. This is a intermediate MIPS architecture @@ -1482,7 +1476,6 @@ config CPU_MIPS64_R6 select CPU_SUPPORTS_MSA select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32 select CPU_SUPPORTS_VZ - select HAVE_KVM help Choose this option to build a kernel for release 6 or later of the MIPS64 architecture. New MIPS processors, starting with the Warrior @@ -1500,7 +1493,6 @@ config CPU_P5600 select CPU_SUPPORTS_VZ select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI - select HAVE_KVM select MIPS_O32_FP64_SUPPORT help Choose this option to build a kernel for MIPS Warrior P5600 CPU. @@ -1621,7 +1613,6 @@ config CPU_CAVIUM_OCTEON select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select MIPS_L1_CACHE_SHIFT_7 select CPU_SUPPORTS_VZ - select HAVE_KVM help The Cavium Octeon processor is a highly integrated chip containing many ethernet hardware widgets for networking tasks. The processor diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index fe565f3a3a91..a6409a312747 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -193,7 +193,6 @@ config S390 select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES - select HAVE_KVM select HAVE_LIVEPATCH select HAVE_MEMBLOCK_PHYS_MAP select HAVE_MOD_ARCH_SPECIFIC diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 72e9b7dcdf7d..cae908d64550 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -19,7 +19,6 @@ if VIRTUALIZATION config KVM def_tristate y prompt "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM select HAVE_KVM_CPU_RELAX_INTERCEPT select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_ASYNC_PF diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5edec175b9bf..da140c3aed84 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -244,7 +244,6 @@ config X86 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_KRETPROBES select HAVE_RETHOOK - select HAVE_KVM select HAVE_LIVEPATCH if X86_64 select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOD_ARCH_SPECIFIC diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index e7cbf011d766..5692393b7565 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -7,7 +7,6 @@ source "virt/kvm/Kconfig" menuconfig VIRTUALIZATION bool "Virtualization" - depends on HAVE_KVM || X86 default y help Say Y here to get to see options for using your Linux host to run other @@ -20,7 +19,6 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM depends on HIGH_RES_TIMERS depends on X86_LOCAL_APIC select KVM_COMMON diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 6408bc5dacd1..aa8a7ee0f554 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -1,9 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # KVM common configuration items and defaults -config HAVE_KVM - bool - config KVM_COMMON bool select EVENTFD From 53eaeb7fbe2702520125ae7d72742362c071a1f2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:35 +0000 Subject: [PATCH 249/814] arm64: Add macro to compose a sysreg field value A common idiom is to compose a tupple (reg, field, val) into a symbol matching an autogenerated definition. Add a help performing the concatenation and replace it when open-coded implementations exist. Suggested-by: Oliver Upton Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/sysreg.h | 5 ++++- arch/arm64/kvm/sys_regs.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index c3b19b376c86..9e8999592f3a 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -1181,6 +1181,8 @@ par; \ }) +#define SYS_FIELD_VALUE(reg, field, val) reg##_##field##_##val + #define SYS_FIELD_GET(reg, field, val) \ FIELD_GET(reg##_##field##_MASK, val) @@ -1188,7 +1190,8 @@ FIELD_PREP(reg##_##field##_MASK, val) #define SYS_FIELD_PREP_ENUM(reg, field, val) \ - FIELD_PREP(reg##_##field##_MASK, reg##_##field##_##val) + FIELD_PREP(reg##_##field##_MASK, \ + SYS_FIELD_VALUE(reg, field, val)) #endif diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 30253bd19917..88b8fbeafaa0 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1685,7 +1685,8 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \ (val) &= ~reg##_##field##_MASK; \ (val) |= FIELD_PREP(reg##_##field##_MASK, \ - min(__f_val, (u64)reg##_##field##_##limit)); \ + min(__f_val, \ + (u64)SYS_FIELD_VALUE(reg, field, limit))); \ (val); \ }) From d9a065914dccce0bbd967cdef1ec21b4de545daf Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:36 +0000 Subject: [PATCH 250/814] arm64: cpufeatures: Correctly handle signed values Although we've had signed values for some features such as PMUv3 and FP, the code that handles the comparaison with some limit has a couple of annoying issues: - the min_field_value is always unsigned, meaning that we cannot easily compare it with a negative value - it is not possible to have a range of values, let alone a range of negative values Fix this by: - adding an upper limit to the comparison, defaulting to all bits being set to the maximum positive value - ensuring that the signess of the min and max values are taken into account A ARM64_CPUID_FIELDS_NEG() macro is provided for signed features, but nothing is using it yet. Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-3-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 65 +++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 21c824edf8ce..a98d95f3492b 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -363,6 +363,7 @@ struct arm64_cpu_capabilities { u8 field_pos; u8 field_width; u8 min_field_value; + u8 max_field_value; u8 hwcap_type; bool sign; unsigned long hwcap; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 8d1a634a403e..92b1546f2622 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -140,12 +140,42 @@ void dump_cpu_features(void) pr_emerg("0x%*pb\n", ARM64_NCAPS, &system_cpucaps); } +#define __ARM64_MAX_POSITIVE(reg, field) \ + ((reg##_##field##_SIGNED ? \ + BIT(reg##_##field##_WIDTH - 1) : \ + BIT(reg##_##field##_WIDTH)) - 1) + +#define __ARM64_MIN_NEGATIVE(reg, field) BIT(reg##_##field##_WIDTH - 1) + +#define __ARM64_CPUID_FIELDS(reg, field, min_value, max_value) \ + .sys_reg = SYS_##reg, \ + .field_pos = reg##_##field##_SHIFT, \ + .field_width = reg##_##field##_WIDTH, \ + .sign = reg##_##field##_SIGNED, \ + .min_field_value = min_value, \ + .max_field_value = max_value, + +/* + * ARM64_CPUID_FIELDS() encodes a field with a range from min_value to + * an implicit maximum that depends on the sign-ess of the field. + * + * An unsigned field will be capped at all ones, while a signed field + * will be limited to the positive half only. + */ #define ARM64_CPUID_FIELDS(reg, field, min_value) \ - .sys_reg = SYS_##reg, \ - .field_pos = reg##_##field##_SHIFT, \ - .field_width = reg##_##field##_WIDTH, \ - .sign = reg##_##field##_SIGNED, \ - .min_field_value = reg##_##field##_##min_value, + __ARM64_CPUID_FIELDS(reg, field, \ + SYS_FIELD_VALUE(reg, field, min_value), \ + __ARM64_MAX_POSITIVE(reg, field)) + +/* + * ARM64_CPUID_FIELDS_NEG() encodes a field with a range from an + * implicit minimal value to max_value. This should be used when + * matching a non-implemented property. + */ +#define ARM64_CPUID_FIELDS_NEG(reg, field, max_value) \ + __ARM64_CPUID_FIELDS(reg, field, \ + __ARM64_MIN_NEGATIVE(reg, field), \ + SYS_FIELD_VALUE(reg, field, max_value)) #define __ARM64_FTR_BITS(SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ { \ @@ -1451,11 +1481,28 @@ has_always(const struct arm64_cpu_capabilities *entry, int scope) static bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) { - int val = cpuid_feature_extract_field_width(reg, entry->field_pos, - entry->field_width, - entry->sign); + int val, min, max; + u64 tmp; - return val >= entry->min_field_value; + val = cpuid_feature_extract_field_width(reg, entry->field_pos, + entry->field_width, + entry->sign); + + tmp = entry->min_field_value; + tmp <<= entry->field_pos; + + min = cpuid_feature_extract_field_width(tmp, entry->field_pos, + entry->field_width, + entry->sign); + + tmp = entry->max_field_value; + tmp <<= entry->field_pos; + + max = cpuid_feature_extract_field_width(tmp, entry->field_pos, + entry->field_width, + entry->sign); + + return val >= min && val <= max; } static u64 From d42bf63fd4db20e1a7a414c2ebe257a81c8c7d6e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:37 +0000 Subject: [PATCH 251/814] arm64: cpufeature: Correctly display signed override values When a field gets overriden, the kernel indicates the result of the override in dmesg. This works well with unsigned fields, but results in a pretty ugly output when the field is signed. Truncate the field to its width before displaying it. Reviewed-by: Oliver Upton Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-4-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 92b1546f2622..bae5d0655262 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -949,7 +949,8 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new) pr_warn("%s[%d:%d]: %s to %llx\n", reg->name, ftrp->shift + ftrp->width - 1, - ftrp->shift, str, tmp); + ftrp->shift, str, + tmp & (BIT(ftrp->width) - 1)); } else if ((ftr_mask & reg->override->val) == ftr_mask) { reg->override->val &= ~ftr_mask; pr_warn("%s[%d:%d]: impossible override, ignored\n", From cfc680bb04c54e61faa51a34d8383a0aa25b583f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:38 +0000 Subject: [PATCH 252/814] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features. Add the corresponding layout. This is extracted from the public ARM SysReg_xml_A_profile-2023-09 delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717. Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Reviewed-by: Miguel Luis Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index 4c9b67934367..fa3fe0856880 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -1791,6 +1791,43 @@ UnsignedEnum 3:0 TCRX EndEnum EndSysreg +Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4 +Res0 63:40 +UnsignedEnum 39:36 E3DSE + 0b0000 NI + 0b0001 IMP +EndEnum +Res0 35:28 +SignedEnum 27:24 E2H0 + 0b0000 IMP + 0b1110 NI_NV1 + 0b1111 NI +EndEnum +UnsignedEnum 23:20 NV_frac + 0b0000 NV_NV2 + 0b0001 NV2_ONLY +EndEnum +UnsignedEnum 19:16 FGWTE3 + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 15:12 HACDBS + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 11:8 ASID2 + 0b0000 NI + 0b0001 IMP +EndEnum +SignedEnum 7:4 EIESB + 0b0000 NI + 0b0001 ToEL3 + 0b0010 ToELx + 0b1111 ANY +EndEnum +Res0 3:0 +EndSysreg + Sysreg SCTLR_EL1 3 0 1 0 0 Field 63 TIDCP Field 62 SPINTMASK From 805bb61f827997c59b92669ae8cc3740ebcf1087 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:39 +0000 Subject: [PATCH 253/814] arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling Add ID_AA64MMFR4_EL1 to the list of idregs the kernel knows about, and describe the E2H0 field. Reviewed-by: Oliver Upton Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-6-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/cpu.h | 1 + arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/kernel/cpuinfo.c | 1 + 3 files changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index b1e43f56ee46..6c13fd47e170 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -56,6 +56,7 @@ struct cpuinfo_arm64 { u64 reg_id_aa64mmfr1; u64 reg_id_aa64mmfr2; u64 reg_id_aa64mmfr3; + u64 reg_id_aa64mmfr4; u64 reg_id_aa64pfr0; u64 reg_id_aa64pfr1; u64 reg_id_aa64zfr0; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index bae5d0655262..ad3753fbdcb1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -437,6 +437,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr3[] = { ARM64_FTR_END, }; +static const struct arm64_ftr_bits ftr_id_aa64mmfr4[] = { + S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR4_EL1_E2H0_SHIFT, 4, 0), + ARM64_FTR_END, +}; + static const struct arm64_ftr_bits ftr_ctr[] = { ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_DIC_SHIFT, 1, 1), @@ -754,6 +759,7 @@ static const struct __ftr_reg_entry { &id_aa64mmfr1_override), ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2), ARM64_FTR_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3), + ARM64_FTR_REG(SYS_ID_AA64MMFR4_EL1, ftr_id_aa64mmfr4), /* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid), @@ -1078,6 +1084,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1); init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2); init_cpu_ftr_reg(SYS_ID_AA64MMFR3_EL1, info->reg_id_aa64mmfr3); + init_cpu_ftr_reg(SYS_ID_AA64MMFR4_EL1, info->reg_id_aa64mmfr4); init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0); init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1); init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0); diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 47043c0d95ec..7ca3fbd200f0 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -447,6 +447,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1); info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1); info->reg_id_aa64mmfr3 = read_cpuid(ID_AA64MMFR3_EL1); + info->reg_id_aa64mmfr4 = read_cpuid(ID_AA64MMFR4_EL1); info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1); info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1); info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1); From da9af5071b25cb81682c3506c96516fe55186577 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:40 +0000 Subject: [PATCH 254/814] arm64: cpufeature: Detect HCR_EL2.NV1 being RES0 A variant of FEAT_E2H0 not being implemented exists in the form of HCR_EL2.E2H being RES1 *and* HCR_EL2.NV1 being RES0 (indicating that only VHE is supported on the host and nested guests). Add the necessary infrastructure for this new CPU capability. Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-7-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 12 ++++++++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 13 insertions(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ad3753fbdcb1..91249d20883b 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1794,6 +1794,11 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, return !meltdown_safe; } +static bool has_nv1(const struct arm64_cpu_capabilities *entry, int scope) +{ + return !has_cpuid_feature(entry, scope); +} + #if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2) static bool has_lpa2_at_stage1(u64 mmfr0) { @@ -2794,6 +2799,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .type = ARM64_CPUCAP_SYSTEM_FEATURE, .matches = has_lpa2, }, + { + .desc = "NV1", + .capability = ARM64_HAS_HCR_NV1, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_nv1, + ARM64_CPUID_FIELDS_NEG(ID_AA64MMFR4_EL1, E2H0, NI_NV1) + }, {}, }; diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index b912b1409fc0..65090dd34641 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -35,6 +35,7 @@ HAS_GENERIC_AUTH_IMP_DEF HAS_GIC_CPUIF_SYSREGS HAS_GIC_PRIO_MASKING HAS_GIC_PRIO_RELAXED_SYNC +HAS_HCR_NV1 HAS_HCX HAS_LDAPR HAS_LPA2 From 3944382fa6f22b54fd399632b1af92c28123979b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:41 +0000 Subject: [PATCH 255/814] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative For CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we already have this path to cope with fruity CPUs. Tweak init_el2 to look at ID_AA64MMFR4_EL1.E2H0 first. Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Reviewed-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-8-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/head.S | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index cab7f91949d8..5bdafbcff009 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -584,25 +584,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) mov_q x1, INIT_SCTLR_EL1_MMU_OFF /* - * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, - * making it impossible to start in nVHE mode. Is that - * compliant with the architecture? Absolutely not! + * Compliant CPUs advertise their VHE-onlyness with + * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be + * RES1 in that case. + * + * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but + * don't advertise it (they predate this relaxation). */ + mrs_s x0, SYS_ID_AA64MMFR4_EL1 + ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH + tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f + mrs x0, hcr_el2 and x0, x0, #HCR_E2H - cbz x0, 1f - + cbz x0, 2f +1: /* Set a sane SCTLR_EL1, the VHE way */ pre_disable_mmu_workaround msr_s SYS_SCTLR_EL12, x1 mov x2, #BOOT_CPU_FLAG_E2H - b 2f + b 3f -1: +2: pre_disable_mmu_workaround msr sctlr_el1, x1 mov x2, xzr -2: +3: __init_el2_nvhe_prepare_eret mov w0, #BOOT_CPU_MODE_EL2 From c21df6e43f0ed51903738ee34cdb2ec2f978024d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:42 +0000 Subject: [PATCH 256/814] KVM: arm64: Expose ID_AA64MMFR4_EL1 to guests We can now expose ID_AA64MMFR4_EL1 to guests, and let NV guests understand that they cannot really switch HCR_EL2.E2H to 0 on some platforms. Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240122181344.258974-9-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/nested.c | 7 +++++++ arch/arm64/kvm/sys_regs.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index ba95d044bc98..d55e809e26cb 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -133,6 +133,13 @@ static u64 limit_nv_id_reg(u32 id, u64 val) val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001); break; + case SYS_ID_AA64MMFR4_EL1: + val = 0; + if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1)) + val |= FIELD_PREP(NV_FTR(MMFR4, E2H0), + ID_AA64MMFR4_EL1_E2H0_NI_NV1); + break; + case SYS_ID_AA64DFR0_EL1: /* Only limited support for PMU, Debug, BPs and WPs */ val &= (NV_FTR(DFR0, PMUVer) | diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 88b8fbeafaa0..08a9571fa809 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2350,7 +2350,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_AA64MMFR2_EL1_NV | ID_AA64MMFR2_EL1_CCIDX)), ID_SANITISED(ID_AA64MMFR3_EL1), - ID_UNALLOCATED(7,4), + ID_SANITISED(ID_AA64MMFR4_EL1), ID_UNALLOCATED(7,5), ID_UNALLOCATED(7,6), ID_UNALLOCATED(7,7), From 94f29ab2d8018c035098b58d89fc4ae36894a706 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:43 +0000 Subject: [PATCH 257/814] KVM: arm64: Force guest's HCR_EL2.E2H RES1 when NV1 is not implemented If NV1 isn't supported on a system, make sure we always evaluate the guest's HCR_EL2.E2H as RES1, irrespective of what the guest may have written there. Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240122181344.258974-10-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_emulate.h | 3 ++- arch/arm64/kvm/sys_regs.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index b804fe832184..debc3753d2ef 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -209,7 +209,8 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu) static inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt) { - return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H; + return (!cpus_have_final_cap(ARM64_HAS_HCR_NV1) || + (ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H)); } static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 08a9571fa809..041b11825578 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2175,6 +2175,16 @@ static bool access_spsr(struct kvm_vcpu *vcpu, return true; } +static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) +{ + u64 val = r->val; + + if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1)) + val |= HCR_E2H; + + return __vcpu_sys_reg(vcpu, r->reg) = val; +} + /* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 @@ -2666,7 +2676,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0), EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1), EL2_REG(ACTLR_EL2, access_rw, reset_val, 0), - EL2_REG_VNCR(HCR_EL2, reset_val, 0), + EL2_REG_VNCR(HCR_EL2, reset_hcr, 0), EL2_REG(MDCR_EL2, access_rw, reset_val, 0), EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1), EL2_REG_VNCR(HSTR_EL2, reset_val, 0), From aade38faca631f25ec2842da4094d74bb2790bd5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 22 Jan 2024 18:13:44 +0000 Subject: [PATCH 258/814] KVM: arm64: Handle Apple M2 as not having HCR_EL2.NV1 implemented Although the Apple M2 family of CPUs can have HCR_EL2.NV1 being set and clear, with the change in trap behaviour being OK, they explode spectacularily on an EL2 S1 page table using the nVHE format. This is no good. Let's pretend this HW doesn't have NV1, and move along. Signed-off-by: Marc Zyngier Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20240122181344.258974-11-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 91249d20883b..0f29ac43c7a2 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1796,7 +1796,23 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, static bool has_nv1(const struct arm64_cpu_capabilities *entry, int scope) { - return !has_cpuid_feature(entry, scope); + /* + * Although the Apple M2 family appears to support NV1, the + * PTW barfs on the nVHE EL2 S1 page table format. Pretend + * that it doesn't support NV1 at all. + */ + static const struct midr_range nv1_ni_list[] = { + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_PRO), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_PRO), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_MAX), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_MAX), + {} + }; + + return !(has_cpuid_feature(entry, scope) || + is_midr_in_range_list(read_cpuid_id(), nv1_ni_list)); } #if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2) From 18970d4f6317a3595cc592c3c7815f63d1818932 Mon Sep 17 00:00:00 2001 From: Brenton Simpson Date: Thu, 8 Feb 2024 11:13:17 -0800 Subject: [PATCH 259/814] Input: xpad - sort xpad_device by vendor and product ID This helps making sure there are no duplicate entries in the tables. Signed-off-by: Brenton Simpson Link: https://lore.kernel.org/r/20240130231903.293265-1-appsforartists@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 1a58629c12b9..153c561c6e0e 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -127,6 +127,7 @@ static const struct xpad_device { u8 mapping; u8 xtype; } xpad_device[] = { + /* Please keep this list sorted by vendor and product ID. */ { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, @@ -146,9 +147,9 @@ static const struct xpad_device { { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE }, - { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, + { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, @@ -331,7 +332,6 @@ static const struct xpad_device { { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, - { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, @@ -346,9 +346,9 @@ static const struct xpad_device { { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, - { 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, @@ -359,6 +359,7 @@ static const struct xpad_device { { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, + { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, @@ -456,6 +457,10 @@ static const signed short xpad_btn_paddles[] = { { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) } static const struct usb_device_id xpad_table[] = { + /* + * Please keep this list sorted by vendor ID. Note that there are 2 + * macros - XPAD_XBOX360_VENDOR and XPAD_XBOXONE_VENDOR. + */ { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ From a853450bf4c752e664abab0b2fad395b7ad7701c Mon Sep 17 00:00:00 2001 From: Quanyang Wang Date: Sun, 28 Jan 2024 12:29:06 +0800 Subject: [PATCH 260/814] crypto: xilinx - call finalize with bh disabled When calling crypto_finalize_request, BH should be disabled to avoid triggering the following calltrace: ------------[ cut here ]------------ WARNING: CPU: 2 PID: 74 at crypto/crypto_engine.c:58 crypto_finalize_request+0xa0/0x118 Modules linked in: cryptodev(O) CPU: 2 PID: 74 Comm: firmware:zynqmp Tainted: G O 6.8.0-rc1-yocto-standard #323 Hardware name: ZynqMP ZCU102 Rev1.0 (DT) pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : crypto_finalize_request+0xa0/0x118 lr : crypto_finalize_request+0x104/0x118 sp : ffffffc085353ce0 x29: ffffffc085353ce0 x28: 0000000000000000 x27: ffffff8808ea8688 x26: ffffffc081715038 x25: 0000000000000000 x24: ffffff880100db00 x23: ffffff880100da80 x22: 0000000000000000 x21: 0000000000000000 x20: ffffff8805b14000 x19: ffffff880100da80 x18: 0000000000010450 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: 0000000000000003 x13: 0000000000000000 x12: ffffff880100dad0 x11: 0000000000000000 x10: ffffffc0832dcd08 x9 : ffffffc0812416d8 x8 : 00000000000001f4 x7 : ffffffc0830d2830 x6 : 0000000000000001 x5 : ffffffc082091000 x4 : ffffffc082091658 x3 : 0000000000000000 x2 : ffffffc7f9653000 x1 : 0000000000000000 x0 : ffffff8802d20000 Call trace: crypto_finalize_request+0xa0/0x118 crypto_finalize_aead_request+0x18/0x30 zynqmp_handle_aes_req+0xcc/0x388 crypto_pump_work+0x168/0x2d8 kthread_worker_fn+0xfc/0x3a0 kthread+0x118/0x138 ret_from_fork+0x10/0x20 irq event stamp: 40 hardirqs last enabled at (39): [] _raw_spin_unlock_irqrestore+0x70/0xb0 hardirqs last disabled at (40): [] el1_dbg+0x28/0x90 softirqs last enabled at (36): [] kernel_neon_begin+0x8c/0xf0 softirqs last disabled at (34): [] kernel_neon_begin+0x60/0xf0 ---[ end trace 0000000000000000 ]--- Fixes: 4d96f7d48131 ("crypto: xilinx - Add Xilinx AES driver") Signed-off-by: Quanyang Wang Signed-off-by: Herbert Xu --- drivers/crypto/xilinx/zynqmp-aes-gcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c index 3c205324b22b..e61405718840 100644 --- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c +++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c @@ -231,7 +231,10 @@ static int zynqmp_handle_aes_req(struct crypto_engine *engine, err = zynqmp_aes_aead_cipher(areq); } + local_bh_disable(); crypto_finalize_aead_request(engine, areq, err); + local_bh_enable(); + return 0; } From 633eeefab69ed4bdfa3f1d375c609e87feb1c55a Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Thu, 1 Feb 2024 14:17:16 +0800 Subject: [PATCH 261/814] crypto: virtio - remove duplicate check if queue is broken virtqueue_enable_cb() will call virtqueue_poll() which will check if queue is broken at beginning, so remove the virtqueue_is_broken() call Reviewed-by: Stefan Hajnoczi Signed-off-by: Li RongQing Signed-off-by: Herbert Xu --- drivers/crypto/virtio/virtio_crypto_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index b909c6a2bf1c..6a67d70e7f1c 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -42,8 +42,6 @@ static void virtcrypto_ctrlq_callback(struct virtqueue *vq) virtio_crypto_ctrlq_callback(vc_ctrl_req); spin_lock_irqsave(&vcrypto->ctrl_lock, flags); } - if (unlikely(virtqueue_is_broken(vq))) - break; } while (!virtqueue_enable_cb(vq)); spin_unlock_irqrestore(&vcrypto->ctrl_lock, flags); } From e2b67859ab6efd4458bda1baaee20331a367d995 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 2 Feb 2024 18:53:16 +0800 Subject: [PATCH 262/814] crypto: qat - add heartbeat error simulator Add a mechanism that allows to inject a heartbeat error for testing purposes. A new attribute `inject_error` is added to debugfs for each QAT device. Upon a write on this attribute, the driver will inject an error on the device which can then be detected by the heartbeat feature. Errors are breaking the device functionality thus they require a device reset in order to be recovered. This functionality is not compiled by default, to enable it CRYPTO_DEV_QAT_ERROR_INJECTION must be set. Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Reviewed-by: Lucas Segarra Fernandez Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Signed-off-by: Mun Chun Yep Signed-off-by: Herbert Xu --- Documentation/ABI/testing/debugfs-driver-qat | 26 +++++++ drivers/crypto/intel/qat/Kconfig | 14 ++++ drivers/crypto/intel/qat/qat_common/Makefile | 2 + .../intel/qat/qat_common/adf_common_drv.h | 1 + .../intel/qat/qat_common/adf_heartbeat.c | 6 -- .../intel/qat/qat_common/adf_heartbeat.h | 18 +++++ .../qat/qat_common/adf_heartbeat_dbgfs.c | 52 +++++++++++++ .../qat/qat_common/adf_heartbeat_inject.c | 76 +++++++++++++++++++ .../intel/qat/qat_common/adf_hw_arbiter.c | 25 ++++++ 9 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c diff --git a/Documentation/ABI/testing/debugfs-driver-qat b/Documentation/ABI/testing/debugfs-driver-qat index b2db010d851e..bd6793760f29 100644 --- a/Documentation/ABI/testing/debugfs-driver-qat +++ b/Documentation/ABI/testing/debugfs-driver-qat @@ -81,3 +81,29 @@ Description: (RO) Read returns, for each Acceleration Engine (AE), the number : Number of Compress and Verify (CnV) errors and type of the last CnV error detected by Acceleration Engine N. + +What: /sys/kernel/debug/qat__/heartbeat/inject_error +Date: March 2024 +KernelVersion: 6.8 +Contact: qat-linux@intel.com +Description: (WO) Write to inject an error that simulates an heartbeat + failure. This is to be used for testing purposes. + + After writing this file, the driver stops arbitration on a + random engine and disables the fetching of heartbeat counters. + If a workload is running on the device, a job submitted to the + accelerator might not get a response and a read of the + `heartbeat/status` attribute might report -1, i.e. device + unresponsive. + The error is unrecoverable thus the device must be restarted to + restore its functionality. + + This attribute is available only when the kernel is built with + CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION=y. + + A write of 1 enables error injection. + + The following example shows how to enable error injection:: + + # cd /sys/kernel/debug/qat__ + # echo 1 > heartbeat/inject_error diff --git a/drivers/crypto/intel/qat/Kconfig b/drivers/crypto/intel/qat/Kconfig index c120f6715a09..02fb8abe4e6e 100644 --- a/drivers/crypto/intel/qat/Kconfig +++ b/drivers/crypto/intel/qat/Kconfig @@ -106,3 +106,17 @@ config CRYPTO_DEV_QAT_C62XVF To compile this as a module, choose M here: the module will be called qat_c62xvf. + +config CRYPTO_DEV_QAT_ERROR_INJECTION + bool "Support for Intel(R) QAT Devices Heartbeat Error Injection" + depends on CRYPTO_DEV_QAT + depends on DEBUG_FS + help + Enables a mechanism that allows to inject a heartbeat error on + Intel(R) QuickAssist devices for testing purposes. + + This is intended for developer use only. + If unsure, say N. + + This functionality is available via debugfs entry of the Intel(R) + QuickAssist device diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile index 6908727bff3b..5915cde8a7aa 100644 --- a/drivers/crypto/intel/qat/qat_common/Makefile +++ b/drivers/crypto/intel/qat/qat_common/Makefile @@ -53,3 +53,5 @@ intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_vf_isr.o adf_pfvf_utils.o \ adf_pfvf_pf_msg.o adf_pfvf_pf_proto.o \ adf_pfvf_vf_msg.o adf_pfvf_vf_proto.o \ adf_gen2_pfvf.o adf_gen4_pfvf.o + +intel_qat-$(CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION) += adf_heartbeat_inject.o diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index f06188033a93..0baae42deb3a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -90,6 +90,7 @@ void adf_exit_aer(void); int adf_init_arb(struct adf_accel_dev *accel_dev); void adf_exit_arb(struct adf_accel_dev *accel_dev); void adf_update_ring_arb(struct adf_etr_ring_data *ring); +int adf_disable_arb_thd(struct adf_accel_dev *accel_dev, u32 ae, u32 thr); int adf_dev_get(struct adf_accel_dev *accel_dev); void adf_dev_put(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c index 13f48d2f6da8..f88b1bc6857e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c @@ -23,12 +23,6 @@ #define ADF_HB_EMPTY_SIG 0xA5A5A5A5 -/* Heartbeat counter pair */ -struct hb_cnt_pair { - __u16 resp_heartbeat_cnt; - __u16 req_heartbeat_cnt; -}; - static int adf_hb_check_polling_freq(struct adf_accel_dev *accel_dev) { u64 curr_time = adf_clock_get_current_time(); diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h index b22e3cb29798..24c3f4f24c86 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h @@ -19,6 +19,12 @@ enum adf_device_heartbeat_status { HB_DEV_UNSUPPORTED, }; +/* Heartbeat counter pair */ +struct hb_cnt_pair { + __u16 resp_heartbeat_cnt; + __u16 req_heartbeat_cnt; +}; + struct adf_heartbeat { unsigned int hb_sent_counter; unsigned int hb_failed_counter; @@ -35,6 +41,9 @@ struct adf_heartbeat { struct dentry *cfg; struct dentry *sent; struct dentry *failed; +#ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION + struct dentry *inject_error; +#endif } dbgfs; }; @@ -51,6 +60,15 @@ void adf_heartbeat_status(struct adf_accel_dev *accel_dev, enum adf_device_heartbeat_status *hb_status); void adf_heartbeat_check_ctrs(struct adf_accel_dev *accel_dev); +#ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION +int adf_heartbeat_inject_error(struct adf_accel_dev *accel_dev); +#else +static inline int adf_heartbeat_inject_error(struct adf_accel_dev *accel_dev) +{ + return -EPERM; +} +#endif + #else static inline int adf_heartbeat_init(struct adf_accel_dev *accel_dev) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c index 2661af6a2ef6..5cd6c2d6f90a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c @@ -155,6 +155,43 @@ static const struct file_operations adf_hb_cfg_fops = { .write = adf_hb_cfg_write, }; +static ssize_t adf_hb_error_inject_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct adf_accel_dev *accel_dev = file->private_data; + size_t written_chars; + char buf[3]; + int ret; + + /* last byte left as string termination */ + if (count != 2) + return -EINVAL; + + written_chars = simple_write_to_buffer(buf, sizeof(buf) - 1, + ppos, user_buf, count); + if (buf[0] != '1') + return -EINVAL; + + ret = adf_heartbeat_inject_error(accel_dev); + if (ret) { + dev_err(&GET_DEV(accel_dev), + "Heartbeat error injection failed with status %d\n", + ret); + return ret; + } + + dev_info(&GET_DEV(accel_dev), "Heartbeat error injection enabled\n"); + + return written_chars; +} + +static const struct file_operations adf_hb_error_inject_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = adf_hb_error_inject_write, +}; + void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev) { struct adf_heartbeat *hb = accel_dev->heartbeat; @@ -171,6 +208,17 @@ void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev) &hb->hb_failed_counter, &adf_hb_stats_fops); hb->dbgfs.cfg = debugfs_create_file("config", 0600, hb->dbgfs.base_dir, accel_dev, &adf_hb_cfg_fops); + + if (IS_ENABLED(CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION)) { + struct dentry *inject_error __maybe_unused; + + inject_error = debugfs_create_file("inject_error", 0200, + hb->dbgfs.base_dir, accel_dev, + &adf_hb_error_inject_fops); +#ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION + hb->dbgfs.inject_error = inject_error; +#endif + } } EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_add); @@ -189,6 +237,10 @@ void adf_heartbeat_dbgfs_rm(struct adf_accel_dev *accel_dev) hb->dbgfs.failed = NULL; debugfs_remove(hb->dbgfs.cfg); hb->dbgfs.cfg = NULL; +#ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION + debugfs_remove(hb->dbgfs.inject_error); + hb->dbgfs.inject_error = NULL; +#endif debugfs_remove(hb->dbgfs.base_dir); hb->dbgfs.base_dir = NULL; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c new file mode 100644 index 000000000000..a3b474bdef6c --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation */ +#include + +#include "adf_admin.h" +#include "adf_common_drv.h" +#include "adf_heartbeat.h" + +#define MAX_HB_TICKS 0xFFFFFFFF + +static int adf_hb_set_timer_to_max(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + + accel_dev->heartbeat->hb_timer = 0; + + if (hw_data->stop_timer) + hw_data->stop_timer(accel_dev); + + return adf_send_admin_hb_timer(accel_dev, MAX_HB_TICKS); +} + +static void adf_set_hb_counters_fail(struct adf_accel_dev *accel_dev, u32 ae, + u32 thr) +{ + struct hb_cnt_pair *stats = accel_dev->heartbeat->dma.virt_addr; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + const size_t max_aes = hw_device->get_num_aes(hw_device); + const size_t hb_ctrs = hw_device->num_hb_ctrs; + size_t thr_id = ae * hb_ctrs + thr; + u16 num_rsp = stats[thr_id].resp_heartbeat_cnt; + + /* + * Inject live.req != live.rsp and live.rsp == last.rsp + * to trigger the heartbeat error detection + */ + stats[thr_id].req_heartbeat_cnt++; + stats += (max_aes * hb_ctrs); + stats[thr_id].resp_heartbeat_cnt = num_rsp; +} + +int adf_heartbeat_inject_error(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + const size_t max_aes = hw_device->get_num_aes(hw_device); + const size_t hb_ctrs = hw_device->num_hb_ctrs; + u32 rand, rand_ae, rand_thr; + unsigned long ae_mask; + int ret; + + ae_mask = hw_device->ae_mask; + + do { + /* Ensure we have a valid ae */ + get_random_bytes(&rand, sizeof(rand)); + rand_ae = rand % max_aes; + } while (!test_bit(rand_ae, &ae_mask)); + + get_random_bytes(&rand, sizeof(rand)); + rand_thr = rand % hb_ctrs; + + /* Increase the heartbeat timer to prevent FW updating HB counters */ + ret = adf_hb_set_timer_to_max(accel_dev); + if (ret) + return ret; + + /* Configure worker threads to stop processing any packet */ + ret = adf_disable_arb_thd(accel_dev, rand_ae, rand_thr); + if (ret) + return ret; + + /* Change HB counters memory to simulate a hang */ + adf_set_hb_counters_fail(accel_dev, rand_ae, rand_thr); + + return 0; +} diff --git a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c index da6956699246..65bd26b25abc 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c +++ b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c @@ -103,3 +103,28 @@ void adf_exit_arb(struct adf_accel_dev *accel_dev) csr_ops->write_csr_ring_srv_arb_en(csr, i, 0); } EXPORT_SYMBOL_GPL(adf_exit_arb); + +int adf_disable_arb_thd(struct adf_accel_dev *accel_dev, u32 ae, u32 thr) +{ + void __iomem *csr = accel_dev->transport->banks[0].csr_addr; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + const u32 *thd_2_arb_cfg; + struct arb_info info; + u32 ae_thr_map; + + if (ADF_AE_STRAND0_THREAD == thr || ADF_AE_STRAND1_THREAD == thr) + thr = ADF_AE_ADMIN_THREAD; + + hw_data->get_arb_info(&info); + thd_2_arb_cfg = hw_data->get_arb_mapping(accel_dev); + if (!thd_2_arb_cfg) + return -EFAULT; + + /* Disable scheduling for this particular AE and thread */ + ae_thr_map = *(thd_2_arb_cfg + ae); + ae_thr_map &= ~(GENMASK(3, 0) << (thr * BIT(2))); + + WRITE_CSR_ARB_WT2SAM(csr, info.arb_offset, info.wt2sam_offset, ae, + ae_thr_map); + return 0; +} From ae508d7afb753f7576c435226e32b9535b7f8b10 Mon Sep 17 00:00:00 2001 From: Furong Zhou Date: Fri, 2 Feb 2024 18:53:17 +0800 Subject: [PATCH 263/814] crypto: qat - add fatal error notify method Add error notify method to report a fatal error event to all the subsystems registered. In addition expose an API, adf_notify_fatal_error(), that allows to trigger a fatal error notification asynchronously in the context of a workqueue. This will be invoked when a fatal error is detected by the ISR or through Heartbeat. Signed-off-by: Furong Zhou Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Mun Chun Yep Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 30 +++++++++++++++++++ .../intel/qat/qat_common/adf_common_drv.h | 3 ++ .../crypto/intel/qat/qat_common/adf_init.c | 12 ++++++++ 3 files changed, 45 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index a39e70bd4b21..22a43b4b8315 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -8,6 +8,11 @@ #include "adf_accel_devices.h" #include "adf_common_drv.h" +struct adf_fatal_error_data { + struct adf_accel_dev *accel_dev; + struct work_struct work; +}; + static struct workqueue_struct *device_reset_wq; static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, @@ -171,6 +176,31 @@ const struct pci_error_handlers adf_err_handler = { }; EXPORT_SYMBOL_GPL(adf_err_handler); +static void adf_notify_fatal_error_worker(struct work_struct *work) +{ + struct adf_fatal_error_data *wq_data = + container_of(work, struct adf_fatal_error_data, work); + struct adf_accel_dev *accel_dev = wq_data->accel_dev; + + adf_error_notifier(accel_dev); + kfree(wq_data); +} + +int adf_notify_fatal_error(struct adf_accel_dev *accel_dev) +{ + struct adf_fatal_error_data *wq_data; + + wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC); + if (!wq_data) + return -ENOMEM; + + wq_data->accel_dev = accel_dev; + INIT_WORK(&wq_data->work, adf_notify_fatal_error_worker); + adf_misc_wq_queue_work(&wq_data->work); + + return 0; +} + int adf_init_aer(void) { device_reset_wq = alloc_workqueue("qat_device_reset_wq", diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index 0baae42deb3a..8c062d5a8db2 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -40,6 +40,7 @@ enum adf_event { ADF_EVENT_SHUTDOWN, ADF_EVENT_RESTARTING, ADF_EVENT_RESTARTED, + ADF_EVENT_FATAL_ERROR, }; struct service_hndl { @@ -60,6 +61,8 @@ int adf_dev_restart(struct adf_accel_dev *accel_dev); void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data); void adf_clean_vf_map(bool); +int adf_notify_fatal_error(struct adf_accel_dev *accel_dev); +void adf_error_notifier(struct adf_accel_dev *accel_dev); int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, struct adf_accel_dev *pf); void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c index f43ae9111553..74f0818c0703 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_init.c +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c @@ -433,6 +433,18 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev) return 0; } +void adf_error_notifier(struct adf_accel_dev *accel_dev) +{ + struct service_hndl *service; + + list_for_each_entry(service, &service_table, list) { + if (service->event_hld(accel_dev, ADF_EVENT_FATAL_ERROR)) + dev_err(&GET_DEV(accel_dev), + "Failed to send error event to %s.\n", + service->name); + } +} + static int adf_dev_shutdown_cache_cfg(struct adf_accel_dev *accel_dev) { char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; From 758a0087db98fa23a3597289dbf3643ba9db2700 Mon Sep 17 00:00:00 2001 From: Furong Zhou Date: Fri, 2 Feb 2024 18:53:18 +0800 Subject: [PATCH 264/814] crypto: qat - disable arbitration before reset Disable arbitration to avoid new requests to be processed before resetting a device. This is needed so that new requests are not fetched when an error is detected. Signed-off-by: Furong Zhou Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Mun Chun Yep Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 22a43b4b8315..acbbd32bd815 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -181,8 +181,16 @@ static void adf_notify_fatal_error_worker(struct work_struct *work) struct adf_fatal_error_data *wq_data = container_of(work, struct adf_fatal_error_data, work); struct adf_accel_dev *accel_dev = wq_data->accel_dev; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; adf_error_notifier(accel_dev); + + if (!accel_dev->is_vf) { + /* Disable arbitration to stop processing of new requests */ + if (hw_device->exit_arb) + hw_device->exit_arb(accel_dev); + } + kfree(wq_data); } From ec26f8e6c784ae391e69b19f4738d7196ed7794d Mon Sep 17 00:00:00 2001 From: Mun Chun Yep Date: Fri, 2 Feb 2024 18:53:19 +0800 Subject: [PATCH 265/814] crypto: qat - update PFVF protocol for recovery Update the PFVF logic to handle restart and recovery. This adds the following functions: * adf_pf2vf_notify_fatal_error(): allows the PF to notify VFs that the device detected a fatal error and requires a reset. This sends to VF the event `ADF_PF2VF_MSGTYPE_FATAL_ERROR`. * adf_pf2vf_wait_for_restarting_complete(): allows the PF to wait for `ADF_VF2PF_MSGTYPE_RESTARTING_COMPLETE` events from active VFs before proceeding with a reset. * adf_pf2vf_notify_restarted(): enables the PF to notify VFs with an `ADF_PF2VF_MSGTYPE_RESTARTED` event after recovery, indicating that the device is back to normal. This prompts VF drivers switch back to use the accelerator for workload processing. These changes improve the communication and synchronization between PF and VF drivers during system restart and recovery processes. Signed-off-by: Mun Chun Yep Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../intel/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/intel/qat/qat_common/adf_aer.c | 3 + .../intel/qat/qat_common/adf_pfvf_msg.h | 7 +- .../intel/qat/qat_common/adf_pfvf_pf_msg.c | 64 ++++++++++++++++++- .../intel/qat/qat_common/adf_pfvf_pf_msg.h | 21 ++++++ .../intel/qat/qat_common/adf_pfvf_pf_proto.c | 8 +++ .../intel/qat/qat_common/adf_pfvf_vf_proto.c | 6 ++ .../crypto/intel/qat/qat_common/adf_sriov.c | 1 + 8 files changed, 109 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index a16c7e6edc65..4a3c36aaa7ca 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -332,6 +332,7 @@ struct adf_accel_vf_info { struct ratelimit_state vf2pf_ratelimit; u32 vf_nr; bool init; + bool restarting; u8 vf_compat_ver; }; diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index acbbd32bd815..ecb114e1b59f 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -7,6 +7,7 @@ #include #include "adf_accel_devices.h" #include "adf_common_drv.h" +#include "adf_pfvf_pf_msg.h" struct adf_fatal_error_data { struct adf_accel_dev *accel_dev; @@ -189,6 +190,8 @@ static void adf_notify_fatal_error_worker(struct work_struct *work) /* Disable arbitration to stop processing of new requests */ if (hw_device->exit_arb) hw_device->exit_arb(accel_dev); + if (accel_dev->pf.vf_info) + adf_pf2vf_notify_fatal_error(accel_dev); } kfree(wq_data); diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_msg.h b/drivers/crypto/intel/qat/qat_common/adf_pfvf_msg.h index 204a42438992..d1b3ef9cadac 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_msg.h +++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_msg.h @@ -99,6 +99,8 @@ enum pf2vf_msgtype { ADF_PF2VF_MSGTYPE_RESTARTING = 0x01, ADF_PF2VF_MSGTYPE_VERSION_RESP = 0x02, ADF_PF2VF_MSGTYPE_BLKMSG_RESP = 0x03, + ADF_PF2VF_MSGTYPE_FATAL_ERROR = 0x04, + ADF_PF2VF_MSGTYPE_RESTARTED = 0x05, /* Values from 0x10 are Gen4 specific, message type is only 4 bits in Gen2 devices. */ ADF_PF2VF_MSGTYPE_RP_RESET_RESP = 0x10, }; @@ -112,6 +114,7 @@ enum vf2pf_msgtype { ADF_VF2PF_MSGTYPE_LARGE_BLOCK_REQ = 0x07, ADF_VF2PF_MSGTYPE_MEDIUM_BLOCK_REQ = 0x08, ADF_VF2PF_MSGTYPE_SMALL_BLOCK_REQ = 0x09, + ADF_VF2PF_MSGTYPE_RESTARTING_COMPLETE = 0x0a, /* Values from 0x10 are Gen4 specific, message type is only 4 bits in Gen2 devices. */ ADF_VF2PF_MSGTYPE_RP_RESET = 0x10, }; @@ -124,8 +127,10 @@ enum pfvf_compatibility_version { ADF_PFVF_COMPAT_FAST_ACK = 0x03, /* Ring to service mapping support for non-standard mappings */ ADF_PFVF_COMPAT_RING_TO_SVC_MAP = 0x04, + /* Fallback compat */ + ADF_PFVF_COMPAT_FALLBACK = 0x05, /* Reference to the latest version */ - ADF_PFVF_COMPAT_THIS_VERSION = 0x04, + ADF_PFVF_COMPAT_THIS_VERSION = 0x05, }; /* PF->VF Version Response */ diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.c index 14c069f0d71a..0e31f4b41844 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.c @@ -1,21 +1,83 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) /* Copyright(c) 2015 - 2021 Intel Corporation */ +#include #include #include "adf_accel_devices.h" #include "adf_pfvf_msg.h" #include "adf_pfvf_pf_msg.h" #include "adf_pfvf_pf_proto.h" +#define ADF_PF_WAIT_RESTARTING_COMPLETE_DELAY 100 +#define ADF_VF_SHUTDOWN_RETRY 100 + void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) { struct adf_accel_vf_info *vf; struct pfvf_message msg = { .type = ADF_PF2VF_MSGTYPE_RESTARTING }; int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + dev_dbg(&GET_DEV(accel_dev), "pf2vf notify restarting\n"); for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { - if (vf->init && adf_send_pf2vf_msg(accel_dev, i, msg)) + vf->restarting = false; + if (!vf->init) + continue; + if (adf_send_pf2vf_msg(accel_dev, i, msg)) dev_err(&GET_DEV(accel_dev), "Failed to send restarting msg to VF%d\n", i); + else if (vf->vf_compat_ver >= ADF_PFVF_COMPAT_FALLBACK) + vf->restarting = true; + } +} + +void adf_pf2vf_wait_for_restarting_complete(struct adf_accel_dev *accel_dev) +{ + int num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + int i, retries = ADF_VF_SHUTDOWN_RETRY; + struct adf_accel_vf_info *vf; + bool vf_running; + + dev_dbg(&GET_DEV(accel_dev), "pf2vf wait for restarting complete\n"); + do { + vf_running = false; + for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) + if (vf->restarting) + vf_running = true; + if (!vf_running) + break; + msleep(ADF_PF_WAIT_RESTARTING_COMPLETE_DELAY); + } while (--retries); + + if (vf_running) + dev_warn(&GET_DEV(accel_dev), "Some VFs are still running\n"); +} + +void adf_pf2vf_notify_restarted(struct adf_accel_dev *accel_dev) +{ + struct pfvf_message msg = { .type = ADF_PF2VF_MSGTYPE_RESTARTED }; + int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + struct adf_accel_vf_info *vf; + + dev_dbg(&GET_DEV(accel_dev), "pf2vf notify restarted\n"); + for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { + if (vf->init && vf->vf_compat_ver >= ADF_PFVF_COMPAT_FALLBACK && + adf_send_pf2vf_msg(accel_dev, i, msg)) + dev_err(&GET_DEV(accel_dev), + "Failed to send restarted msg to VF%d\n", i); + } +} + +void adf_pf2vf_notify_fatal_error(struct adf_accel_dev *accel_dev) +{ + struct pfvf_message msg = { .type = ADF_PF2VF_MSGTYPE_FATAL_ERROR }; + int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + struct adf_accel_vf_info *vf; + + dev_dbg(&GET_DEV(accel_dev), "pf2vf notify fatal error\n"); + for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { + if (vf->init && vf->vf_compat_ver >= ADF_PFVF_COMPAT_FALLBACK && + adf_send_pf2vf_msg(accel_dev, i, msg)) + dev_err(&GET_DEV(accel_dev), + "Failed to send fatal error msg to VF%d\n", i); } } diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.h b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.h index e8982d1ac896..f203d88c919c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.h +++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_msg.h @@ -5,7 +5,28 @@ #include "adf_accel_devices.h" +#if defined(CONFIG_PCI_IOV) void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev); +void adf_pf2vf_wait_for_restarting_complete(struct adf_accel_dev *accel_dev); +void adf_pf2vf_notify_restarted(struct adf_accel_dev *accel_dev); +void adf_pf2vf_notify_fatal_error(struct adf_accel_dev *accel_dev); +#else +static inline void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) +{ +} + +static inline void adf_pf2vf_wait_for_restarting_complete(struct adf_accel_dev *accel_dev) +{ +} + +static inline void adf_pf2vf_notify_restarted(struct adf_accel_dev *accel_dev) +{ +} + +static inline void adf_pf2vf_notify_fatal_error(struct adf_accel_dev *accel_dev) +{ +} +#endif typedef int (*adf_pf2vf_blkmsg_provider)(struct adf_accel_dev *accel_dev, u8 *buffer, u8 compat); diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c index 388e58bcbcaf..9ab93fbfefde 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c @@ -291,6 +291,14 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, vf_info->init = false; } break; + case ADF_VF2PF_MSGTYPE_RESTARTING_COMPLETE: + { + dev_dbg(&GET_DEV(accel_dev), + "Restarting Complete received from VF%d\n", vf_nr); + vf_info->restarting = false; + vf_info->init = false; + } + break; case ADF_VF2PF_MSGTYPE_LARGE_BLOCK_REQ: case ADF_VF2PF_MSGTYPE_MEDIUM_BLOCK_REQ: case ADF_VF2PF_MSGTYPE_SMALL_BLOCK_REQ: diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_vf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_vf_proto.c index 1015155b6374..dc284a089c88 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_vf_proto.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_vf_proto.c @@ -308,6 +308,12 @@ static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, adf_pf2vf_handle_pf_restarting(accel_dev); return false; + case ADF_PF2VF_MSGTYPE_RESTARTED: + dev_dbg(&GET_DEV(accel_dev), "Restarted message received from PF\n"); + return true; + case ADF_PF2VF_MSGTYPE_FATAL_ERROR: + dev_err(&GET_DEV(accel_dev), "Fatal error received from PF\n"); + return true; case ADF_PF2VF_MSGTYPE_VERSION_RESP: case ADF_PF2VF_MSGTYPE_BLKMSG_RESP: case ADF_PF2VF_MSGTYPE_RP_RESET_RESP: diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c index f44025bb6f99..cb2a9830f192 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c @@ -103,6 +103,7 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) return; adf_pf2vf_notify_restarting(accel_dev); + adf_pf2vf_wait_for_restarting_complete(accel_dev); pci_disable_sriov(accel_to_pci_dev(accel_dev)); /* Disable VF to PF interrupts */ From 4469f9b2346834085fe4478ee1a851ee1de8ccb2 Mon Sep 17 00:00:00 2001 From: Mun Chun Yep Date: Fri, 2 Feb 2024 18:53:20 +0800 Subject: [PATCH 266/814] crypto: qat - re-enable sriov after pf reset When a Physical Function (PF) is reset, SR-IOV gets disabled, making the associated Virtual Functions (VFs) unavailable. Even after reset and using pci_restore_state, VFs remain uncreated because the numvfs still at 0. Therefore, it's necessary to reconfigure SR-IOV to re-enable VFs. This commit introduces the ADF_SRIOV_ENABLED configuration flag to cache the SR-IOV enablement state. SR-IOV is only re-enabled if it was previously configured. This commit also introduces a dedicated workqueue without `WQ_MEM_RECLAIM` flag for enabling SR-IOV during Heartbeat and CPM error resets, preventing workqueue flushing warning. This patch is based on earlier work done by Shashank Gupta. Signed-off-by: Mun Chun Yep Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 40 ++++++++++++++++++- .../intel/qat/qat_common/adf_cfg_strings.h | 1 + .../intel/qat/qat_common/adf_common_drv.h | 5 +++ .../crypto/intel/qat/qat_common/adf_sriov.c | 37 +++++++++++++++-- 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index ecb114e1b59f..cd273b31db0e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -15,6 +15,7 @@ struct adf_fatal_error_data { }; static struct workqueue_struct *device_reset_wq; +static struct workqueue_struct *device_sriov_wq; static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, pci_channel_state_t state) @@ -43,6 +44,13 @@ struct adf_reset_dev_data { struct work_struct reset_work; }; +/* sriov dev data */ +struct adf_sriov_dev_data { + struct adf_accel_dev *accel_dev; + struct completion compl; + struct work_struct sriov_work; +}; + void adf_reset_sbr(struct adf_accel_dev *accel_dev) { struct pci_dev *pdev = accel_to_pci_dev(accel_dev); @@ -88,11 +96,22 @@ void adf_dev_restore(struct adf_accel_dev *accel_dev) } } +static void adf_device_sriov_worker(struct work_struct *work) +{ + struct adf_sriov_dev_data *sriov_data = + container_of(work, struct adf_sriov_dev_data, sriov_work); + + adf_reenable_sriov(sriov_data->accel_dev); + complete(&sriov_data->compl); +} + static void adf_device_reset_worker(struct work_struct *work) { struct adf_reset_dev_data *reset_data = container_of(work, struct adf_reset_dev_data, reset_work); struct adf_accel_dev *accel_dev = reset_data->accel_dev; + unsigned long wait_jiffies = msecs_to_jiffies(10000); + struct adf_sriov_dev_data sriov_data; adf_dev_restarting_notify(accel_dev); if (adf_dev_restart(accel_dev)) { @@ -103,6 +122,14 @@ static void adf_device_reset_worker(struct work_struct *work) WARN(1, "QAT: device restart failed. Device is unusable\n"); return; } + + sriov_data.accel_dev = accel_dev; + init_completion(&sriov_data.compl); + INIT_WORK(&sriov_data.sriov_work, adf_device_sriov_worker); + queue_work(device_sriov_wq, &sriov_data.sriov_work); + if (wait_for_completion_timeout(&sriov_data.compl, wait_jiffies)) + adf_pf2vf_notify_restarted(accel_dev); + adf_dev_restarted_notify(accel_dev); clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); @@ -216,7 +243,14 @@ int adf_init_aer(void) { device_reset_wq = alloc_workqueue("qat_device_reset_wq", WQ_MEM_RECLAIM, 0); - return !device_reset_wq ? -EFAULT : 0; + if (!device_reset_wq) + return -EFAULT; + + device_sriov_wq = alloc_workqueue("qat_device_sriov_wq", 0, 0); + if (!device_sriov_wq) + return -EFAULT; + + return 0; } void adf_exit_aer(void) @@ -224,4 +258,8 @@ void adf_exit_aer(void) if (device_reset_wq) destroy_workqueue(device_reset_wq); device_reset_wq = NULL; + + if (device_sriov_wq) + destroy_workqueue(device_sriov_wq); + device_sriov_wq = NULL; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h index 322b76903a73..e015ad6cace2 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h @@ -49,5 +49,6 @@ ADF_ETRMGR_BANK "%d" ADF_ETRMGR_CORE_AFFINITY #define ADF_ACCEL_STR "Accelerator%d" #define ADF_HEARTBEAT_TIMER "HeartbeatTimer" +#define ADF_SRIOV_ENABLED "SriovEnabled" #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index 8c062d5a8db2..10891c9da6e7 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -192,6 +192,7 @@ bool adf_misc_wq_queue_delayed_work(struct delayed_work *work, #if defined(CONFIG_PCI_IOV) int adf_sriov_configure(struct pci_dev *pdev, int numvfs); void adf_disable_sriov(struct adf_accel_dev *accel_dev); +void adf_reenable_sriov(struct adf_accel_dev *accel_dev); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev); bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev); @@ -212,6 +213,10 @@ static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev) { } +static inline void adf_reenable_sriov(struct adf_accel_dev *accel_dev) +{ +} + static inline int adf_init_pf_wq(void) { return 0; diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c index cb2a9830f192..87a70c00c41e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c @@ -60,7 +60,6 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) /* This ptr will be populated when VFs will be created */ vf_info->accel_dev = accel_dev; vf_info->vf_nr = i; - vf_info->vf_compat_ver = 0; mutex_init(&vf_info->pf2vf_lock); ratelimit_state_init(&vf_info->vf2pf_ratelimit, @@ -84,6 +83,32 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) return pci_enable_sriov(pdev, totalvfs); } +void adf_reenable_sriov(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + char cfg[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; + unsigned long val = 0; + + if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, + ADF_SRIOV_ENABLED, cfg)) + return; + + if (!accel_dev->pf.vf_info) + return; + + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, + &val, ADF_DEC)) + return; + + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, + &val, ADF_DEC)) + return; + + set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); + dev_dbg(&pdev->dev, "Re-enabling SRIOV\n"); + adf_enable_sriov(accel_dev); +} + /** * adf_disable_sriov() - Disable SRIOV for the device * @accel_dev: Pointer to accel device. @@ -116,8 +141,10 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) for (i = 0, vf = accel_dev->pf.vf_info; i < totalvfs; i++, vf++) mutex_destroy(&vf->pf2vf_lock); - kfree(accel_dev->pf.vf_info); - accel_dev->pf.vf_info = NULL; + if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) { + kfree(accel_dev->pf.vf_info); + accel_dev->pf.vf_info = NULL; + } } EXPORT_SYMBOL_GPL(adf_disable_sriov); @@ -195,6 +222,10 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs) if (ret) return ret; + val = 1; + adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC, ADF_SRIOV_ENABLED, + &val, ADF_DEC); + return numvfs; } EXPORT_SYMBOL_GPL(adf_sriov_configure); From 2aaa1995a94a3187e52ddb9f127fa1307ee8ad00 Mon Sep 17 00:00:00 2001 From: Mun Chun Yep Date: Fri, 2 Feb 2024 18:53:21 +0800 Subject: [PATCH 267/814] crypto: qat - add fatal error notification Notify a fatal error condition and optionally reset the device in the following cases: * if the device reports an uncorrectable fatal error through an interrupt * if the heartbeat feature detects that the device is not responding This patch is based on earlier work done by Shashank Gupta. Signed-off-by: Mun Chun Yep Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_heartbeat.c | 3 +++ drivers/crypto/intel/qat/qat_common/adf_isr.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c index f88b1bc6857e..fe8428d4ff39 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c @@ -229,6 +229,9 @@ void adf_heartbeat_status(struct adf_accel_dev *accel_dev, "Heartbeat ERROR: QAT is not responding.\n"); *hb_status = HB_DEV_UNRESPONSIVE; hb->hb_failed_counter++; + if (adf_notify_fatal_error(accel_dev)) + dev_err(&GET_DEV(accel_dev), + "Failed to notify fatal error\n"); return; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c index a13d9885d60f..020d213f4c99 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c @@ -139,8 +139,13 @@ static bool adf_handle_ras_int(struct adf_accel_dev *accel_dev) if (ras_ops->handle_interrupt && ras_ops->handle_interrupt(accel_dev, &reset_required)) { - if (reset_required) + if (reset_required) { dev_err(&GET_DEV(accel_dev), "Fatal error, reset required\n"); + if (adf_notify_fatal_error(accel_dev)) + dev_err(&GET_DEV(accel_dev), + "Failed to notify fatal error\n"); + } + return true; } From f5419a4239af8b3951f990c83d0d8c865a485475 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 2 Feb 2024 18:53:22 +0800 Subject: [PATCH 268/814] crypto: qat - add auto reset on error Expose the `auto_reset` sysfs attribute to configure the driver to reset the device when a fatal error is detected. When auto reset is enabled, the driver resets the device when it detects either an heartbeat failure or a fatal error through an interrupt. This patch is based on earlier work done by Shashank Gupta. Signed-off-by: Damian Muszynski Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Mun Chun Yep Signed-off-by: Herbert Xu --- Documentation/ABI/testing/sysfs-driver-qat | 20 ++++++++++ .../intel/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/intel/qat/qat_common/adf_aer.c | 11 +++++- .../intel/qat/qat_common/adf_common_drv.h | 1 + .../crypto/intel/qat/qat_common/adf_sysfs.c | 37 +++++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-qat b/Documentation/ABI/testing/sysfs-driver-qat index bbf329cf0d67..6778f1fea874 100644 --- a/Documentation/ABI/testing/sysfs-driver-qat +++ b/Documentation/ABI/testing/sysfs-driver-qat @@ -141,3 +141,23 @@ Description: 64 This attribute is only available for qat_4xxx devices. + +What: /sys/bus/pci/devices//qat/auto_reset +Date: March 2024 +KernelVersion: 6.8 +Contact: qat-linux@intel.com +Description: (RW) Reports the current state of the autoreset feature + for a QAT device + + Write to the attribute to enable or disable device auto reset. + + Device auto reset is disabled by default. + + The values are:: + + * 1/Yy/on: auto reset enabled. If the device encounters an + unrecoverable error, it will be reset automatically. + * 0/Nn/off: auto reset disabled. If the device encounters an + unrecoverable error, it will not be reset. + + This attribute is only available for qat_4xxx devices. diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index 4a3c36aaa7ca..0f26aa976c8c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -402,6 +402,7 @@ struct adf_accel_dev { struct adf_error_counters ras_errors; struct mutex state_lock; /* protect state of the device */ bool is_vf; + bool autoreset_on_error; u32 accel_id; }; #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index cd273b31db0e..b3d4b6b99c65 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -204,6 +204,14 @@ const struct pci_error_handlers adf_err_handler = { }; EXPORT_SYMBOL_GPL(adf_err_handler); +int adf_dev_autoreset(struct adf_accel_dev *accel_dev) +{ + if (accel_dev->autoreset_on_error) + return adf_dev_aer_schedule_reset(accel_dev, ADF_DEV_RESET_ASYNC); + + return 0; +} + static void adf_notify_fatal_error_worker(struct work_struct *work) { struct adf_fatal_error_data *wq_data = @@ -215,10 +223,11 @@ static void adf_notify_fatal_error_worker(struct work_struct *work) if (!accel_dev->is_vf) { /* Disable arbitration to stop processing of new requests */ - if (hw_device->exit_arb) + if (accel_dev->autoreset_on_error && hw_device->exit_arb) hw_device->exit_arb(accel_dev); if (accel_dev->pf.vf_info) adf_pf2vf_notify_fatal_error(accel_dev); + adf_dev_autoreset(accel_dev); } kfree(wq_data); diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index 10891c9da6e7..57328249c89e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -87,6 +87,7 @@ int adf_ae_stop(struct adf_accel_dev *accel_dev); extern const struct pci_error_handlers adf_err_handler; void adf_reset_sbr(struct adf_accel_dev *accel_dev); void adf_reset_flr(struct adf_accel_dev *accel_dev); +int adf_dev_autoreset(struct adf_accel_dev *accel_dev); void adf_dev_restore(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c index d450dad32c9e..4e7f70d4049d 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c @@ -204,6 +204,42 @@ static ssize_t pm_idle_enabled_store(struct device *dev, struct device_attribute } static DEVICE_ATTR_RW(pm_idle_enabled); +static ssize_t auto_reset_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + char *auto_reset; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + auto_reset = accel_dev->autoreset_on_error ? "on" : "off"; + + return sysfs_emit(buf, "%s\n", auto_reset); +} + +static ssize_t auto_reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_accel_dev *accel_dev; + bool enabled = false; + int ret; + + ret = kstrtobool(buf, &enabled); + if (ret) + return ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + accel_dev->autoreset_on_error = enabled; + + return count; +} +static DEVICE_ATTR_RW(auto_reset); + static DEVICE_ATTR_RW(state); static DEVICE_ATTR_RW(cfg_services); @@ -291,6 +327,7 @@ static struct attribute *qat_attrs[] = { &dev_attr_pm_idle_enabled.attr, &dev_attr_rp2srv.attr, &dev_attr_num_rps.attr, + &dev_attr_auto_reset.attr, NULL, }; From 750fa7c20e60926431ec50d63899771ffcd9fd5c Mon Sep 17 00:00:00 2001 From: Furong Zhou Date: Fri, 2 Feb 2024 18:53:23 +0800 Subject: [PATCH 269/814] crypto: qat - limit heartbeat notifications When the driver detects an heartbeat failure, it starts the recovery flow. Set a limit so that the number of events is limited in case the heartbeat status is read too frequently. Signed-off-by: Furong Zhou Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Mun Chun Yep Signed-off-by: Herbert Xu --- .../crypto/intel/qat/qat_common/adf_heartbeat.c | 17 ++++++++++++++--- .../crypto/intel/qat/qat_common/adf_heartbeat.h | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c index fe8428d4ff39..b19aa1ef8eee 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c @@ -205,6 +205,19 @@ static int adf_hb_get_status(struct adf_accel_dev *accel_dev) return ret; } +static void adf_heartbeat_reset(struct adf_accel_dev *accel_dev) +{ + u64 curr_time = adf_clock_get_current_time(); + u64 time_since_reset = curr_time - accel_dev->heartbeat->last_hb_reset_time; + + if (time_since_reset < ADF_CFG_HB_RESET_MS) + return; + + accel_dev->heartbeat->last_hb_reset_time = curr_time; + if (adf_notify_fatal_error(accel_dev)) + dev_err(&GET_DEV(accel_dev), "Failed to notify fatal error\n"); +} + void adf_heartbeat_status(struct adf_accel_dev *accel_dev, enum adf_device_heartbeat_status *hb_status) { @@ -229,9 +242,7 @@ void adf_heartbeat_status(struct adf_accel_dev *accel_dev, "Heartbeat ERROR: QAT is not responding.\n"); *hb_status = HB_DEV_UNRESPONSIVE; hb->hb_failed_counter++; - if (adf_notify_fatal_error(accel_dev)) - dev_err(&GET_DEV(accel_dev), - "Failed to notify fatal error\n"); + adf_heartbeat_reset(accel_dev); return; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h index 24c3f4f24c86..16fdfb48b196 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h @@ -13,6 +13,8 @@ struct dentry; #define ADF_CFG_HB_TIMER_DEFAULT_MS 500 #define ADF_CFG_HB_COUNT_THRESHOLD 3 +#define ADF_CFG_HB_RESET_MS 5000 + enum adf_device_heartbeat_status { HB_DEV_UNRESPONSIVE = 0, HB_DEV_ALIVE, @@ -30,6 +32,7 @@ struct adf_heartbeat { unsigned int hb_failed_counter; unsigned int hb_timer; u64 last_hb_check_time; + u64 last_hb_reset_time; bool ctrs_cnt_checked; struct hb_dma_addr { dma_addr_t phy_addr; From 9567d3dc760931afc38f7f1144c66dd8c4b8c680 Mon Sep 17 00:00:00 2001 From: Mun Chun Yep Date: Fri, 2 Feb 2024 18:53:24 +0800 Subject: [PATCH 270/814] crypto: qat - improve aer error reset handling Rework the AER reset and recovery flow to take into account root port integrated devices that gets reset between the error detected and the slot reset callbacks. In adf_error_detected() the devices is gracefully shut down. The worker threads are disabled, the error conditions are notified to listeners and through PFVF comms and finally the device is reset as part of adf_dev_down(). In adf_slot_reset(), the device is brought up again. If SRIOV VFs were enabled before reset, these are re-enabled and VFs are notified of restarting through PFVF comms. Signed-off-by: Mun Chun Yep Reviewed-by: Ahsan Atta Reviewed-by: Markas Rapoportas Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index b3d4b6b99c65..3597e7605a14 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -33,6 +33,19 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; } + set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); + if (accel_dev->hw_device->exit_arb) { + dev_dbg(&pdev->dev, "Disabling arbitration\n"); + accel_dev->hw_device->exit_arb(accel_dev); + } + adf_error_notifier(accel_dev); + adf_pf2vf_notify_fatal_error(accel_dev); + adf_dev_restarting_notify(accel_dev); + adf_pf2vf_notify_restarting(accel_dev); + adf_pf2vf_wait_for_restarting_complete(accel_dev); + pci_clear_master(pdev); + adf_dev_down(accel_dev, false); + return PCI_ERS_RESULT_NEED_RESET; } @@ -180,14 +193,25 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) { struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + int res = 0; if (!accel_dev) { pr_err("QAT: Can't find acceleration device\n"); return PCI_ERS_RESULT_DISCONNECT; } - if (adf_dev_aer_schedule_reset(accel_dev, ADF_DEV_RESET_SYNC)) + + if (!pdev->is_busmaster) + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + res = adf_dev_up(accel_dev, false); + if (res && res != -EALREADY) return PCI_ERS_RESULT_DISCONNECT; + adf_reenable_sriov(accel_dev); + adf_pf2vf_notify_restarted(accel_dev); + adf_dev_restarted_notify(accel_dev); + clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); return PCI_ERS_RESULT_RECOVERED; } From e8829ef1f73fa4051a936ab9f0204195dae4ef2b Mon Sep 17 00:00:00 2001 From: Joachim Vandersmissen Date: Sat, 3 Feb 2024 01:19:59 -0600 Subject: [PATCH 271/814] crypto: rsa - restrict plaintext/ciphertext values more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SP 800-56Br2, Section 7.1.1 [1] specifies that: 1. If m does not satisfy 1 < m < (n – 1), output an indication that m is out of range, and exit without further processing. Similarly, Section 7.1.2 of the same standard specifies that: 1. If the ciphertext c does not satisfy 1 < c < (n – 1), output an indication that the ciphertext is out of range, and exit without further processing. This range is slightly more conservative than RFC3447, as it also excludes RSA fixed points 0, 1, and n - 1. [1] https://doi.org/10.6028/NIST.SP.800-56Br2 Signed-off-by: Joachim Vandersmissen Signed-off-by: Herbert Xu --- crypto/rsa.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/crypto/rsa.c b/crypto/rsa.c index b9cd11fb7d36..d9be9e86097e 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -24,14 +24,38 @@ struct rsa_mpi_key { MPI qinv; }; +static int rsa_check_payload(MPI x, MPI n) +{ + MPI n1; + + if (mpi_cmp_ui(x, 1) <= 0) + return -EINVAL; + + n1 = mpi_alloc(0); + if (!n1) + return -ENOMEM; + + if (mpi_sub_ui(n1, n, 1) || mpi_cmp(x, n1) >= 0) { + mpi_free(n1); + return -EINVAL; + } + + mpi_free(n1); + return 0; +} + /* * RSAEP function [RFC3447 sec 5.1.1] * c = m^e mod n; */ static int _rsa_enc(const struct rsa_mpi_key *key, MPI c, MPI m) { - /* (1) Validate 0 <= m < n */ - if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0) + /* + * Even though (1) in RFC3447 only requires 0 <= m <= n - 1, we are + * slightly more conservative and require 1 < m < n - 1. This is in line + * with SP 800-56Br2, Section 7.1.1. + */ + if (rsa_check_payload(m, key->n)) return -EINVAL; /* (2) c = m^e mod n */ @@ -50,8 +74,12 @@ static int _rsa_dec_crt(const struct rsa_mpi_key *key, MPI m_or_m1_or_h, MPI c) MPI m2, m12_or_qh; int ret = -ENOMEM; - /* (1) Validate 0 <= c < n */ - if (mpi_cmp_ui(c, 0) < 0 || mpi_cmp(c, key->n) >= 0) + /* + * Even though (1) in RFC3447 only requires 0 <= c <= n - 1, we are + * slightly more conservative and require 1 < c < n - 1. This is in line + * with SP 800-56Br2, Section 7.1.2. + */ + if (rsa_check_payload(c, key->n)) return -EINVAL; m2 = mpi_alloc(0); From 0f82d108028a9dfea20e1c3c0ada1e64403002af Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 8 Feb 2024 12:01:00 -0800 Subject: [PATCH 272/814] Input: ti_am335x_tsc - remove redundant assignment to variable config The variable config is being initialized with a value that is never read, it is being re-assigned in the next statement. The initialization is redundant and can be removed. Cleans up clang scan build warning: drivers/input/touchscreen/ti_am335x_tsc.c:160:2: warning: Value stored to 'config' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240205215940.1851349-1-colin.i.king@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ti_am335x_tsc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 34324f8512ac..294b7ceded27 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -157,7 +157,6 @@ static void titsc_step_config(struct titsc *ts_dev) n++ == 0 ? STEPCONFIG_OPENDLY : 0); } - config = 0; config = STEPCONFIG_MODE_HWSYNC | STEPCONFIG_AVG_16 | ts_dev->bit_yn | STEPCONFIG_INM_ADCREFM; From 87b8cf2387c5ee79576988b2e72b84eeb92c57ec Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 12 Feb 2024 14:47:35 +0000 Subject: [PATCH 273/814] arm64: cpufeatures: Add missing ID_AA64MMFR4_EL1 to __read_sysreg_by_encoding() When triggering a CPU hotplug scenario, we reparse the CPU feature with SCOPE_LOCAL_CPU, for which we use __read_sysreg_by_encoding() to get the HW value for this CPU. As it turns out, we're missing the handling for ID_AA64MMFR4_EL1, and trigger a BUG(). Funnily enough, Marek isn't completely happy about that. Add the damn register to the list. Fixes: 805bb61f8279 ("arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling") Reported-by: Marek Szyprowski Tested-by: Marek Szyprowski Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240212144736.1933112-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 0f29ac43c7a2..2f8958f27e9e 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1456,6 +1456,7 @@ u64 __read_sysreg_by_encoding(u32 sys_id) read_sysreg_case(SYS_ID_AA64MMFR1_EL1); read_sysreg_case(SYS_ID_AA64MMFR2_EL1); read_sysreg_case(SYS_ID_AA64MMFR3_EL1); + read_sysreg_case(SYS_ID_AA64MMFR4_EL1); read_sysreg_case(SYS_ID_AA64ISAR0_EL1); read_sysreg_case(SYS_ID_AA64ISAR1_EL1); read_sysreg_case(SYS_ID_AA64ISAR2_EL1); From 3673d01a2f555603cbf756874c7388b76bfbc967 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 12 Feb 2024 14:47:36 +0000 Subject: [PATCH 274/814] arm64: cpufeatures: Only check for NV1 if NV is present We handle ID_AA64MMFR4_EL1.E2H0 being 0 as NV1 being present. However, this is only true if FEAT_NV is implemented. Add the required check to has_nv1(), avoiding spuriously advertising NV1 on HW that doesn't have NV at all. Fixes: da9af5071b25 ("arm64: cpufeature: Detect HCR_EL2.NV1 being RES0") Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240212144736.1933112-3-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 2f8958f27e9e..3421b684d340 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1812,8 +1812,9 @@ static bool has_nv1(const struct arm64_cpu_capabilities *entry, int scope) {} }; - return !(has_cpuid_feature(entry, scope) || - is_midr_in_range_list(read_cpuid_id(), nv1_ni_list)); + return (this_cpu_has_cap(ARM64_HAS_NESTED_VIRT) && + !(has_cpuid_feature(entry, scope) || + is_midr_in_range_list(read_cpuid_id(), nv1_ni_list))); } #if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2) From 1f3ca7023fe63a80e4acfa82f0186c3263356dcb Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Fri, 9 Feb 2024 10:37:19 +0000 Subject: [PATCH 275/814] KVM: arm64: print Hyp mode Print which of the hyp modes is being used (hVHE, nVHE). Signed-off-by: Joey Gouly Cc: Marc Zyngier Cc: Oliver Upton Cc: Mark Brown Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20240209103719.3813599-1-joey.gouly@arm.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/arm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index a25265aca432..090dbc954157 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2591,7 +2591,8 @@ static __init int kvm_arm_init(void) } else if (in_hyp_mode) { kvm_info("VHE mode initialized successfully\n"); } else { - kvm_info("Hyp mode initialized successfully\n"); + char mode = cpus_have_final_cap(ARM64_KVM_HVHE) ? 'h' : 'n'; + kvm_info("Hyp mode (%cVHE) initialized successfully\n", mode); } /* From d198e2668e247f40f68b008ce1d2656dbf2d47eb Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Thu, 8 Feb 2024 10:54:21 +0000 Subject: [PATCH 276/814] KVM: arm64: add comments to __kern_hyp_va Document this function a little, to make it easier to understand. The assembly comments were copied from the kern_hyp_va asm macro. Signed-off-by: Joey Gouly Cc: Marc Zyngier Cc: Oliver Upton Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20240208105422.3444159-2-joey.gouly@arm.com [oliver: migrate a bit more detail from the asm variant] Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_mmu.h | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index e3e793d0ec30..7e7f276bcdd0 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -56,11 +56,6 @@ /* * Convert a kernel VA into a HYP VA. * reg: VA to be converted. - * - * The actual code generation takes place in kvm_update_va_mask, and - * the instructions below are only there to reserve the space and - * perform the register allocation (kvm_update_va_mask uses the - * specific registers encoded in the instructions). */ .macro kern_hyp_va reg #ifndef __KVM_VHE_HYPERVISOR__ @@ -127,14 +122,29 @@ void kvm_apply_hyp_relocations(void); #define __hyp_pa(x) (((phys_addr_t)(x)) + hyp_physvirt_offset) +/* + * Convert a kernel VA into a HYP VA. + * + * Can be called from hyp or non-hyp context. + * + * The actual code generation takes place in kvm_update_va_mask(), and + * the instructions below are only there to reserve the space and + * perform the register allocation (kvm_update_va_mask() uses the + * specific registers encoded in the instructions). + */ static __always_inline unsigned long __kern_hyp_va(unsigned long v) { +/* + * This #ifndef is an optimisation for when this is called from VHE hyp + * context. When called from a VHE non-hyp context, kvm_update_va_mask() will + * replace the instructions with `nop`s. + */ #ifndef __KVM_VHE_HYPERVISOR__ - asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n" - "ror %0, %0, #1\n" - "add %0, %0, #0\n" - "add %0, %0, #0, lsl 12\n" - "ror %0, %0, #63\n", + asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n" /* mask with va_mask */ + "ror %0, %0, #1\n" /* rotate to the first tag bit */ + "add %0, %0, #0\n" /* insert the low 12 bits of the tag */ + "add %0, %0, #0, lsl 12\n" /* insert the top 12 bits of the tag */ + "ror %0, %0, #63\n", /* rotate back */ ARM64_ALWAYS_SYSTEM, kvm_update_va_mask) : "+r" (v)); From a02395d0f3bfa4b2d2a0aa53cc0f2eaeea0e3e66 Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Thu, 8 Feb 2024 10:54:22 +0000 Subject: [PATCH 277/814] KVM: arm64: removed unused kern_hyp_va asm macro The last usage of this macro was removed in: commit 5dc33bd199ca ("KVM: arm64: nVHE: Pass pointers consistently to hyp-init") Signed-off-by: Joey Gouly Cc: Marc Zyngier Cc: Oliver Upton Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20240208105422.3444159-3-joey.gouly@arm.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_mmu.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 7e7f276bcdd0..d5e48d870461 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -53,22 +53,6 @@ #include -/* - * Convert a kernel VA into a HYP VA. - * reg: VA to be converted. - */ -.macro kern_hyp_va reg -#ifndef __KVM_VHE_HYPERVISOR__ -alternative_cb ARM64_ALWAYS_SYSTEM, kvm_update_va_mask - and \reg, \reg, #1 /* mask with va_mask */ - ror \reg, \reg, #1 /* rotate to the first tag bit */ - add \reg, \reg, #0 /* insert the low 12 bits of the tag */ - add \reg, \reg, #0, lsl 12 /* insert the top 12 bits of the tag */ - ror \reg, \reg, #63 /* rotate back */ -alternative_cb_end -#endif -.endm - /* * Convert a hypervisor VA to a PA * reg: hypervisor address to be converted in place From 06fdd894b473c6cc29c9b39b82e0941cefec4e51 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 2 Feb 2024 15:46:03 -0800 Subject: [PATCH 278/814] KVM: selftests: Fix GUEST_PRINTF() format warnings in ARM code Fix a pile of -Wformat warnings in the KVM ARM selftests code, almost all of which are benign "long" versus "long long" issues (selftests are 64-bit only, and the guest printf code treats "ll" the same as "l"). The code itself isn't problematic, but the warnings make it impossible to build ARM selftests with -Werror, which does detect real issues from time to time. Opportunistically have GUEST_ASSERT_BITMAP_REG() interpret set_expected, which is a bool, as an unsigned decimal value, i.e. have it print '0' or '1' instead of '0x0' or '0x1'. Signed-off-by: Sean Christopherson Tested-by: Zenghui Yu Link: https://lore.kernel.org/r/20240202234603.366925-1-seanjc@google.com Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/aarch64/arch_timer.c | 4 ++-- .../testing/selftests/kvm/aarch64/debug-exceptions.c | 2 +- tools/testing/selftests/kvm/aarch64/hypercalls.c | 4 ++-- .../testing/selftests/kvm/aarch64/page_fault_test.c | 2 +- .../selftests/kvm/aarch64/vpmu_counter_access.c | 12 ++++++------ 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 274b8465b42a..d5e8f365aa01 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -158,9 +158,9 @@ static void guest_validate_irq(unsigned int intid, /* Basic 'timer condition met' check */ __GUEST_ASSERT(xcnt >= cval, - "xcnt = 0x%llx, cval = 0x%llx, xcnt_diff_us = 0x%llx", + "xcnt = 0x%lx, cval = 0x%lx, xcnt_diff_us = 0x%lx", xcnt, cval, xcnt_diff_us); - __GUEST_ASSERT(xctl & CTL_ISTATUS, "xcnt = 0x%llx", xcnt); + __GUEST_ASSERT(xctl & CTL_ISTATUS, "xcnt = 0x%lx", xcnt); WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); } diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index 866002917441..2582c49e525a 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -365,7 +365,7 @@ static void guest_wp_handler(struct ex_regs *regs) static void guest_ss_handler(struct ex_regs *regs) { - __GUEST_ASSERT(ss_idx < 4, "Expected index < 4, got '%u'", ss_idx); + __GUEST_ASSERT(ss_idx < 4, "Expected index < 4, got '%lu'", ss_idx); ss_addr[ss_idx++] = regs->pc; regs->pstate |= SPSR_SS; } diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 31f66ba97228..c62739d897d6 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -105,12 +105,12 @@ static void guest_test_hvc(const struct test_hvc_info *hc_info) case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: case TEST_STAGE_HVC_IFACE_FALSE_INFO: __GUEST_ASSERT(res.a0 == SMCCC_RET_NOT_SUPPORTED, - "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%llx, stage = %u", + "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%lx, stage = %u", res.a0, hc_info->func_id, hc_info->arg1, stage); break; case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: __GUEST_ASSERT(res.a0 != SMCCC_RET_NOT_SUPPORTED, - "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%llx, stage = %u", + "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%lx, stage = %u", res.a0, hc_info->func_id, hc_info->arg1, stage); break; default: diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 08a5ca5bed56..7bbd9fb5c8d6 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -292,7 +292,7 @@ static void guest_code(struct test_desc *test) static void no_dabt_handler(struct ex_regs *regs) { - GUEST_FAIL("Unexpected dabt, far_el1 = 0x%llx", read_sysreg(far_el1)); + GUEST_FAIL("Unexpected dabt, far_el1 = 0x%lx", read_sysreg(far_el1)); } static void no_iabt_handler(struct ex_regs *regs) diff --git a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c index 9d51b5691349..f8f0c655c723 100644 --- a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c @@ -195,11 +195,11 @@ struct pmc_accessor pmc_accessors[] = { \ if (set_expected) \ __GUEST_ASSERT((_tval & mask), \ - "tval: 0x%lx; mask: 0x%lx; set_expected: 0x%lx", \ + "tval: 0x%lx; mask: 0x%lx; set_expected: %u", \ _tval, mask, set_expected); \ else \ __GUEST_ASSERT(!(_tval & mask), \ - "tval: 0x%lx; mask: 0x%lx; set_expected: 0x%lx", \ + "tval: 0x%lx; mask: 0x%lx; set_expected: %u", \ _tval, mask, set_expected); \ } @@ -286,7 +286,7 @@ static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx) acc->write_typer(pmc_idx, write_data); read_data = acc->read_typer(pmc_idx); __GUEST_ASSERT(read_data == write_data, - "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx", + "pmc_idx: 0x%x; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx", pmc_idx, PMC_ACC_TO_IDX(acc), read_data, write_data); /* @@ -297,14 +297,14 @@ static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx) /* The count value must be 0, as it is disabled and reset */ __GUEST_ASSERT(read_data == 0, - "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx", + "pmc_idx: 0x%x; acc_idx: 0x%lx; read_data: 0x%lx", pmc_idx, PMC_ACC_TO_IDX(acc), read_data); write_data = read_data + pmc_idx + 0x12345; acc->write_cntr(pmc_idx, write_data); read_data = acc->read_cntr(pmc_idx); __GUEST_ASSERT(read_data == write_data, - "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx", + "pmc_idx: 0x%x; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx", pmc_idx, PMC_ACC_TO_IDX(acc), read_data, write_data); } @@ -379,7 +379,7 @@ static void guest_code(uint64_t expected_pmcr_n) int i, pmc; __GUEST_ASSERT(expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS, - "Expected PMCR.N: 0x%lx; ARMv8 general counters: 0x%lx", + "Expected PMCR.N: 0x%lx; ARMv8 general counters: 0x%x", expected_pmcr_n, ARMV8_PMU_MAX_GENERAL_COUNTERS); pmcr = read_sysreg(pmcr_el0); From 0eaef900b05f0bd111e94602d60c64a282dfa1ef Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Jan 2024 17:17:38 +0800 Subject: [PATCH 279/814] dt-bindings: can: fsl,flexcan: add i.MX95 compatible string Add i.MX95 flexcan which is compatible i.MX93 flexcan Signed-off-by: Peng Fan Acked-by: Marc Kleine-Budde Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240122091738.2078746-1-peng.fan@oss.nxp.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml index 4162469c3c08..f197d9b516bb 100644 --- a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml +++ b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml @@ -38,6 +38,9 @@ properties: - fsl,imx6ul-flexcan - fsl,imx6sx-flexcan - const: fsl,imx6q-flexcan + - items: + - const: fsl,imx95-flexcan + - const: fsl,imx93-flexcan - items: - enum: - fsl,ls1028ar1-flexcan From 15ff10ea77a526c3e0b73e97450966e271a501e8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 24 Jan 2024 13:05:50 -0600 Subject: [PATCH 280/814] dt-bindings: i2c: mux: i2c-demux-pinctrl: Drop i2c-mux.yaml reference The I2C de-mux is different than an I2C mux, so i2c-mux.yaml is not relevant and shouldn't be referenced. Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20240124190552.1551929-1-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml b/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml index 2c08f2a7cf1e..dd3d24212551 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml @@ -32,7 +32,6 @@ description: | +-------------------------------+ allOf: - - $ref: i2c-mux.yaml - $ref: /schemas/i2c/i2c-controller.yaml# properties: From 91f9a47ddb9d6f24028540d843d8464b97f05b0a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 24 Jan 2024 13:05:51 -0600 Subject: [PATCH 281/814] dt-bindings: i2c: mux: i2c-demux-pinctrl: Define "i2c-parent" constraints The 'phandle-array' type is a bit ambiguous. It can be either just an array of phandles or an array of phandles plus args. "i2c-parent" is the former and needs to constrain each entry to a single phandle value. Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20240124190552.1551929-2-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml b/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml index dd3d24212551..b813f6d4810c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml @@ -40,6 +40,8 @@ properties: i2c-parent: $ref: /schemas/types.yaml#/definitions/phandle-array + items: + maxItems: 1 description: List of phandles of I2C masters available for selection. The first one will be used as default. From f7c7190f49b8486fac3b9d499e826bf724f94652 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 7 Feb 2024 15:56:03 +0100 Subject: [PATCH 282/814] scsi: core: Really include kunit tests with SCSI_LIB_KUNIT_TEST Commit 25a1f7a0a1fe ("scsi: core: Add kunit tests for scsi_check_passthrough()") adds the config SCSI_LIB_KUNIT_TEST and corresponding tests. Due to naming confusion, the actual tests would only be included when the non-existing config SCSI_KUNIT_TEST is enabled (note this missing 'LIB' in the config name). So, they are basically dead right now. Adjust the name to actual existing config. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20240207145603.15680-1-lukas.bulwahn@gmail.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c726f2025c59..ca48ba9a229a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3435,6 +3435,6 @@ void scsi_build_sense(struct scsi_cmnd *scmd, int desc, u8 key, u8 asc, u8 ascq) } EXPORT_SYMBOL_GPL(scsi_build_sense); -#ifdef CONFIG_SCSI_KUNIT_TEST +#ifdef CONFIG_SCSI_LIB_KUNIT_TEST #include "scsi_lib_test.c" #endif From 8cdc71fbf65567dca6f52aac206d91754ad55147 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Mon, 12 Feb 2024 21:09:33 +0000 Subject: [PATCH 283/814] KVM: selftests: Print timer ctl register in ISTATUS assertion Zenghui noted that the test assertion for the ISTATUS bit is printing the current timer value instead of the control register in the case of failure. While the assertion is sound, printing CNT isn't informative. Change things around to actually print the CTL register value instead. Reported-by: Zenghui Yu Closes: https://lore.kernel.org/kvmarm/3188e6f1-f150-f7d0-6c2b-5b7608b0b012@huawei.com/ Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20240212210932.3095265-2-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/aarch64/arch_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index d5e8f365aa01..ab4b604d8ec0 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -160,7 +160,7 @@ static void guest_validate_irq(unsigned int intid, __GUEST_ASSERT(xcnt >= cval, "xcnt = 0x%lx, cval = 0x%lx, xcnt_diff_us = 0x%lx", xcnt, cval, xcnt_diff_us); - __GUEST_ASSERT(xctl & CTL_ISTATUS, "xcnt = 0x%lx", xcnt); + __GUEST_ASSERT(xctl & CTL_ISTATUS, "xctl = 0x%lx", xctl); WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); } From a0bcad233fd6a4cdd14441d7cc27b28475721fe8 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 15:38:37 -0300 Subject: [PATCH 284/814] scsi: core: Make scsi_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the scsi_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240212-bus_cleanup-scsi2-v2-1-65004493ff09@marliere.net Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_priv.h | 2 +- drivers/scsi/scsi_sysfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 3f0dfb97db6b..92e966a2b48a 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -156,7 +156,7 @@ extern void scsi_sysfs_device_initialize(struct scsi_device *); extern struct scsi_transport_template blank_transport_template; extern void __scsi_remove_device(struct scsi_device *); -extern struct bus_type scsi_bus_type; +extern const struct bus_type scsi_bus_type; extern const struct attribute_group *scsi_shost_groups[]; /* scsi_netlink.c */ diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 24f6eefb6803..14d0be0da0c6 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -549,7 +549,7 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env return 0; } -struct bus_type scsi_bus_type = { +const struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, From 9f1a0769f1939456f3b4ce388f021963d20afbf8 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Sat, 10 Feb 2024 15:15:12 -0800 Subject: [PATCH 285/814] MAINTAINERS: of: Add Saravana Kannan Adding myself as a second maintainer for Open Firmware and Device Tree to help Rob out with reviews and other maintainer work. Cc: devicetree@vger.kernel.org Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20240210231513.111117-1-saravanak@google.com Signed-off-by: Rob Herring --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index b01f890ec789..45c6c13b4edf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16359,6 +16359,7 @@ F: drivers/infiniband/ulp/opa_vnic OPEN FIRMWARE AND FLATTENED DEVICE TREE M: Rob Herring +M: Saravana Kannan L: devicetree@vger.kernel.org S: Maintained W: http://www.devicetree.org/ From e72638535dfa3b6435ccdaad04adbb9facc83ba5 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Mon, 5 Feb 2024 10:40:33 +0800 Subject: [PATCH 286/814] of: Make explicit cpu_to_be32 conversion to mute sparse warning Kernel test robot reports sparse warning: sparse warnings: (new ones prefixed by >>) >> drivers/of/base.c:1337:73: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted __be32 @@ got int @@ drivers/of/base.c:1337:73: sparse: expected restricted __be32 drivers/of/base.c:1337:73: sparse: got int Thus, Make explicit conversions to mute warning(Although BE and LE are exactly same in binary representation for 0/~0). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402042134.GEb3Bgwl-lkp@intel.com/ Signed-off-by: Dawei Li Link: https://lore.kernel.org/r/20240205024033.3572617-1-dawei.li@shingroup.cn Signed-off-by: Rob Herring --- drivers/of/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index b0ad8fc06e80..f71cda9ac09d 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1345,8 +1345,8 @@ int of_parse_phandle_with_args_map(const struct device_node *np, char *pass_name = NULL; struct device_node *cur, *new = NULL; const __be32 *map, *mask, *pass; - static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 }; - static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 }; + static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) }; + static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(0) }; __be32 initial_match_array[MAX_PHANDLE_ARGS]; const __be32 *match_array = initial_match_array; int i, ret, map_len, match; From 14354fc38a6f7a9c03c57fba2845a69f184990dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Feb 2024 12:08:27 +0100 Subject: [PATCH 287/814] dt-bindings: misc: qcom,fastrpc: Compute callbacks can be DMA coherent Apparently on Qualcomm SM8550 and SM8650 the FastRPC compute callbacks are DMA coherent: sm8650-qrd.dtb: fastrpc: compute-cb@2: 'dma-coherent' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240212110827.59302-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml b/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml index 2dc3e245fa5d..c27a8f33d8d7 100644 --- a/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml +++ b/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml @@ -77,6 +77,8 @@ patternProperties: reg: maxItems: 1 + dma-coherent: true + iommus: minItems: 1 maxItems: 3 From cb47c01b348857fda83bc7db33d7f37946a19c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Feb 2024 15:08:39 +0100 Subject: [PATCH 288/814] dt-bindings: vendor-prefixes: add smartrg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SmartRG described itself as a CPE manufacturer and produced few home network devices (e.g. wireless routers). Their SmartRG SR400ac router (smartrg,sr400ac) is covered by in-Linux DT binding and DTS file. Signed-off-by: Rafał Miłecki Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240212140839.27150-1-zajec5@gmail.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 1a0dc04f1db4..71e37cea8689 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1297,6 +1297,8 @@ patternProperties: description: Skyworks Solutions, Inc. "^smartlabs,.*": description: SmartLabs LLC + "^smartrg,.*": + description: SmartRG, Inc. "^smi,.*": description: Silicon Motion Technology Corporation "^smsc,.*": From 6e7164714539eeed9c616d33547fdd3961e6a11c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Feb 2024 11:53:27 +0100 Subject: [PATCH 289/814] dt-bindings: use capital "OR" for multiple licenses in SPDX Documentation/process/license-rules.rst and checkpatch expect the SPDX identifier syntax for multiple licenses to use capital "OR". Correct it to keep consistent format and avoid copy-paste issues. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240208105327.129159-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/display/panel/visionox,r66451.yaml | 2 +- Documentation/devicetree/bindings/usb/cypress,hx3.yaml | 2 +- include/dt-bindings/power/amlogic,c3-pwrc.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/visionox,r66451.yaml b/Documentation/devicetree/bindings/display/panel/visionox,r66451.yaml index 6ba323683921..187840bb76c7 100644 --- a/Documentation/devicetree/bindings/display/panel/visionox,r66451.yaml +++ b/Documentation/devicetree/bindings/display/panel/visionox,r66451.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- $id: http://devicetree.org/schemas/display/panel/visionox,r66451.yaml# diff --git a/Documentation/devicetree/bindings/usb/cypress,hx3.yaml b/Documentation/devicetree/bindings/usb/cypress,hx3.yaml index 47add0d85fb8..28096619a882 100644 --- a/Documentation/devicetree/bindings/usb/cypress,hx3.yaml +++ b/Documentation/devicetree/bindings/usb/cypress,hx3.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- $id: http://devicetree.org/schemas/usb/cypress,hx3.yaml# diff --git a/include/dt-bindings/power/amlogic,c3-pwrc.h b/include/dt-bindings/power/amlogic,c3-pwrc.h index 1d98a25b08a4..61759df4b2e7 100644 --- a/include/dt-bindings/power/amlogic,c3-pwrc.h +++ b/include/dt-bindings/power/amlogic,c3-pwrc.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ /* * Copyright (c) 2023 Amlogic, Inc. * Author: hongyu chen1 From ceecb37e49673019afdcf39e2d4fcfd5ebcf06c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Feb 2024 16:05:22 +0100 Subject: [PATCH 290/814] docs: dt: writing-schema: clarify that schema should describe hardware The 'title' and 'description' fields in Devicetree schema is supposed to describe hardware, not the binding itself. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240212150524.81819-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/writing-schema.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/writing-schema.rst b/Documentation/devicetree/bindings/writing-schema.rst index 0a6cf19a1459..2e5575e6a4e5 100644 --- a/Documentation/devicetree/bindings/writing-schema.rst +++ b/Documentation/devicetree/bindings/writing-schema.rst @@ -31,7 +31,7 @@ $schema Indicates the meta-schema the schema file adheres to. title - A one-line description on the contents of the binding schema. + A one-line description of the hardware being described in the binding schema. maintainers A DT specific property. Contains a list of email address(es) @@ -39,7 +39,7 @@ maintainers description Optional. A multi-line text block containing any detailed - information about this binding. It should contain things such as what the block + information about this hardware. It should contain things such as what the block or device does, standards the device conforms to, and links to datasheets for more information. From d9a41dc4de9fcdf6395a31bfcb737328e2b9fe1e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Feb 2024 16:05:23 +0100 Subject: [PATCH 291/814] docs: dt: writing-schema: explain additional/unevaluatedProperties Add to the list of schema contents expected keywords with their explanation: additionalProperties and unevaluatedProperties. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240212150524.81819-2-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/writing-schema.rst | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/writing-schema.rst b/Documentation/devicetree/bindings/writing-schema.rst index 2e5575e6a4e5..a35859f3be00 100644 --- a/Documentation/devicetree/bindings/writing-schema.rst +++ b/Documentation/devicetree/bindings/writing-schema.rst @@ -71,6 +71,26 @@ required A list of DT properties from the 'properties' section that must always be present. +additionalProperties / unevaluatedProperties + Keywords controlling how schema will validate properties not matched by this + schema's 'properties' or 'patternProperties'. Each schema is supposed to + have exactly one of these keywords in top-level part, so either + additionalProperties or unevaluatedProperties. Nested nodes, so properties + being objects, are supposed to have one as well. + + * additionalProperties: false + Most common case, where no additional schema is referenced or if this + binding allows subset of properties from other referenced schemas. + + * unevaluatedProperties: false + Used when this binding references other schema whose all properties + should be allowed. + + * additionalProperties: true + Rare case, used for schemas implementing common set of properties. Such + schemas are supposed to be referenced by other schemas, which then use + 'unevaluatedProperties: false'. Typically bus or common-part schemas. + examples Optional. A list of one or more DTS hunks implementing the binding. Note: YAML doesn't allow leading tabs, so spaces must be used instead. From 2ff94f7ce292a77e77965919d7dccb7ac04a88f5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Feb 2024 16:05:24 +0100 Subject: [PATCH 292/814] docs: dt: writing-schema: document expectations on example DTS Devicetree binding maintainers expect the example DTS in a binding to show the usage of only this one particular binding, without unrelated device nodes. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240212150524.81819-3-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/writing-schema.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/writing-schema.rst b/Documentation/devicetree/bindings/writing-schema.rst index a35859f3be00..7e71cdd1d6de 100644 --- a/Documentation/devicetree/bindings/writing-schema.rst +++ b/Documentation/devicetree/bindings/writing-schema.rst @@ -92,8 +92,10 @@ additionalProperties / unevaluatedProperties 'unevaluatedProperties: false'. Typically bus or common-part schemas. examples - Optional. A list of one or more DTS hunks implementing the - binding. Note: YAML doesn't allow leading tabs, so spaces must be used instead. + Optional. A list of one or more DTS hunks implementing this binding only. + Example should not contain unrelated device nodes, e.g. consumer nodes in a + provider binding, other nodes referenced by phandle. + Note: YAML doesn't allow leading tabs, so spaces must be used instead. Unless noted otherwise, all properties are required. From 5580e96dad5a439d561d9648ffcbccb739c2a120 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Feb 2024 00:14:04 +1100 Subject: [PATCH 293/814] powerpc/smp: Adjust nr_cpu_ids to cover all threads of a core If nr_cpu_ids is too low to include at least all the threads of a single core adjust nr_cpu_ids upwards. This avoids triggering odd bugs in code that assumes all threads of a core are available. Cc: stable@vger.kernel.org Signed-off-by: Michael Ellerman Link: https://msgid.link/20231229120107.2281153-1-mpe@ellerman.id.au --- arch/powerpc/kernel/prom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 0b5878c3125b..58e80076bed5 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -375,6 +375,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, if (IS_ENABLED(CONFIG_PPC64)) boot_cpu_hwid = be32_to_cpu(intserv[found_thread]); + if (nr_cpu_ids % nthreads != 0) { + set_nr_cpu_ids(ALIGN(nr_cpu_ids, nthreads)); + pr_warn("nr_cpu_ids was not a multiple of threads_per_core, adjusted to %d\n", + nr_cpu_ids); + } + /* * PAPR defines "logical" PVR values for cpus that * meet various levels of the architecture: From 777f81f0a9c780a6443bcf2c7785f0cc2e87c1ef Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Feb 2024 00:14:04 +1100 Subject: [PATCH 294/814] powerpc/smp: Increase nr_cpu_ids to include the boot CPU If nr_cpu_ids is too low to include the boot CPU adjust nr_cpu_ids upward. Otherwise the kernel will BUG when trying to allocate a paca for the boot CPU and fail to boot. Cc: stable@vger.kernel.org Signed-off-by: Michael Ellerman Link: https://msgid.link/20231229120107.2281153-2-mpe@ellerman.id.au --- arch/powerpc/kernel/prom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 58e80076bed5..77364729a1b6 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -381,6 +381,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, nr_cpu_ids); } + if (boot_cpuid >= nr_cpu_ids) { + set_nr_cpu_ids(min(CONFIG_NR_CPUS, ALIGN(boot_cpuid + 1, nthreads))); + pr_warn("Boot CPU %d >= nr_cpu_ids, adjusted nr_cpu_ids to %d\n", + boot_cpuid, nr_cpu_ids); + } + /* * PAPR defines "logical" PVR values for cpus that * meet various levels of the architecture: From dca79603fbc592ec7ea8bd7ba274052d3984e882 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Feb 2024 00:14:04 +1100 Subject: [PATCH 295/814] powerpc/smp: Lookup avail once per device tree node The of_device_is_available() check only needs to be done once per device node, there's no need to repeat it for each thread. Move it out of the loop. Signed-off-by: Michael Ellerman Link: https://msgid.link/20231229120107.2281153-3-mpe@ellerman.id.au --- arch/powerpc/kernel/setup-common.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 9b142b9d5187..375bade1cf09 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -468,17 +468,16 @@ void __init smp_setup_cpu_maps(void) nthreads = len / sizeof(int); + bool avail = of_device_is_available(dn); + if (!avail) + avail = !of_property_match_string(dn, + "enable-method", "spin-table"); + for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { - bool avail; DBG(" thread %d -> cpu %d (hard id %d)\n", j, cpu, be32_to_cpu(intserv[j])); - avail = of_device_is_available(dn); - if (!avail) - avail = !of_property_match_string(dn, - "enable-method", "spin-table"); - set_cpu_present(cpu, avail); set_cpu_possible(cpu, true); cpu_to_phys_id[cpu] = be32_to_cpu(intserv[j]); From 9832de654499f0bf797a3719c4d4c5bd401f18f5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Feb 2024 00:14:05 +1100 Subject: [PATCH 296/814] powerpc/smp: Factor out assign_threads() Factor out the for loop that assigns CPU numbers to threads of a core. The function takes the next CPU number to use as input, and returns the next available CPU number after the threads has been assigned. This will allow a subsequent change to assign threads out of order. Signed-off-by: Michael Ellerman Link: https://msgid.link/20231229120107.2281153-4-mpe@ellerman.id.au --- arch/powerpc/kernel/setup-common.c | 32 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 375bade1cf09..a5aab5a79545 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -411,6 +411,25 @@ static void __init cpu_init_thread_core_maps(int tpc) u32 *cpu_to_phys_id = NULL; +static int assign_threads(unsigned int cpu, unsigned int nthreads, bool present, + const __be32 *hw_ids) +{ + for (int i = 0; i < nthreads && cpu < nr_cpu_ids; i++) { + __be32 hwid; + + hwid = be32_to_cpu(hw_ids[i]); + + DBG(" thread %d -> cpu %d (hard id %d)\n", i, cpu, hwid); + + set_cpu_present(cpu, present); + set_cpu_possible(cpu, true); + cpu_to_phys_id[cpu] = hwid; + cpu++; + } + + return cpu; +} + /** * setup_cpu_maps - initialize the following cpu maps: * cpu_possible_mask @@ -446,7 +465,7 @@ void __init smp_setup_cpu_maps(void) for_each_node_by_type(dn, "cpu") { const __be32 *intserv; __be32 cpu_be; - int j, len; + int len; DBG(" * %pOF...\n", dn); @@ -473,16 +492,7 @@ void __init smp_setup_cpu_maps(void) avail = !of_property_match_string(dn, "enable-method", "spin-table"); - for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { - - DBG(" thread %d -> cpu %d (hard id %d)\n", - j, cpu, be32_to_cpu(intserv[j])); - - set_cpu_present(cpu, avail); - set_cpu_possible(cpu, true); - cpu_to_phys_id[cpu] = be32_to_cpu(intserv[j]); - cpu++; - } + cpu = assign_threads(cpu, nthreads, avail, intserv); if (cpu >= nr_cpu_ids) { of_node_put(dn); From 0875f1ceba974042069f04946aa8f1d4d1e688da Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Feb 2024 00:14:05 +1100 Subject: [PATCH 297/814] powerpc/smp: Remap boot CPU onto core 0 if >= nr_cpu_ids If nr_cpu_ids is too low to include the boot CPU, remap the boot CPU onto logical core 0. This is achieved in two stages. In early_init_dt_scan_cpus() the boot CPU is renumbered to be on logical core 0, and the original boot core's hardware ID is recorded. Later in smp_setup_cpu_maps(), if the original boot core ID is set, the logical CPU numbers on the 0th core are skipped in the normal device tree search over CPU device tree nodes. Then the search is continued until the device tree node matching the boot core is found, and those CPUs are assigned the CPU numbers starting at 0. This allows kdump kernels to be booted with low values for nr_cpu_ids to conserve memory, while also allowing the crashing/boot CPU to be any CPU. Signed-off-by: Michael Ellerman Tested-by: Wen Xiong Link: https://msgid.link/20231229120107.2281153-5-mpe@ellerman.id.au --- arch/powerpc/include/asm/smp.h | 1 + arch/powerpc/kernel/prom.c | 16 +++++++++++----- arch/powerpc/kernel/setup-common.c | 19 +++++++++++++++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index aaaa576d0e15..b77927ccb0ab 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -27,6 +27,7 @@ extern int boot_cpuid; extern int boot_cpu_hwid; /* PPC64 only */ +extern int boot_core_hwid; extern int spinning_secondaries; extern u32 *cpu_to_phys_id; extern bool coregroup_enabled; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 77364729a1b6..f2c2f79ea477 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -368,8 +368,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node, if (found < 0) return 0; - DBG("boot cpu: logical %d physical %d\n", found, - be32_to_cpu(intserv[found_thread])); boot_cpuid = found; if (IS_ENABLED(CONFIG_PPC64)) @@ -382,11 +380,19 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } if (boot_cpuid >= nr_cpu_ids) { - set_nr_cpu_ids(min(CONFIG_NR_CPUS, ALIGN(boot_cpuid + 1, nthreads))); - pr_warn("Boot CPU %d >= nr_cpu_ids, adjusted nr_cpu_ids to %d\n", - boot_cpuid, nr_cpu_ids); + // Remember boot core for smp_setup_cpu_maps() + boot_core_hwid = be32_to_cpu(intserv[0]); + + pr_warn("Boot CPU %d (core hwid %d) >= nr_cpu_ids, adjusted boot CPU to %d\n", + boot_cpuid, boot_core_hwid, found_thread); + + // Adjust boot CPU to appear on logical core 0 + boot_cpuid = found_thread; } + DBG("boot cpu: logical %d physical %d\n", boot_cpuid, + be32_to_cpu(intserv[found_thread])); + /* * PAPR defines "logical" PVR values for cpus that * meet various levels of the architecture: diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index a5aab5a79545..6fe68aa93268 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -85,6 +85,7 @@ EXPORT_SYMBOL(machine_id); int boot_cpuid = -1; EXPORT_SYMBOL_GPL(boot_cpuid); +int __initdata boot_core_hwid = -1; #ifdef CONFIG_PPC64 int boot_cpu_hwid = -1; @@ -492,12 +493,26 @@ void __init smp_setup_cpu_maps(void) avail = !of_property_match_string(dn, "enable-method", "spin-table"); - cpu = assign_threads(cpu, nthreads, avail, intserv); + if (boot_core_hwid >= 0) { + if (cpu == 0) { + pr_info("Skipping CPU node %pOF to allow for boot core.\n", dn); + cpu = nthreads; + continue; + } - if (cpu >= nr_cpu_ids) { + if (be32_to_cpu(intserv[0]) == boot_core_hwid) { + pr_info("Renumbered boot core %pOF to logical 0\n", dn); + assign_threads(0, nthreads, avail, intserv); + of_node_put(dn); + break; + } + } else if (cpu >= nr_cpu_ids) { of_node_put(dn); break; } + + if (cpu < nr_cpu_ids) + cpu = assign_threads(cpu, nthreads, avail, intserv); } /* If no SMT supported, nthreads is forced to 1 */ From c5aebb53b32460bc52680dd4e2a2f6b84d5ea521 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 13 Feb 2024 14:58:37 +0100 Subject: [PATCH 298/814] powerpc: Force inlining of arch_vmap_p{u/m}d_supported() arch_vmap_pud_supported() and arch_vmap_pmd_supported() are expected to constant-fold to false when RADIX is not enabled. Force inlining in order to avoid following failure which leads to unexpected call of non-existing pud_set_huge() and pmd_set_huge() on powerpc 8xx. In function 'pud_huge_tests', inlined from 'debug_vm_pgtable' at mm/debug_vm_pgtable.c:1399:2: ./arch/powerpc/include/asm/vmalloc.h:9:33: warning: inlining failed in call to 'arch_vmap_pud_supported.isra': call is unlikely and code size would grow [-Winline] 9 | #define arch_vmap_pud_supported arch_vmap_pud_supported | ^~~~~~~~~~~~~~~~~~~~~~~ ./arch/powerpc/include/asm/vmalloc.h:10:20: note: in expansion of macro 'arch_vmap_pud_supported' 10 | static inline bool arch_vmap_pud_supported(pgprot_t prot) | ^~~~~~~~~~~~~~~~~~~~~~~ ./arch/powerpc/include/asm/vmalloc.h:9:33: note: called from here 9 | #define arch_vmap_pud_supported arch_vmap_pud_supported mm/debug_vm_pgtable.c:458:14: note: in expansion of macro 'arch_vmap_pud_supported' 458 | if (!arch_vmap_pud_supported(args->page_prot) || | ^~~~~~~~~~~~~~~~~~~~~~~ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402131836.OU1TDuoi-lkp@intel.com/ Fixes: 8309c9d71702 ("powerpc: inline huge vmap supported functions") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/bbd84ad52bf377e8d3b5865a906f2dc5d99964ba.1707832677.git.christophe.leroy@csgroup.eu --- arch/powerpc/include/asm/vmalloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/vmalloc.h b/arch/powerpc/include/asm/vmalloc.h index 4c69ece52a31..59ed89890c90 100644 --- a/arch/powerpc/include/asm/vmalloc.h +++ b/arch/powerpc/include/asm/vmalloc.h @@ -7,14 +7,14 @@ #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP #define arch_vmap_pud_supported arch_vmap_pud_supported -static inline bool arch_vmap_pud_supported(pgprot_t prot) +static __always_inline bool arch_vmap_pud_supported(pgprot_t prot) { /* HPT does not cope with large pages in the vmalloc area */ return radix_enabled(); } #define arch_vmap_pmd_supported arch_vmap_pmd_supported -static inline bool arch_vmap_pmd_supported(pgprot_t prot) +static __always_inline bool arch_vmap_pmd_supported(pgprot_t prot) { return radix_enabled(); } From e15d01277a8bdacf8ac485049d21d450153fa47e Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 17:04:59 -0300 Subject: [PATCH 299/814] powerpc: vio: move device attributes into a new ifdef In order to make the distinction of the vio_bus_type variable based on CONFIG_PPC_SMLPAR more explicit, move the required structs into a new ifdef block. This is needed in order to make vio_bus_type const and because the distinction is made explicit, there is no need to set the fields within the vio_cmo_sysfs_init function. Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://msgid.link/20240212-bus_cleanup-powerpc2-v2-1-8441b3f77827@marliere.net --- arch/powerpc/platforms/pseries/vio.c | 59 ++++++++++++++++------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 2dc9cbc4bcd8..6c58824190a2 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -991,18 +991,6 @@ static DEVICE_ATTR_RO(cmo_allocated); static DEVICE_ATTR_RW(cmo_desired); static DEVICE_ATTR_RW(cmo_allocs_failed); -static struct attribute *vio_cmo_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_devspec.attr, - &dev_attr_modalias.attr, - &dev_attr_cmo_entitled.attr, - &dev_attr_cmo_allocated.attr, - &dev_attr_cmo_desired.attr, - &dev_attr_cmo_allocs_failed.attr, - NULL, -}; -ATTRIBUTE_GROUPS(vio_cmo_dev); - /* sysfs bus functions and data structures for CMO */ #define viobus_cmo_rd_attr(name) \ @@ -1062,11 +1050,7 @@ static struct attribute *vio_bus_attrs[] = { }; ATTRIBUTE_GROUPS(vio_bus); -static void __init vio_cmo_sysfs_init(void) -{ - vio_bus_type.dev_groups = vio_cmo_dev_groups; - vio_bus_type.bus_groups = vio_bus_groups; -} +static void __init vio_cmo_sysfs_init(void) { } #else /* CONFIG_PPC_SMLPAR */ int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} @@ -1584,14 +1568,6 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(modalias); -static struct attribute *vio_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_devspec.attr, - &dev_attr_modalias.attr, - NULL, -}; -ATTRIBUTE_GROUPS(vio_dev); - void vio_unregister_device(struct vio_dev *viodev) { device_unregister(&viodev->dev); @@ -1626,6 +1602,38 @@ static int vio_hotplug(const struct device *dev, struct kobj_uevent_env *env) return 0; } +#ifdef CONFIG_PPC_SMLPAR +static struct attribute *vio_cmo_dev_attrs[] = { + &dev_attr_name.attr, + &dev_attr_devspec.attr, + &dev_attr_modalias.attr, + &dev_attr_cmo_entitled.attr, + &dev_attr_cmo_allocated.attr, + &dev_attr_cmo_desired.attr, + &dev_attr_cmo_allocs_failed.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vio_cmo_dev); + +struct bus_type vio_bus_type = { + .name = "vio", + .dev_groups = vio_cmo_dev_groups, + .bus_groups = vio_bus_groups, + .uevent = vio_hotplug, + .match = vio_bus_match, + .probe = vio_bus_probe, + .remove = vio_bus_remove, + .shutdown = vio_bus_shutdown, +}; +#else /* CONFIG_PPC_SMLPAR */ +static struct attribute *vio_dev_attrs[] = { + &dev_attr_name.attr, + &dev_attr_devspec.attr, + &dev_attr_modalias.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vio_dev); + struct bus_type vio_bus_type = { .name = "vio", .dev_groups = vio_dev_groups, @@ -1635,6 +1643,7 @@ struct bus_type vio_bus_type = { .remove = vio_bus_remove, .shutdown = vio_bus_shutdown, }; +#endif /* CONFIG_PPC_SMLPAR */ /** * vio_get_attribute: - get attribute for virtual device From 565206aaa6528b30df9294e9aafac429e4bc94eb Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 17:05:00 -0300 Subject: [PATCH 300/814] powerpc: vio: make vio_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the vio_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://msgid.link/20240212-bus_cleanup-powerpc2-v2-2-8441b3f77827@marliere.net --- arch/powerpc/include/asm/vio.h | 2 +- arch/powerpc/platforms/pseries/vio.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h index cc9b787627ad..6faf2a931755 100644 --- a/arch/powerpc/include/asm/vio.h +++ b/arch/powerpc/include/asm/vio.h @@ -39,7 +39,7 @@ */ #define VIO_CMO_MIN_ENT 1562624 -extern struct bus_type vio_bus_type; +extern const struct bus_type vio_bus_type; struct iommu_table; diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 6c58824190a2..90ff85c879bf 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1615,7 +1615,7 @@ static struct attribute *vio_cmo_dev_attrs[] = { }; ATTRIBUTE_GROUPS(vio_cmo_dev); -struct bus_type vio_bus_type = { +const struct bus_type vio_bus_type = { .name = "vio", .dev_groups = vio_cmo_dev_groups, .bus_groups = vio_bus_groups, @@ -1634,7 +1634,7 @@ static struct attribute *vio_dev_attrs[] = { }; ATTRIBUTE_GROUPS(vio_dev); -struct bus_type vio_bus_type = { +const struct bus_type vio_bus_type = { .name = "vio", .dev_groups = vio_dev_groups, .uevent = vio_hotplug, From 8e3d0b8d99d708e8262e76313e0436339add80ec Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 17:05:01 -0300 Subject: [PATCH 301/814] powerpc: mpic: make mpic_subsys const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the mpic_subsys variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://msgid.link/20240212-bus_cleanup-powerpc2-v2-3-8441b3f77827@marliere.net --- arch/powerpc/include/asm/mpic.h | 2 +- arch/powerpc/sysdev/mpic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 58353c5bd3fb..0c03a98986cd 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -336,7 +336,7 @@ struct mpic #endif }; -extern struct bus_type mpic_subsys; +extern const struct bus_type mpic_subsys; /* * MPIC flags (passed to mpic_alloc) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index dabbdd356664..d94cf36b0f65 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -49,7 +49,7 @@ #define DBG(fmt...) #endif -struct bus_type mpic_subsys = { +const struct bus_type mpic_subsys = { .name = "mpic", .dev_name = "mpic", }; From 112202f34e56cd475e26b2a461dd856ca7570ef9 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 17:05:02 -0300 Subject: [PATCH 302/814] powerpc: pmac: make macio_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the macio_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://msgid.link/20240212-bus_cleanup-powerpc2-v2-4-8441b3f77827@marliere.net --- arch/powerpc/include/asm/macio.h | 2 +- drivers/macintosh/macio_asic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index 3a07c62973aa..ab9608e63e40 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h @@ -6,7 +6,7 @@ #include #include -extern struct bus_type macio_bus_type; +extern const struct bus_type macio_bus_type; /* MacIO device driver is defined later */ struct macio_driver; diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index a5ee8f736a8e..565f1e21ff7d 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -136,7 +136,7 @@ static int macio_device_modalias(const struct device *dev, struct kobj_uevent_en extern const struct attribute_group *macio_dev_groups[]; -struct bus_type macio_bus_type = { +const struct bus_type macio_bus_type = { .name = "macio", .match = macio_bus_match, .uevent = macio_device_modalias, From 14ce0dbb562713bc058ad16d281db355757e6ec0 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 12 Feb 2024 17:05:03 -0300 Subject: [PATCH 303/814] powerpc: ibmebus: make ibmebus_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the ibmebus_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://msgid.link/20240212-bus_cleanup-powerpc2-v2-5-8441b3f77827@marliere.net --- arch/powerpc/include/asm/ibmebus.h | 2 +- arch/powerpc/platforms/pseries/ibmebus.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/ibmebus.h b/arch/powerpc/include/asm/ibmebus.h index 6f33253a364a..46fe406f461c 100644 --- a/arch/powerpc/include/asm/ibmebus.h +++ b/arch/powerpc/include/asm/ibmebus.h @@ -48,7 +48,7 @@ struct platform_driver; -extern struct bus_type ibmebus_bus_type; +extern const struct bus_type ibmebus_bus_type; int ibmebus_register_driver(struct platform_driver *drv); void ibmebus_unregister_driver(struct platform_driver *drv); diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index 998e3aff2457..b401282727a4 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -55,7 +55,7 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */ .init_name = "ibmebus", }; -struct bus_type ibmebus_bus_type; +const struct bus_type ibmebus_bus_type; /* These devices will automatically be added to the bus during init */ static const struct of_device_id ibmebus_matches[] __initconst = { @@ -432,7 +432,7 @@ static int ibmebus_bus_modalias(const struct device *dev, struct kobj_uevent_env return of_device_uevent_modalias(dev, env); } -struct bus_type ibmebus_bus_type = { +const struct bus_type ibmebus_bus_type = { .name = "ibmebus", .uevent = ibmebus_bus_modalias, .bus_groups = ibmbus_bus_groups, From 7b2411e793673b6282ab7907be26b82234681313 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 8 Feb 2024 15:50:31 +0100 Subject: [PATCH 304/814] KVM: s390: fix virtual vs physical address confusion Fix virtual vs physical address confusion. This does not fix a bug since virtual and physical address spaces are currently the same. Suggested-by: Janosch Frank Signed-off-by: Alexander Gordeev Acked-by: Janosch Frank Acked-by: Anthony Krowiak Signed-off-by: Janosch Frank --- arch/s390/kvm/kvm-s390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ea63ac769889..6635a7acef34 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -3153,7 +3153,7 @@ static int kvm_s390_apxa_installed(void) */ static void kvm_s390_set_crycb_format(struct kvm *kvm) { - kvm->arch.crypto.crycbd = (__u32)(unsigned long) kvm->arch.crypto.crycb; + kvm->arch.crypto.crycbd = virt_to_phys(kvm->arch.crypto.crycb); /* Clear the CRYCB format bits - i.e., set format 0 by default */ kvm->arch.crypto.crycbd &= ~(CRYCB_FORMAT_MASK); From 9aa030cee1c45d6e962f6bf22ba63d4aff2b1644 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 15 Feb 2024 01:49:54 +0000 Subject: [PATCH 305/814] arm64: cpufeatures: Fix FEAT_NV check when checking for FEAT_NV1 Using this_cpu_has_cap() has the potential to go wrong when used system-wide on a preemptible kernel. Instead, use the __system_matches_cap() helper when checking for FEAT_NV in the FEAT_NV1 probing helper. Fixes: 3673d01a2f55 ("arm64: cpufeatures: Only check for NV1 if NV is present") Reported-by: Marek Szyprowski Signed-off-by: Marc Zyngier Reviewed-by: Suzuki K Poulose Tested-by: Marek Szyprowski Link: https://lore.kernel.org/kvmarm/86bk8k5ts3.wl-maz@kernel.org/ Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3421b684d340..f309fd542c20 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1812,7 +1812,7 @@ static bool has_nv1(const struct arm64_cpu_capabilities *entry, int scope) {} }; - return (this_cpu_has_cap(ARM64_HAS_NESTED_VIRT) && + return (__system_matches_cap(ARM64_HAS_NESTED_VIRT) && !(has_cpuid_feature(entry, scope) || is_midr_in_range_list(read_cpuid_id(), nv1_ni_list))); } From 0955723ef93583be768c5ddc22aff11d6c3cc260 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 11 Dec 2023 09:30:29 +0100 Subject: [PATCH 306/814] sparc: remove obsolete config ARCH_ATU Before consolidation of commit 4965a68780c5 ("arch: define the ARCH_DMA_ADDR_T_64BIT config symbol in lib/Kconfig"), the config ARCH_ATU was used to control the state of the config ARCH_DMA_ADDR_T_64BIT. After this consolidation, the config ARCH_ATU has been without use and effect. Remove this obsolete config. Signed-off-by: Lukas Bulwahn Reviewed-by: Christoph Hellwig Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20231211083029.22078-1-lukas.bulwahn@gmail.com --- arch/sparc/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 204c43cb3d43..c54ee10b8e2d 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -112,10 +112,6 @@ config ARCH_PROC_KCORE_TEXT config CPU_BIG_ENDIAN def_bool y -config ARCH_ATU - bool - default y if SPARC64 - config STACKTRACE_SUPPORT bool default y if SPARC64 From b628db427fd24892e1690ff50e8bf568210fa333 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Feb 2024 15:35:33 +0000 Subject: [PATCH 307/814] scsi: qla1280: Remove redundant assignment to variable 'mr' The variable 'mr' being assigned a value that is never read, the assignment is redundant and can be removed. Cleans up clang scan build warning: drivers/scsi/qla1280.c:2481:2: warning: Value stored to 'mr' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240215153533.2067413-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla1280.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 27bce80262c2..8958547ac111 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2478,7 +2478,6 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) /* Load return mailbox registers. */ optr = mb; iptr = (uint16_t *) &ha->mailbox_out[0]; - mr = MAILBOX_REGISTER_COUNT; memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t)); if (ha->flags.reset_marker) From 9f3dbcb5632d6876226031d552ef6163bb3ad215 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:05:00 +0100 Subject: [PATCH 308/814] scsi: csiostor: Avoid function pointer casts csiostor uses function pointer casts to keep the csio_ln_ev state machine hidden, but this causes warnings about control flow integrity (KCFI) violations in clang-16 and higher: drivers/scsi/csiostor/csio_lnode.c:1098:33: error: cast from 'void (*)(struct csio_lnode *, enum csio_ln_ev)' to 'csio_sm_state_t' (aka 'void (*)(void *, unsigned int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 1098 | return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/csiostor/csio_lnode.c:1369:29: error: cast from 'void (*)(struct csio_lnode *, enum csio_ln_ev)' to 'csio_sm_state_t' (aka 'void (*)(void *, unsigned int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 1369 | if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/csiostor/csio_lnode.c:1373:29: error: cast from 'void (*)(struct csio_lnode *, enum csio_ln_ev)' to 'csio_sm_state_t' (aka 'void (*)(void *, unsigned int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 1373 | if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/csiostor/csio_lnode.c:1377:29: error: cast from 'void (*)(struct csio_lnode *, enum csio_ln_ev)' to 'csio_sm_state_t' (aka 'void (*)(void *, unsigned int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 1377 | if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Move the enum into a shared header so the correct types can be used without the need for casts. Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240213100518.457623-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_defs.h | 18 ++++++++++++++++-- drivers/scsi/csiostor/csio_lnode.c | 8 ++++---- drivers/scsi/csiostor/csio_lnode.h | 13 ------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/csiostor/csio_defs.h b/drivers/scsi/csiostor/csio_defs.h index c38017b4af98..e50e93e7fe5a 100644 --- a/drivers/scsi/csiostor/csio_defs.h +++ b/drivers/scsi/csiostor/csio_defs.h @@ -73,7 +73,21 @@ csio_list_deleted(struct list_head *list) #define csio_list_prev(elem) (((struct list_head *)(elem))->prev) /* State machine */ -typedef void (*csio_sm_state_t)(void *, uint32_t); +struct csio_lnode; + +/* State machine evets */ +enum csio_ln_ev { + CSIO_LNE_NONE = (uint32_t)0, + CSIO_LNE_LINKUP, + CSIO_LNE_FAB_INIT_DONE, + CSIO_LNE_LINK_DOWN, + CSIO_LNE_DOWN_LINK, + CSIO_LNE_LOGO, + CSIO_LNE_CLOSE, + CSIO_LNE_MAX_EVENT, +}; + +typedef void (*csio_sm_state_t)(struct csio_lnode *ln, enum csio_ln_ev evt); struct csio_sm { struct list_head sm_list; @@ -83,7 +97,7 @@ struct csio_sm { static inline void csio_set_state(void *smp, void *state) { - ((struct csio_sm *)smp)->sm_state = (csio_sm_state_t)state; + ((struct csio_sm *)smp)->sm_state = state; } static inline void diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index d5ac93897023..5b3ffefae476 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -1095,7 +1095,7 @@ csio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, int csio_is_lnode_ready(struct csio_lnode *ln) { - return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)); + return (csio_get_state(ln) == csio_lns_ready); } /*****************************************************************************/ @@ -1366,15 +1366,15 @@ csio_free_fcfinfo(struct kref *kref) void csio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str) { - if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) { + if (csio_get_state(ln) == csio_lns_uninit) { strcpy(str, "UNINIT"); return; } - if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) { + if (csio_get_state(ln) == csio_lns_ready) { strcpy(str, "READY"); return; } - if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) { + if (csio_get_state(ln) == csio_lns_offline) { strcpy(str, "OFFLINE"); return; } diff --git a/drivers/scsi/csiostor/csio_lnode.h b/drivers/scsi/csiostor/csio_lnode.h index 372a67d122d3..607698a0f063 100644 --- a/drivers/scsi/csiostor/csio_lnode.h +++ b/drivers/scsi/csiostor/csio_lnode.h @@ -53,19 +53,6 @@ extern int csio_fcoe_rnodes; extern int csio_fdmi_enable; -/* State machine evets */ -enum csio_ln_ev { - CSIO_LNE_NONE = (uint32_t)0, - CSIO_LNE_LINKUP, - CSIO_LNE_FAB_INIT_DONE, - CSIO_LNE_LINK_DOWN, - CSIO_LNE_DOWN_LINK, - CSIO_LNE_LOGO, - CSIO_LNE_CLOSE, - CSIO_LNE_MAX_EVENT, -}; - - struct csio_fcf_info { struct list_head list; uint8_t priority; From bd6d99b70b2ffa96119826f22e96a5b77e6f90d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:48 +0100 Subject: [PATCH 309/814] macintosh: therm_windtunnel: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/74b35a7183dead9cb8359b38356e1a70e720c53e.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/therm_windtunnel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3c1b29476ce2..37cdc6931f6d 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -481,11 +481,9 @@ static int therm_of_probe(struct platform_device *dev) return -ENODEV; } -static int -therm_of_remove( struct platform_device *dev ) +static void therm_of_remove(struct platform_device *dev) { i2c_del_driver( &g4fan_driver ); - return 0; } static const struct of_device_id therm_of_match[] = {{ @@ -501,7 +499,7 @@ static struct platform_driver therm_of_driver = { .of_match_table = therm_of_match, }, .probe = therm_of_probe, - .remove = therm_of_remove, + .remove_new = therm_of_remove, }; struct apple_thermal_info { From 839cf59b5596abcdfbcdc4278a7bd4f8da32e1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:49 +0100 Subject: [PATCH 310/814] macintosh: windfarm_pm112: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/eac991c7f2267237382f77bc15c016ff62e1fbb7.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_pm112.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index d1dec314ae30..876b4d8cbe37 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -662,16 +662,14 @@ static int wf_pm112_probe(struct platform_device *dev) return 0; } -static int wf_pm112_remove(struct platform_device *dev) +static void wf_pm112_remove(struct platform_device *dev) { wf_unregister_client(&pm112_events); - /* should release all sensors and controls */ - return 0; } static struct platform_driver wf_pm112_driver = { .probe = wf_pm112_probe, - .remove = wf_pm112_remove, + .remove_new = wf_pm112_remove, .driver = { .name = "windfarm", }, From 2e7e64c8427c2385bf47456a612d908f827bbbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:50 +0100 Subject: [PATCH 311/814] macintosh: windfarm_pm121: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/36f421f845449a9700f704379105aa5f5db5dd9e.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_pm121.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index 82500417ebee..cd45fbc4fe1c 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -992,15 +992,14 @@ static int pm121_probe(struct platform_device *ddev) return 0; } -static int pm121_remove(struct platform_device *ddev) +static void pm121_remove(struct platform_device *ddev) { wf_unregister_client(&pm121_events); - return 0; } static struct platform_driver pm121_driver = { .probe = pm121_probe, - .remove = pm121_remove, + .remove_new = pm121_remove, .driver = { .name = "windfarm", .bus = &platform_bus_type, From 057894a40e973c829baacce0b9de6bdf6c8ec1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:51 +0100 Subject: [PATCH 312/814] macintosh: windfarm_pm72: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/0406f1db35f23f66fa8a5f8c756fa456601795c4.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_pm72.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c index e21f973551cc..14fa1e9ac3e0 100644 --- a/drivers/macintosh/windfarm_pm72.c +++ b/drivers/macintosh/windfarm_pm72.c @@ -775,17 +775,14 @@ static int wf_pm72_probe(struct platform_device *dev) return 0; } -static int wf_pm72_remove(struct platform_device *dev) +static void wf_pm72_remove(struct platform_device *dev) { wf_unregister_client(&pm72_events); - - /* should release all sensors and controls */ - return 0; } static struct platform_driver wf_pm72_driver = { .probe = wf_pm72_probe, - .remove = wf_pm72_remove, + .remove_new = wf_pm72_remove, .driver = { .name = "windfarm", }, From fb0217d79d77f1092929bae1137ac0f586c29fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:52 +0100 Subject: [PATCH 313/814] macintosh: windfarm_pm81: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/725a17c7fb1bbe6d827b38bbee40494aebf9c06d.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_pm81.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 257fb2c695c5..404d2454e33d 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -724,7 +724,7 @@ static int wf_smu_probe(struct platform_device *ddev) return 0; } -static int wf_smu_remove(struct platform_device *ddev) +static void wf_smu_remove(struct platform_device *ddev) { wf_unregister_client(&wf_smu_events); @@ -761,13 +761,11 @@ static int wf_smu_remove(struct platform_device *ddev) /* Destroy control loops state structures */ kfree(wf_smu_sys_fans); kfree(wf_smu_cpu_fans); - - return 0; } static struct platform_driver wf_smu_driver = { - .probe = wf_smu_probe, - .remove = wf_smu_remove, + .probe = wf_smu_probe, + .remove_new = wf_smu_remove, .driver = { .name = "windfarm", }, From 7cfe99872c711ffa727db85c608a0897955a2758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:53 +0100 Subject: [PATCH 314/814] macintosh: windfarm_pm91: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/398f9079cacd5b87a930181c250aad2ad4d31424.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_pm91.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 120a9cfba0c5..fba02a375435 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -647,7 +647,7 @@ static int wf_smu_probe(struct platform_device *ddev) return 0; } -static int wf_smu_remove(struct platform_device *ddev) +static void wf_smu_remove(struct platform_device *ddev) { wf_unregister_client(&wf_smu_events); @@ -691,13 +691,11 @@ static int wf_smu_remove(struct platform_device *ddev) kfree(wf_smu_slots_fans); kfree(wf_smu_drive_fans); kfree(wf_smu_cpu_fans); - - return 0; } static struct platform_driver wf_smu_driver = { - .probe = wf_smu_probe, - .remove = wf_smu_remove, + .probe = wf_smu_probe, + .remove_new = wf_smu_remove, .driver = { .name = "windfarm", }, From 4b26558415d628ad2c0d3d4ec65156a0c99eaf02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 10 Jan 2024 16:42:54 +0100 Subject: [PATCH 315/814] macintosh: windfarm_rm31: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/42358a12b38c9498b8ab2896d4f3d4eb9484b45e.1704900449.git.u.kleine-koenig@pengutronix.de --- drivers/macintosh/windfarm_rm31.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c index e9eb7fdde48c..dc8f2c7ef103 100644 --- a/drivers/macintosh/windfarm_rm31.c +++ b/drivers/macintosh/windfarm_rm31.c @@ -668,17 +668,14 @@ static int wf_rm31_probe(struct platform_device *dev) return 0; } -static int wf_rm31_remove(struct platform_device *dev) +static void wf_rm31_remove(struct platform_device *dev) { wf_unregister_client(&rm31_events); - - /* should release all sensors and controls */ - return 0; } static struct platform_driver wf_rm31_driver = { .probe = wf_rm31_probe, - .remove = wf_rm31_remove, + .remove_new = wf_rm31_remove, .driver = { .name = "windfarm", }, From 3281366a8e79a512956382885091565db1036b64 Mon Sep 17 00:00:00 2001 From: Peter Bergner Date: Wed, 14 Feb 2024 16:34:06 -0600 Subject: [PATCH 316/814] uapi/auxvec: Define AT_HWCAP3 and AT_HWCAP4 aux vector, entries The powerpc toolchain keeps a copy of the HWCAP bit masks in the TCB for fast access by the __builtin_cpu_supports() built-in function. The TCB space for the HWCAP entries - which are created in pairs - is an ABI extension, so waiting to create the space for HWCAP3 and HWCAP4 until they are needed is problematic. Define AT_HWCAP3 and AT_HWCAP4 in the generic uapi header so they can be used in glibc to reserve space in the powerpc TCB for their future use. I scanned through the Linux and GLIBC source codes looking for unused AT_* values and 29 and 30 did not seem to be used, so they are what I went with. Signed-off-by: Peter Bergner Acked-by: Adhemerval Zanella Acked-by: Nicholas Piggin Acked-by: Szabolcs Nagy Acked-by: Arnd Bergmann Signed-off-by: Michael Ellerman Link: https://msgid.link/a406b535-dc55-4856-8ae9-5a063644a1af@linux.ibm.com --- include/uapi/linux/auxvec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/auxvec.h b/include/uapi/linux/auxvec.h index 6991c4b8ab18..cc61cb9b3e9a 100644 --- a/include/uapi/linux/auxvec.h +++ b/include/uapi/linux/auxvec.h @@ -32,6 +32,8 @@ #define AT_HWCAP2 26 /* extension of AT_HWCAP */ #define AT_RSEQ_FEATURE_SIZE 27 /* rseq supported feature size */ #define AT_RSEQ_ALIGN 28 /* rseq allocation alignment */ +#define AT_HWCAP3 29 /* extension of AT_HWCAP */ +#define AT_HWCAP4 30 /* extension of AT_HWCAP */ #define AT_EXECFN 31 /* filename of program */ From 3312a0e8f64ec68db695224fcc7457e7292426eb Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 14 Feb 2024 13:45:36 +0200 Subject: [PATCH 317/814] dt-bindings: phy: Add Rockchip HDMI/eDP Combo PHY schema Add dt-binding schema for the HDMI/eDP Transmitter Combo PHY found on Rockchip RK3588 SoC. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Heiko Stuebner Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20240214-phy-hdptx-v4-1-e7974f46c1a7@collabora.com Signed-off-by: Vinod Koul --- .../phy/rockchip,rk3588-hdptx-phy.yaml | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml new file mode 100644 index 000000000000..54e822c715f3 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/rockchip,rk3588-hdptx-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC HDMI/eDP Transmitter Combo PHY + +maintainers: + - Cristian Ciocaltea + +properties: + compatible: + enum: + - rockchip,rk3588-hdptx-phy + + reg: + maxItems: 1 + + clocks: + items: + - description: Reference clock + - description: APB clock + + clock-names: + items: + - const: ref + - const: apb + + "#phy-cells": + const: 0 + + resets: + items: + - description: PHY reset line + - description: APB reset line + - description: INIT reset line + - description: CMN reset line + - description: LANE reset line + - description: ROPLL reset line + - description: LCPLL reset line + + reset-names: + items: + - const: phy + - const: apb + - const: init + - const: cmn + - const: lane + - const: ropll + - const: lcpll + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: Some PHY related data is accessed through GRF regs. + +required: + - compatible + - reg + - clocks + - clock-names + - "#phy-cells" + - resets + - reset-names + - rockchip,grf + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + phy@fed60000 { + compatible = "rockchip,rk3588-hdptx-phy"; + reg = <0x0 0xfed60000 0x0 0x2000>; + clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; + clock-names = "ref", "apb"; + #phy-cells = <0>; + resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>, + <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>, + <&cru SRST_HDPTX0_LANE>, <&cru SRST_HDPTX0_ROPLL>, + <&cru SRST_HDPTX0_LCPLL>; + reset-names = "phy", "apb", "init", "cmn", "lane", "ropll", "lcpll"; + rockchip,grf = <&hdptxphy_grf>; + }; + }; From 553be2830c5f33308483e8118de748a2c69fe593 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 14 Feb 2024 13:45:37 +0200 Subject: [PATCH 318/814] phy: rockchip: Add Samsung HDMI/eDP Combo PHY driver Add driver for the HDMI/eDP TX Combo PHY found on Rockchip RK3588 SoC. The PHY is based on a Samsung IP block and supports HDMI 2.1 TMDS, FRL and eDP links. The maximum data rate is 12Gbps (FRL), while the minimum is 250Mbps (TMDS). Only the TMDS link is currently supported. Co-developed-by: Algea Cao Signed-off-by: Algea Cao Tested-by: Heiko Stuebner Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20240214-phy-hdptx-v4-2-e7974f46c1a7@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/Kconfig | 8 + drivers/phy/rockchip/Makefile | 1 + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 1028 +++++++++++++++++ 3 files changed, 1037 insertions(+) create mode 100644 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 94360fc96a6f..a34f67bb7e61 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -83,6 +83,14 @@ config PHY_ROCKCHIP_PCIE help Enable this to support the Rockchip PCIe PHY. +config PHY_ROCKCHIP_SAMSUNG_HDPTX + tristate "Rockchip Samsung HDMI/eDP Combo PHY driver" + depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + select GENERIC_PHY + help + Enable this to support the Rockchip HDMI/eDP Combo PHY + with Samsung IP block. + config PHY_ROCKCHIP_SNPS_PCIE3 tristate "Rockchip Snps PCIe3 PHY Driver" depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 7eab129230d1..3d911304e654 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o +obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX) += phy-rockchip-samsung-hdptx.o obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c new file mode 100644 index 000000000000..946c01210ac8 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -0,0 +1,1028 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 Collabora Ltd. + * + * Author: Algea Cao + * Author: Cristian Ciocaltea + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRF_HDPTX_CON0 0x00 +#define HDPTX_I_PLL_EN BIT(7) +#define HDPTX_I_BIAS_EN BIT(6) +#define HDPTX_I_BGR_EN BIT(5) +#define GRF_HDPTX_STATUS 0x80 +#define HDPTX_O_PLL_LOCK_DONE BIT(3) +#define HDPTX_O_PHY_CLK_RDY BIT(2) +#define HDPTX_O_PHY_RDY BIT(1) +#define HDPTX_O_SB_RDY BIT(0) + +#define HDTPX_REG(_n, _min, _max) \ + ( \ + BUILD_BUG_ON_ZERO((0x##_n) < (0x##_min)) + \ + BUILD_BUG_ON_ZERO((0x##_n) > (0x##_max)) + \ + ((0x##_n) * 4) \ + ) + +#define CMN_REG(n) HDTPX_REG(n, 0000, 00a7) +#define SB_REG(n) HDTPX_REG(n, 0100, 0129) +#define LNTOP_REG(n) HDTPX_REG(n, 0200, 0229) +#define LANE_REG(n) HDTPX_REG(n, 0300, 062d) + +/* CMN_REG(0008) */ +#define LCPLL_EN_MASK BIT(6) +#define LCPLL_LCVCO_MODE_EN_MASK BIT(4) +/* CMN_REG(001e) */ +#define LCPLL_PI_EN_MASK BIT(5) +#define LCPLL_100M_CLK_EN_MASK BIT(0) +/* CMN_REG(0025) */ +#define LCPLL_PMS_IQDIV_RSTN BIT(4) +/* CMN_REG(0028) */ +#define LCPLL_SDC_FRAC_EN BIT(2) +#define LCPLL_SDC_FRAC_RSTN BIT(0) +/* CMN_REG(002d) */ +#define LCPLL_SDC_N_MASK GENMASK(3, 1) +/* CMN_REG(002e) */ +#define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0) +/* CMN_REG(002f) */ +#define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2) +#define LCPLL_SDC_NDIV_RSTN BIT(0) +/* CMN_REG(003d) */ +#define ROPLL_LCVCO_EN BIT(4) +/* CMN_REG(004e) */ +#define ROPLL_PI_EN BIT(5) +/* CMN_REG(005c) */ +#define ROPLL_PMS_IQDIV_RSTN BIT(5) +/* CMN_REG(005e) */ +#define ROPLL_SDM_EN_MASK BIT(6) +#define ROPLL_SDM_FRAC_EN_RBR BIT(3) +#define ROPLL_SDM_FRAC_EN_HBR BIT(2) +#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1) +#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0) +/* CMN_REG(0064) */ +#define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3) +/* CMN_REG(0069) */ +#define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0) +/* CMN_REG(0074) */ +#define ROPLL_SDC_NDIV_RSTN BIT(2) +#define ROPLL_SSC_EN BIT(0) +/* CMN_REG(0081) */ +#define OVRD_PLL_CD_CLK_EN BIT(8) +#define PLL_CD_HSCLK_EAST_EN BIT(0) +/* CMN_REG(0086) */ +#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) +#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) +#define PLL_PCG_CLK_EN BIT(0) +/* CMN_REG(0087) */ +#define PLL_FRL_MODE_EN BIT(3) +#define PLL_TX_HS_CLK_EN BIT(2) +/* CMN_REG(0089) */ +#define LCPLL_ALONE_MODE BIT(1) +/* CMN_REG(0097) */ +#define DIG_CLK_SEL BIT(1) +#define ROPLL_REF BIT(1) +#define LCPLL_REF 0 +/* CMN_REG(0099) */ +#define CMN_ROPLL_ALONE_MODE BIT(2) +#define ROPLL_ALONE_MODE BIT(2) +/* CMN_REG(009a) */ +#define HS_SPEED_SEL BIT(0) +#define DIV_10_CLOCK BIT(0) +/* CMN_REG(009b) */ +#define IS_SPEED_SEL BIT(4) +#define LINK_SYMBOL_CLOCK BIT(4) +#define LINK_SYMBOL_CLOCK1_2 0 + +/* SB_REG(0102) */ +#define OVRD_SB_RXTERM_EN_MASK BIT(5) +#define SB_RXTERM_EN_MASK BIT(4) +#define ANA_SB_RXTERM_OFFSP_MASK GENMASK(3, 0) +/* SB_REG(0103) */ +#define ANA_SB_RXTERM_OFFSN_MASK GENMASK(6, 3) +#define OVRD_SB_RX_RESCAL_DONE_MASK BIT(1) +#define SB_RX_RESCAL_DONE_MASK BIT(0) +/* SB_REG(0104) */ +#define OVRD_SB_EN_MASK BIT(5) +#define SB_EN_MASK BIT(4) +/* SB_REG(0105) */ +#define OVRD_SB_EARC_CMDC_EN_MASK BIT(6) +#define SB_EARC_CMDC_EN_MASK BIT(5) +#define ANA_SB_TX_HLVL_PROG_MASK GENMASK(2, 0) +/* SB_REG(0106) */ +#define ANA_SB_TX_LLVL_PROG_MASK GENMASK(6, 4) +/* SB_REG(0109) */ +#define ANA_SB_DMRX_AFC_DIV_RATIO_MASK GENMASK(2, 0) +/* SB_REG(010f) */ +#define OVRD_SB_VREG_EN_MASK BIT(7) +#define SB_VREG_EN_MASK BIT(6) +#define OVRD_SB_VREG_LPF_BYPASS_MASK BIT(5) +#define SB_VREG_LPF_BYPASS_MASK BIT(4) +#define ANA_SB_VREG_GAIN_CTRL_MASK GENMASK(3, 0) +/* SB_REG(0110) */ +#define ANA_SB_VREG_REF_SEL_MASK BIT(0) +/* SB_REG(0113) */ +#define SB_RX_RCAL_OPT_CODE_MASK GENMASK(5, 4) +#define SB_RX_RTERM_CTRL_MASK GENMASK(3, 0) +/* SB_REG(0114) */ +#define SB_TG_SB_EN_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_TG_RXTERM_EN_DELAY_TIME_MASK GENMASK(2, 0) +/* SB_REG(0115) */ +#define SB_READY_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_TG_OSC_EN_DELAY_TIME_MASK GENMASK(2, 0) +/* SB_REG(0116) */ +#define AFC_RSTN_DELAY_TIME_MASK GENMASK(6, 4) +/* SB_REG(0117) */ +#define FAST_PULSE_TIME_MASK GENMASK(3, 0) +/* SB_REG(011b) */ +#define SB_EARC_SIG_DET_BYPASS_MASK BIT(4) +#define SB_AFC_TOL_MASK GENMASK(3, 0) +/* SB_REG(011f) */ +#define SB_PWM_AFC_CTRL_MASK GENMASK(7, 2) +#define SB_RCAL_RSTN_MASK BIT(1) +/* SB_REG(0120) */ +#define SB_EARC_EN_MASK BIT(1) +#define SB_EARC_AFC_EN_MASK BIT(2) +/* SB_REG(0123) */ +#define OVRD_SB_READY_MASK BIT(5) +#define SB_READY_MASK BIT(4) + +/* LNTOP_REG(0200) */ +#define PROTOCOL_SEL BIT(2) +#define HDMI_MODE BIT(2) +#define HDMI_TMDS_FRL_SEL BIT(1) +/* LNTOP_REG(0206) */ +#define DATA_BUS_SEL BIT(0) +#define DATA_BUS_36_40 BIT(0) +/* LNTOP_REG(0207) */ +#define LANE_EN 0xf +#define ALL_LANE_EN 0xf + +/* LANE_REG(0312) */ +#define LN0_TX_SER_RATE_SEL_RBR BIT(5) +#define LN0_TX_SER_RATE_SEL_HBR BIT(4) +#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2) +/* LANE_REG(0412) */ +#define LN1_TX_SER_RATE_SEL_RBR BIT(5) +#define LN1_TX_SER_RATE_SEL_HBR BIT(4) +#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2) +/* LANE_REG(0512) */ +#define LN2_TX_SER_RATE_SEL_RBR BIT(5) +#define LN2_TX_SER_RATE_SEL_HBR BIT(4) +#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2) +/* LANE_REG(0612) */ +#define LN3_TX_SER_RATE_SEL_RBR BIT(5) +#define LN3_TX_SER_RATE_SEL_HBR BIT(4) +#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) + +struct lcpll_config { + u32 bit_rate; + u8 lcvco_mode_en; + u8 pi_en; + u8 clk_en_100m; + u8 pms_mdiv; + u8 pms_mdiv_afc; + u8 pms_pdiv; + u8 pms_refdiv; + u8 pms_sdiv; + u8 pi_cdiv_rstn; + u8 pi_cdiv_sel; + u8 sdm_en; + u8 sdm_rstn; + u8 sdc_frac_en; + u8 sdc_rstn; + u8 sdm_deno; + u8 sdm_num_sign; + u8 sdm_num; + u8 sdc_n; + u8 sdc_n2; + u8 sdc_num; + u8 sdc_deno; + u8 sdc_ndiv_rstn; + u8 ssc_en; + u8 ssc_fm_dev; + u8 ssc_fm_freq; + u8 ssc_clk_div_sel; + u8 cd_tx_ser_rate_sel; +}; + +struct ropll_config { + u32 bit_rate; + u8 pms_mdiv; + u8 pms_mdiv_afc; + u8 pms_pdiv; + u8 pms_refdiv; + u8 pms_sdiv; + u8 pms_iqdiv_rstn; + u8 ref_clk_sel; + u8 sdm_en; + u8 sdm_rstn; + u8 sdc_frac_en; + u8 sdc_rstn; + u8 sdm_clk_div; + u8 sdm_deno; + u8 sdm_num_sign; + u8 sdm_num; + u8 sdc_n; + u8 sdc_num; + u8 sdc_deno; + u8 sdc_ndiv_rstn; + u8 ssc_en; + u8 ssc_fm_dev; + u8 ssc_fm_freq; + u8 ssc_clk_div_sel; + u8 ana_cpp_ctrl; + u8 ana_lpf_c_sel; + u8 cd_tx_ser_rate_sel; +}; + +enum rk_hdptx_reset { + RST_PHY = 0, + RST_APB, + RST_INIT, + RST_CMN, + RST_LANE, + RST_ROPLL, + RST_LCPLL, + RST_MAX +}; + +struct rk_hdptx_phy { + struct device *dev; + struct regmap *regmap; + struct regmap *grf; + + struct phy *phy; + struct phy_config *phy_cfg; + struct clk_bulk_data *clks; + int nr_clks; + struct reset_control_bulk_data rsts[RST_MAX]; +}; + +static const struct ropll_config ropll_tmds_cfg[] = { + { 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1540000, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, + 0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1462500, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1190000, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 855000, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5, + 1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +}; + +static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = { + REG_SEQ0(CMN_REG(0009), 0x0c), + REG_SEQ0(CMN_REG(000a), 0x83), + REG_SEQ0(CMN_REG(000b), 0x06), + REG_SEQ0(CMN_REG(000c), 0x20), + REG_SEQ0(CMN_REG(000d), 0xb8), + REG_SEQ0(CMN_REG(000e), 0x0f), + REG_SEQ0(CMN_REG(000f), 0x0f), + REG_SEQ0(CMN_REG(0010), 0x04), + REG_SEQ0(CMN_REG(0011), 0x00), + REG_SEQ0(CMN_REG(0012), 0x26), + REG_SEQ0(CMN_REG(0013), 0x22), + REG_SEQ0(CMN_REG(0014), 0x24), + REG_SEQ0(CMN_REG(0015), 0x77), + REG_SEQ0(CMN_REG(0016), 0x08), + REG_SEQ0(CMN_REG(0017), 0x00), + REG_SEQ0(CMN_REG(0018), 0x04), + REG_SEQ0(CMN_REG(0019), 0x48), + REG_SEQ0(CMN_REG(001a), 0x01), + REG_SEQ0(CMN_REG(001b), 0x00), + REG_SEQ0(CMN_REG(001c), 0x01), + REG_SEQ0(CMN_REG(001d), 0x64), + REG_SEQ0(CMN_REG(001f), 0x00), + REG_SEQ0(CMN_REG(0026), 0x53), + REG_SEQ0(CMN_REG(0029), 0x01), + REG_SEQ0(CMN_REG(0030), 0x00), + REG_SEQ0(CMN_REG(0031), 0x20), + REG_SEQ0(CMN_REG(0032), 0x30), + REG_SEQ0(CMN_REG(0033), 0x0b), + REG_SEQ0(CMN_REG(0034), 0x23), + REG_SEQ0(CMN_REG(0035), 0x00), + REG_SEQ0(CMN_REG(0038), 0x00), + REG_SEQ0(CMN_REG(0039), 0x00), + REG_SEQ0(CMN_REG(003a), 0x00), + REG_SEQ0(CMN_REG(003b), 0x00), + REG_SEQ0(CMN_REG(003c), 0x80), + REG_SEQ0(CMN_REG(003e), 0x0c), + REG_SEQ0(CMN_REG(003f), 0x83), + REG_SEQ0(CMN_REG(0040), 0x06), + REG_SEQ0(CMN_REG(0041), 0x20), + REG_SEQ0(CMN_REG(0042), 0xb8), + REG_SEQ0(CMN_REG(0043), 0x00), + REG_SEQ0(CMN_REG(0044), 0x46), + REG_SEQ0(CMN_REG(0045), 0x24), + REG_SEQ0(CMN_REG(0046), 0xff), + REG_SEQ0(CMN_REG(0047), 0x00), + REG_SEQ0(CMN_REG(0048), 0x44), + REG_SEQ0(CMN_REG(0049), 0xfa), + REG_SEQ0(CMN_REG(004a), 0x08), + REG_SEQ0(CMN_REG(004b), 0x00), + REG_SEQ0(CMN_REG(004c), 0x01), + REG_SEQ0(CMN_REG(004d), 0x64), + REG_SEQ0(CMN_REG(004e), 0x14), + REG_SEQ0(CMN_REG(004f), 0x00), + REG_SEQ0(CMN_REG(0050), 0x00), + REG_SEQ0(CMN_REG(005d), 0x0c), + REG_SEQ0(CMN_REG(005f), 0x01), + REG_SEQ0(CMN_REG(006b), 0x04), + REG_SEQ0(CMN_REG(0073), 0x30), + REG_SEQ0(CMN_REG(0074), 0x00), + REG_SEQ0(CMN_REG(0075), 0x20), + REG_SEQ0(CMN_REG(0076), 0x30), + REG_SEQ0(CMN_REG(0077), 0x08), + REG_SEQ0(CMN_REG(0078), 0x0c), + REG_SEQ0(CMN_REG(0079), 0x00), + REG_SEQ0(CMN_REG(007b), 0x00), + REG_SEQ0(CMN_REG(007c), 0x00), + REG_SEQ0(CMN_REG(007d), 0x00), + REG_SEQ0(CMN_REG(007e), 0x00), + REG_SEQ0(CMN_REG(007f), 0x00), + REG_SEQ0(CMN_REG(0080), 0x00), + REG_SEQ0(CMN_REG(0081), 0x09), + REG_SEQ0(CMN_REG(0082), 0x04), + REG_SEQ0(CMN_REG(0083), 0x24), + REG_SEQ0(CMN_REG(0084), 0x20), + REG_SEQ0(CMN_REG(0085), 0x03), + REG_SEQ0(CMN_REG(0086), 0x01), + REG_SEQ0(CMN_REG(0087), 0x0c), + REG_SEQ0(CMN_REG(008a), 0x55), + REG_SEQ0(CMN_REG(008b), 0x25), + REG_SEQ0(CMN_REG(008c), 0x2c), + REG_SEQ0(CMN_REG(008d), 0x22), + REG_SEQ0(CMN_REG(008e), 0x14), + REG_SEQ0(CMN_REG(008f), 0x20), + REG_SEQ0(CMN_REG(0090), 0x00), + REG_SEQ0(CMN_REG(0091), 0x00), + REG_SEQ0(CMN_REG(0092), 0x00), + REG_SEQ0(CMN_REG(0093), 0x00), + REG_SEQ0(CMN_REG(009a), 0x11), + REG_SEQ0(CMN_REG(009b), 0x10), +}; + +static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = { + REG_SEQ0(CMN_REG(0008), 0x00), + REG_SEQ0(CMN_REG(0011), 0x01), + REG_SEQ0(CMN_REG(0017), 0x20), + REG_SEQ0(CMN_REG(001e), 0x14), + REG_SEQ0(CMN_REG(0020), 0x00), + REG_SEQ0(CMN_REG(0021), 0x00), + REG_SEQ0(CMN_REG(0022), 0x11), + REG_SEQ0(CMN_REG(0023), 0x00), + REG_SEQ0(CMN_REG(0024), 0x00), + REG_SEQ0(CMN_REG(0025), 0x53), + REG_SEQ0(CMN_REG(0026), 0x00), + REG_SEQ0(CMN_REG(0027), 0x00), + REG_SEQ0(CMN_REG(0028), 0x01), + REG_SEQ0(CMN_REG(002a), 0x00), + REG_SEQ0(CMN_REG(002b), 0x00), + REG_SEQ0(CMN_REG(002c), 0x00), + REG_SEQ0(CMN_REG(002d), 0x00), + REG_SEQ0(CMN_REG(002e), 0x04), + REG_SEQ0(CMN_REG(002f), 0x00), + REG_SEQ0(CMN_REG(0030), 0x20), + REG_SEQ0(CMN_REG(0031), 0x30), + REG_SEQ0(CMN_REG(0032), 0x0b), + REG_SEQ0(CMN_REG(0033), 0x23), + REG_SEQ0(CMN_REG(0034), 0x00), + REG_SEQ0(CMN_REG(003d), 0x40), + REG_SEQ0(CMN_REG(0042), 0x78), + REG_SEQ0(CMN_REG(004e), 0x34), + REG_SEQ0(CMN_REG(005c), 0x25), + REG_SEQ0(CMN_REG(005e), 0x4f), + REG_SEQ0(CMN_REG(0074), 0x04), + REG_SEQ0(CMN_REG(0081), 0x01), + REG_SEQ0(CMN_REG(0087), 0x04), + REG_SEQ0(CMN_REG(0089), 0x00), + REG_SEQ0(CMN_REG(0095), 0x00), + REG_SEQ0(CMN_REG(0097), 0x02), + REG_SEQ0(CMN_REG(0099), 0x04), + REG_SEQ0(CMN_REG(009b), 0x00), +}; + +static const struct reg_sequence rk_hdtpx_common_sb_init_seq[] = { + REG_SEQ0(SB_REG(0114), 0x00), + REG_SEQ0(SB_REG(0115), 0x00), + REG_SEQ0(SB_REG(0116), 0x00), + REG_SEQ0(SB_REG(0117), 0x00), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = { + REG_SEQ0(LNTOP_REG(0201), 0x00), + REG_SEQ0(LNTOP_REG(0202), 0x00), + REG_SEQ0(LNTOP_REG(0203), 0x0f), + REG_SEQ0(LNTOP_REG(0204), 0xff), + REG_SEQ0(LNTOP_REG(0205), 0xff), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = { + REG_SEQ0(LNTOP_REG(0201), 0x07), + REG_SEQ0(LNTOP_REG(0202), 0xc1), + REG_SEQ0(LNTOP_REG(0203), 0xf0), + REG_SEQ0(LNTOP_REG(0204), 0x7c), + REG_SEQ0(LNTOP_REG(0205), 0x1f), +}; + +static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = { + REG_SEQ0(LANE_REG(0303), 0x0c), + REG_SEQ0(LANE_REG(0307), 0x20), + REG_SEQ0(LANE_REG(030a), 0x17), + REG_SEQ0(LANE_REG(030b), 0x77), + REG_SEQ0(LANE_REG(030c), 0x77), + REG_SEQ0(LANE_REG(030d), 0x77), + REG_SEQ0(LANE_REG(030e), 0x38), + REG_SEQ0(LANE_REG(0310), 0x03), + REG_SEQ0(LANE_REG(0311), 0x0f), + REG_SEQ0(LANE_REG(0316), 0x02), + REG_SEQ0(LANE_REG(031b), 0x01), + REG_SEQ0(LANE_REG(031f), 0x15), + REG_SEQ0(LANE_REG(0320), 0xa0), + REG_SEQ0(LANE_REG(0403), 0x0c), + REG_SEQ0(LANE_REG(0407), 0x20), + REG_SEQ0(LANE_REG(040a), 0x17), + REG_SEQ0(LANE_REG(040b), 0x77), + REG_SEQ0(LANE_REG(040c), 0x77), + REG_SEQ0(LANE_REG(040d), 0x77), + REG_SEQ0(LANE_REG(040e), 0x38), + REG_SEQ0(LANE_REG(0410), 0x03), + REG_SEQ0(LANE_REG(0411), 0x0f), + REG_SEQ0(LANE_REG(0416), 0x02), + REG_SEQ0(LANE_REG(041b), 0x01), + REG_SEQ0(LANE_REG(041f), 0x15), + REG_SEQ0(LANE_REG(0420), 0xa0), + REG_SEQ0(LANE_REG(0503), 0x0c), + REG_SEQ0(LANE_REG(0507), 0x20), + REG_SEQ0(LANE_REG(050a), 0x17), + REG_SEQ0(LANE_REG(050b), 0x77), + REG_SEQ0(LANE_REG(050c), 0x77), + REG_SEQ0(LANE_REG(050d), 0x77), + REG_SEQ0(LANE_REG(050e), 0x38), + REG_SEQ0(LANE_REG(0510), 0x03), + REG_SEQ0(LANE_REG(0511), 0x0f), + REG_SEQ0(LANE_REG(0516), 0x02), + REG_SEQ0(LANE_REG(051b), 0x01), + REG_SEQ0(LANE_REG(051f), 0x15), + REG_SEQ0(LANE_REG(0520), 0xa0), + REG_SEQ0(LANE_REG(0603), 0x0c), + REG_SEQ0(LANE_REG(0607), 0x20), + REG_SEQ0(LANE_REG(060a), 0x17), + REG_SEQ0(LANE_REG(060b), 0x77), + REG_SEQ0(LANE_REG(060c), 0x77), + REG_SEQ0(LANE_REG(060d), 0x77), + REG_SEQ0(LANE_REG(060e), 0x38), + REG_SEQ0(LANE_REG(0610), 0x03), + REG_SEQ0(LANE_REG(0611), 0x0f), + REG_SEQ0(LANE_REG(0616), 0x02), + REG_SEQ0(LANE_REG(061b), 0x01), + REG_SEQ0(LANE_REG(061f), 0x15), + REG_SEQ0(LANE_REG(0620), 0xa0), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { + REG_SEQ0(LANE_REG(0312), 0x00), + REG_SEQ0(LANE_REG(031e), 0x00), + REG_SEQ0(LANE_REG(0412), 0x00), + REG_SEQ0(LANE_REG(041e), 0x00), + REG_SEQ0(LANE_REG(0512), 0x00), + REG_SEQ0(LANE_REG(051e), 0x00), + REG_SEQ0(LANE_REG(0612), 0x00), + REG_SEQ0(LANE_REG(061e), 0x08), + REG_SEQ0(LANE_REG(0303), 0x2f), + REG_SEQ0(LANE_REG(0403), 0x2f), + REG_SEQ0(LANE_REG(0503), 0x2f), + REG_SEQ0(LANE_REG(0603), 0x2f), + REG_SEQ0(LANE_REG(0305), 0x03), + REG_SEQ0(LANE_REG(0405), 0x03), + REG_SEQ0(LANE_REG(0505), 0x03), + REG_SEQ0(LANE_REG(0605), 0x03), + REG_SEQ0(LANE_REG(0306), 0x1c), + REG_SEQ0(LANE_REG(0406), 0x1c), + REG_SEQ0(LANE_REG(0506), 0x1c), + REG_SEQ0(LANE_REG(0606), 0x1c), +}; + +static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0000 ... 0x029c: + case 0x0400 ... 0x04a4: + case 0x0800 ... 0x08a4: + case 0x0c00 ... 0x0cb4: + case 0x1000 ... 0x10b4: + case 0x1400 ... 0x14b4: + case 0x1800 ... 0x18b4: + return true; + } + + return false; +} + +static const struct regmap_config rk_hdptx_phy_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .writeable_reg = rk_hdptx_phy_is_rw_reg, + .readable_reg = rk_hdptx_phy_is_rw_reg, + .fast_io = true, + .max_register = 0x18b4, +}; + +#define rk_hdptx_multi_reg_write(hdptx, seq) \ + regmap_multi_reg_write((hdptx)->regmap, seq, ARRAY_SIZE(seq)) + +static void rk_hdptx_pre_power_up(struct rk_hdptx_phy *hdptx) +{ + u32 val; + + reset_control_assert(hdptx->rsts[RST_APB].rstc); + usleep_range(20, 25); + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + + reset_control_assert(hdptx->rsts[RST_LANE].rstc); + reset_control_assert(hdptx->rsts[RST_CMN].rstc); + reset_control_assert(hdptx->rsts[RST_INIT].rstc); + + val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); +} + +static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx) +{ + u32 val; + int ret; + + reset_control_deassert(hdptx->rsts[RST_LANE].rstc); + + val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | + HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, + (val & HDPTX_O_PHY_RDY) && + (val & HDPTX_O_PLL_LOCK_DONE), + 100, 5000); + if (ret) { + dev_err(hdptx->dev, "Failed to get PHY lane lock: %d\n", ret); + return ret; + } + + dev_dbg(hdptx->dev, "PHY lane locked\n"); + + return 0; +} + +static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx) +{ + u32 val; + int ret; + + val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | + HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + usleep_range(10, 15); + reset_control_deassert(hdptx->rsts[RST_INIT].rstc); + + usleep_range(10, 15); + val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + usleep_range(10, 15); + reset_control_deassert(hdptx->rsts[RST_CMN].rstc); + + ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, + val & HDPTX_O_PHY_CLK_RDY, 20, 400); + if (ret) { + dev_err(hdptx->dev, "Failed to get PHY clk ready: %d\n", ret); + return ret; + } + + dev_dbg(hdptx->dev, "PHY clk ready\n"); + + return 0; +} + +static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) +{ + u32 val; + + /* reset phy and apb, or phy locked flag may keep 1 */ + reset_control_assert(hdptx->rsts[RST_PHY].rstc); + usleep_range(20, 30); + reset_control_deassert(hdptx->rsts[RST_PHY].rstc); + + reset_control_assert(hdptx->rsts[RST_APB].rstc); + usleep_range(20, 30); + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + + regmap_write(hdptx->regmap, LANE_REG(0300), 0x82); + regmap_write(hdptx->regmap, SB_REG(010f), 0xc1); + regmap_write(hdptx->regmap, SB_REG(0110), 0x1); + regmap_write(hdptx->regmap, LANE_REG(0301), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0401), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0501), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0601), 0x80); + + reset_control_assert(hdptx->rsts[RST_LANE].rstc); + reset_control_assert(hdptx->rsts[RST_CMN].rstc); + reset_control_assert(hdptx->rsts[RST_INIT].rstc); + + val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); +} + +static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate, + struct ropll_config *cfg) +{ + const unsigned int fout = data_rate / 2, fref = 24000; + unsigned long k = 0, lc, k_sub, lc_sub; + unsigned int fvco, sdc; + u32 mdiv, sdiv, n = 8; + + if (fout > 0xfffffff) + return false; + + for (sdiv = 16; sdiv >= 1; sdiv--) { + if (sdiv % 2 && sdiv != 1) + continue; + + fvco = fout * sdiv; + + if (fvco < 2000000 || fvco > 4000000) + continue; + + mdiv = DIV_ROUND_UP(fvco, fref); + if (mdiv < 20 || mdiv > 255) + continue; + + if (fref * mdiv - fvco) { + for (sdc = 264000; sdc <= 750000; sdc += fref) + if (sdc * n > fref * mdiv) + break; + + if (sdc > 750000) + continue; + + rational_best_approximation(fref * mdiv - fvco, + sdc / 16, + GENMASK(6, 0), + GENMASK(7, 0), + &k, &lc); + + rational_best_approximation(sdc * n - fref * mdiv, + sdc, + GENMASK(6, 0), + GENMASK(7, 0), + &k_sub, &lc_sub); + } + + break; + } + + if (sdiv < 1) + return false; + + if (cfg) { + cfg->pms_mdiv = mdiv; + cfg->pms_mdiv_afc = mdiv; + cfg->pms_pdiv = 1; + cfg->pms_refdiv = 1; + cfg->pms_sdiv = sdiv - 1; + + cfg->sdm_en = k > 0 ? 1 : 0; + if (cfg->sdm_en) { + cfg->sdm_deno = lc; + cfg->sdm_num_sign = 1; + cfg->sdm_num = k; + cfg->sdc_n = n - 3; + cfg->sdc_num = k_sub; + cfg->sdc_deno = lc_sub; + } + } + + return true; +} + +static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, + unsigned int rate) +{ + const struct ropll_config *cfg = NULL; + struct ropll_config rc = {0}; + int i; + + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) + if (rate == ropll_tmds_cfg[i].bit_rate) { + cfg = &ropll_tmds_cfg[i]; + break; + } + + if (!cfg) { + if (rk_hdptx_phy_clk_pll_calc(rate, &rc)) { + cfg = &rc; + } else { + dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__); + return -EINVAL; + } + } + + dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u, sdm_en=%u, k_sign=%u, k=%u, lc=%u\n", + cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en, + cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); + + rk_hdptx_pre_power_up(hdptx); + + reset_control_assert(hdptx->rsts[RST_ROPLL].rstc); + usleep_range(20, 30); + reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc); + + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq); + + regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv); + regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc); + regmap_write(hdptx->regmap, CMN_REG(0059), + (cfg->pms_pdiv << 4) | cfg->pms_refdiv); + regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4); + + regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK, + FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en)); + if (!cfg->sdm_en) + regmap_update_bits(hdptx->regmap, CMN_REG(005e), 0xf, 0); + + regmap_update_bits(hdptx->regmap, CMN_REG(0064), ROPLL_SDM_NUM_SIGN_RBR_MASK, + FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, cfg->sdm_num_sign)); + + regmap_write(hdptx->regmap, CMN_REG(0060), cfg->sdm_deno); + regmap_write(hdptx->regmap, CMN_REG(0065), cfg->sdm_num); + + regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK, + FIELD_PREP(ROPLL_SDC_N_RBR_MASK, cfg->sdc_n)); + + regmap_write(hdptx->regmap, CMN_REG(006c), cfg->sdc_num); + regmap_write(hdptx->regmap, CMN_REG(0070), cfg->sdc_deno); + + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, + FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); + + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN, + PLL_PCG_CLK_EN); + + return rk_hdptx_post_enable_pll(hdptx); +} + +static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, + unsigned int rate) +{ + u32 val; + int ret; + + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); + if (ret) + return ret; + + if (!(val & HDPTX_O_PLL_LOCK_DONE)) { + ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); + if (ret) + return ret; + } + + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); + + regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); + + if (rate >= 3400000) { + /* For 1/40 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq); + } else { + /* For 1/10 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_lowbr_seq); + } + + regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07); + regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f); + + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq); + + return rk_hdptx_post_enable_lane(hdptx); +} + +static int rk_hdptx_phy_power_on(struct phy *phy) +{ + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + int ret, bus_width = phy_get_bus_width(hdptx->phy); + /* + * FIXME: Temporary workaround to pass pixel_clk_rate + * from the HDMI bridge driver until phy_configure_opts_hdmi + * becomes available in the PHY API. + */ + unsigned int rate = bus_width & 0xfffffff; + + dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n", + __func__, bus_width, rate); + + ret = pm_runtime_resume_and_get(hdptx->dev); + if (ret) { + dev_err(hdptx->dev, "Failed to resume phy: %d\n", ret); + return ret; + } + + ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); + if (ret) + pm_runtime_put(hdptx->dev); + + return ret; +} + +static int rk_hdptx_phy_power_off(struct phy *phy) +{ + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + u32 val; + int ret; + + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); + if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) + rk_hdptx_phy_disable(hdptx); + + pm_runtime_put(hdptx->dev); + + return ret; +} + +static const struct phy_ops rk_hdptx_phy_ops = { + .power_on = rk_hdptx_phy_power_on, + .power_off = rk_hdptx_phy_power_off, + .owner = THIS_MODULE, +}; + +static int rk_hdptx_phy_runtime_suspend(struct device *dev) +{ + struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(hdptx->nr_clks, hdptx->clks); + + return 0; +} + +static int rk_hdptx_phy_runtime_resume(struct device *dev) +{ + struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(hdptx->nr_clks, hdptx->clks); + if (ret) + dev_err(hdptx->dev, "Failed to enable clocks: %d\n", ret); + + return ret; +} + +static int rk_hdptx_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct rk_hdptx_phy *hdptx; + void __iomem *regs; + int ret; + + hdptx = devm_kzalloc(dev, sizeof(*hdptx), GFP_KERNEL); + if (!hdptx) + return -ENOMEM; + + hdptx->dev = dev; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), + "Failed to ioremap resource\n"); + + ret = devm_clk_bulk_get_all(dev, &hdptx->clks); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get clocks\n"); + if (ret == 0) + return dev_err_probe(dev, -EINVAL, "Missing clocks\n"); + + hdptx->nr_clks = ret; + + hdptx->regmap = devm_regmap_init_mmio(dev, regs, + &rk_hdptx_phy_regmap_config); + if (IS_ERR(hdptx->regmap)) + return dev_err_probe(dev, PTR_ERR(hdptx->regmap), + "Failed to init regmap\n"); + + hdptx->rsts[RST_PHY].id = "phy"; + hdptx->rsts[RST_APB].id = "apb"; + hdptx->rsts[RST_INIT].id = "init"; + hdptx->rsts[RST_CMN].id = "cmn"; + hdptx->rsts[RST_LANE].id = "lane"; + hdptx->rsts[RST_ROPLL].id = "ropll"; + hdptx->rsts[RST_LCPLL].id = "lcpll"; + + ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts); + if (ret) + return dev_err_probe(dev, ret, "Failed to get resets\n"); + + hdptx->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(hdptx->grf)) + return dev_err_probe(dev, PTR_ERR(hdptx->grf), + "Could not get GRF syscon\n"); + + hdptx->phy = devm_phy_create(dev, NULL, &rk_hdptx_phy_ops); + if (IS_ERR(hdptx->phy)) + return dev_err_probe(dev, PTR_ERR(hdptx->phy), + "Failed to create HDMI PHY\n"); + + platform_set_drvdata(pdev, hdptx); + phy_set_drvdata(hdptx->phy, hdptx); + phy_set_bus_width(hdptx->phy, 8); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return dev_err_probe(dev, PTR_ERR(phy_provider), + "Failed to register PHY provider\n"); + + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + reset_control_deassert(hdptx->rsts[RST_CMN].rstc); + reset_control_deassert(hdptx->rsts[RST_INIT].rstc); + + return 0; +} + +static const struct dev_pm_ops rk_hdptx_phy_pm_ops = { + RUNTIME_PM_OPS(rk_hdptx_phy_runtime_suspend, + rk_hdptx_phy_runtime_resume, NULL) +}; + +static const struct of_device_id rk_hdptx_phy_of_match[] = { + { .compatible = "rockchip,rk3588-hdptx-phy", }, + {} +}; +MODULE_DEVICE_TABLE(of, rk_hdptx_phy_of_match); + +static struct platform_driver rk_hdptx_phy_driver = { + .probe = rk_hdptx_phy_probe, + .driver = { + .name = "rockchip-hdptx-phy", + .pm = &rk_hdptx_phy_pm_ops, + .of_match_table = rk_hdptx_phy_of_match, + }, +}; +module_platform_driver(rk_hdptx_phy_driver); + +MODULE_AUTHOR("Algea Cao "); +MODULE_AUTHOR("Cristian Ciocaltea "); +MODULE_DESCRIPTION("Samsung HDMI/eDP Transmitter Combo PHY Driver"); +MODULE_LICENSE("GPL"); From 03db1786fe9eae146ba9b3e4fd220f1e502d588b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2024 18:02:14 +0200 Subject: [PATCH 319/814] phy: ti: tusb1210: Use temporary variable for struct device Use temporary variable for struct device to make code neater. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240209160334.2304230-2-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-tusb1210.c | 47 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index b4881cb34475..7232b104a62d 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -52,7 +52,7 @@ enum tusb1210_chg_det_state { }; struct tusb1210 { - struct ulpi *ulpi; + struct device *dev; struct phy *phy; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_cs; @@ -71,26 +71,27 @@ struct tusb1210 { static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val) { + struct device *dev = tusb->dev; int ret; - ret = ulpi_write(tusb->ulpi, reg, val); + ret = ulpi_write(to_ulpi_dev(dev), reg, val); if (ret) - dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n", - ret, val, reg); + dev_err(dev, "error %d writing val 0x%02x to reg 0x%02x\n", ret, val, reg); return ret; } static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val) { + struct device *dev = tusb->dev; int ret; - ret = ulpi_read(tusb->ulpi, reg); + ret = ulpi_read(to_ulpi_dev(dev), reg); if (ret >= 0) { *val = ret; ret = 0; } else { - dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg); + dev_err(dev, "error %d reading reg 0x%02x\n", ret, reg); } return ret; @@ -178,7 +179,7 @@ static void tusb1210_reset(struct tusb1210 *tusb) static void tusb1210_chg_det_set_type(struct tusb1210 *tusb, enum power_supply_usb_type type) { - dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type); + dev_dbg(tusb->dev, "charger type: %d\n", type); tusb->chg_type = type; tusb->chg_det_retries = 0; power_supply_changed(tusb->psy); @@ -189,7 +190,7 @@ static void tusb1210_chg_det_set_state(struct tusb1210 *tusb, int delay_ms) { if (delay_ms) - dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n", + dev_dbg(tusb->dev, "chg_det new state %s in %d ms\n", tusb1210_chg_det_states[new_state], delay_ms); tusb->chg_det_state = new_state; @@ -253,7 +254,7 @@ static void tusb1210_chg_det_work(struct work_struct *work) int ret; u8 val; - dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n", + dev_dbg(tusb->dev, "chg_det state %s vbus_present %d\n", tusb1210_chg_det_states[tusb->chg_det_state], vbus_present); switch (tusb->chg_det_state) { @@ -261,9 +262,9 @@ static void tusb1210_chg_det_work(struct work_struct *work) tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; tusb->chg_det_retries = 0; /* Power on USB controller for ulpi_read()/_write() */ - ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent); + ret = pm_runtime_resume_and_get(tusb->dev->parent); if (ret < 0) { - dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret); + dev_err(tusb->dev, "error %d runtime-resuming\n", ret); /* Should never happen, skip charger detection */ tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); return; @@ -332,7 +333,7 @@ static void tusb1210_chg_det_work(struct work_struct *work) mutex_unlock(&tusb->phy->mutex); - pm_runtime_put(tusb->ulpi->dev.parent); + pm_runtime_put(tusb->dev->parent); tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); break; case TUSB1210_CHG_DET_CONNECTED: @@ -428,13 +429,14 @@ static const struct power_supply_desc tusb1210_psy_desc = { static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { struct power_supply_config psy_cfg = { .drv_data = tusb }; - struct device *dev = &tusb->ulpi->dev; + struct device *dev = tusb->dev; + struct ulpi *ulpi = to_ulpi_dev(dev); int ret; if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect")) return; - if (tusb->ulpi->id.product != 0x1508) { + if (ulpi->id.product != 0x1508) { dev_err(dev, "error charger detection is only supported on the TUSB1211\n"); return; } @@ -485,25 +487,24 @@ static const struct phy_ops phy_ops = { static int tusb1210_probe(struct ulpi *ulpi) { + struct device *dev = &ulpi->dev; struct tusb1210 *tusb; u8 val, reg; int ret; - tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL); + tusb = devm_kzalloc(dev, sizeof(*tusb), GFP_KERNEL); if (!tusb) return -ENOMEM; - tusb->ulpi = ulpi; + tusb->dev = dev; - tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset", - GPIOD_OUT_LOW); + tusb->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(tusb->gpio_reset)) return PTR_ERR(tusb->gpio_reset); gpiod_set_value_cansleep(tusb->gpio_reset, 1); - tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs", - GPIOD_OUT_LOW); + tusb->gpio_cs = devm_gpiod_get_optional(dev, "cs", GPIOD_OUT_LOW); if (IS_ERR(tusb->gpio_cs)) return PTR_ERR(tusb->gpio_cs); @@ -519,15 +520,15 @@ static int tusb1210_probe(struct ulpi *ulpi) return ret; /* High speed output drive strength configuration */ - if (!device_property_read_u8(&ulpi->dev, "ihstx", &val)) + if (!device_property_read_u8(dev, "ihstx", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK); /* High speed output impedance configuration */ - if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val)) + if (!device_property_read_u8(dev, "zhsdrv", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK); /* DP/DM swap control */ - if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val)) + if (!device_property_read_u8(dev, "datapolarity", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK); ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg); From 505dfc6ba84c85651f8f8a7bf721aadc49049a44 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2024 18:02:15 +0200 Subject: [PATCH 320/814] phy: ti: tusb1210: Define device IDs Define device IDs since some of them are being used more than once. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240209160334.2304230-3-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-tusb1210.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index 7232b104a62d..13cd614e12a1 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -17,6 +17,10 @@ #include #include +#define TI_VENDOR_ID 0x0451 +#define TI_DEVICE_TUSB1210 0x1507 +#define TI_DEVICE_TUSB1211 0x1508 + #define TUSB1211_POWER_CONTROL 0x3d #define TUSB1211_POWER_CONTROL_SET 0x3e #define TUSB1211_POWER_CONTROL_CLEAR 0x3f @@ -436,7 +440,7 @@ static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect")) return; - if (ulpi->id.product != 0x1508) { + if (ulpi->id.product != TI_DEVICE_TUSB1211) { dev_err(dev, "error charger detection is only supported on the TUSB1211\n"); return; } @@ -562,11 +566,9 @@ static void tusb1210_remove(struct ulpi *ulpi) tusb1210_remove_charger_detect(tusb); } -#define TI_VENDOR_ID 0x0451 - static const struct ulpi_device_id tusb1210_ulpi_id[] = { - { TI_VENDOR_ID, 0x1507, }, /* TUSB1210 */ - { TI_VENDOR_ID, 0x1508, }, /* TUSB1211 */ + { TI_VENDOR_ID, TI_DEVICE_TUSB1210 }, + { TI_VENDOR_ID, TI_DEVICE_TUSB1211 }, { }, }; MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id); From 0f1991949d9bd5cf6d4e1c490b7e9ba2d2d56d7f Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 7 Aug 2023 02:09:14 +0100 Subject: [PATCH 321/814] sparc: Use shared font data sparc has a 'btext' font used for the console which is almost identical to the shared font_sun8x16, so use it rather than duplicating the data. They were actually identical until about a decade ago when commit bcfbeecea11c ("drivers: console: font_: Change a glyph from "broken bar" to "vertical line"") which changed the | in the shared font to be a solid bar rather than a broken bar. That's the only difference. This was originally spotted by PMD which noticed that PPC does the same thing with the same data, and they also share a bunch of functions to manipulate the data. Tested very lightly with a boot without FS in qemu. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Sam Ravnborg Acked-by: Randy Dunlap Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20230807010914.799713-1-linux@treblig.org --- arch/sparc/Kconfig | 2 + arch/sparc/kernel/btext.c | 365 +------------------------------------- 2 files changed, 11 insertions(+), 356 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index c54ee10b8e2d..b087d4fe00af 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -215,6 +215,8 @@ config EARLYFB bool "Support for early boot text console" default y depends on SPARC64 + select FONT_SUN8x16 + select FONT_SUPPORT help Say Y here to enable a faster early framebuffer boot console. diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c index e2d3f0d2971f..2bf558a0c568 100644 --- a/arch/sparc/kernel/btext.c +++ b/arch/sparc/kernel/btext.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,9 +21,9 @@ static void scrollscreen(void); #endif static void draw_byte(unsigned char c, long locX, long locY); -static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); -static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); -static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); +static void draw_byte_32(const unsigned char *bits, unsigned int *base, int rb); +static void draw_byte_16(const unsigned char *bits, unsigned int *base, int rb); +static void draw_byte_8(const unsigned char *bits, unsigned int *base, int rb); #define __force_data __section(".data") @@ -36,10 +37,6 @@ static int dispDeviceDepth __force_data; static int dispDeviceRect[4] __force_data; static unsigned char *dispDeviceBase __force_data; -#define cmapsz (16*256) - -static unsigned char vga_font[cmapsz]; - static int __init btext_initialize(phandle node) { unsigned int width, height, depth, pitch; @@ -194,7 +191,8 @@ static void btext_drawtext(const char *c, unsigned int len) static void draw_byte(unsigned char c, long locX, long locY) { unsigned char *base = calc_base(locX << 3, locY << 4); - unsigned char *font = &vga_font[((unsigned int)c) * 16]; + unsigned int font_index = c * 16; + const unsigned char *font = font_sun_8x16.data + font_index; int rb = dispDeviceRowBytes; switch(dispDeviceDepth) { @@ -239,7 +237,7 @@ static unsigned int expand_bits_16[4] = { }; -static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) +static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb) { int l, bits; int fg = 0xFFFFFFFFUL; @@ -260,7 +258,7 @@ static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) } } -static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) +static void draw_byte_16(const unsigned char *font, unsigned int *base, int rb) { int l, bits; int fg = 0xFFFFFFFFUL; @@ -278,7 +276,7 @@ static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) } } -static void draw_byte_8(unsigned char *font, unsigned int *base, int rb) +static void draw_byte_8(const unsigned char *font, unsigned int *base, int rb) { int l, bits; int fg = 0x0F0F0F0FUL; @@ -326,348 +324,3 @@ int __init btext_find_display(void) } return ret; } - -static unsigned char vga_font[cmapsz] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, -0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, -0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, -0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, -0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, -0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, -0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, -0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, -0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, -0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, -0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, -0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, -0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, -0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, -0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, -0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, -0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, -0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, -0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, -0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, -0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, -0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, -0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, -0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, -0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, -0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, -0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, -0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, -0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, -0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, -0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, -0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, -0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, -0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, -0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, -0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, -0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, -0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, -0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, -0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, -0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, -0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, -0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, -0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, -0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, -0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, -0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, -0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, -0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, -0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, -0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, -0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, -0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, -0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, -0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, -0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, -0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, -0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, -0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, -0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, -0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, -0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, -0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, -0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, -0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, -0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, -0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, -0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, -0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, -0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, -0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, -0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, -}; From 3cc208ffa84a77650561efc7a851ee0e979bbdb9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 3 Jan 2024 17:16:05 -0600 Subject: [PATCH 322/814] sparc: Fix typos Fix typos, most reported by "codespell arch/sparc". Only touches comments, no code changes. Signed-off-by: Bjorn Helgaas Cc: sparclinux@vger.kernel.org Reviewed-by: Randy Dunlap Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240103231605.1801364-9-helgaas@kernel.org --- arch/sparc/include/asm/hypervisor.h | 6 +++--- arch/sparc/include/asm/ldc.h | 2 +- arch/sparc/include/asm/mmu_context_64.h | 4 ++-- arch/sparc/include/asm/switch_to_64.h | 2 +- arch/sparc/kernel/irq_64.c | 2 +- arch/sparc/kernel/kprobes.c | 2 +- arch/sparc/kernel/ldc.c | 2 +- arch/sparc/kernel/leon_pci_grpci2.c | 2 +- arch/sparc/kernel/of_device_64.c | 2 +- arch/sparc/kernel/pci.c | 2 +- arch/sparc/kernel/pci_impl.h | 4 ++-- arch/sparc/kernel/pci_schizo.c | 4 ++-- arch/sparc/kernel/perf_event.c | 2 +- arch/sparc/kernel/prom_irqtrans.c | 2 +- arch/sparc/kernel/psycho_common.c | 2 +- arch/sparc/kernel/signal_32.c | 2 +- arch/sparc/kernel/signal_64.c | 2 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc/mm/tsb.c | 2 +- arch/sparc/net/bpf_jit_comp_32.c | 6 +++--- 20 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index 08650d503cc2..f220edcf17c7 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -430,7 +430,7 @@ unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, * ERRORS: No errors defined. * * Return the hypervisor ID handle for the current CPU. Use by a - * virtual CPU to discover it's own identity. + * virtual CPU to discover its own identity. */ #define HV_FAST_CPU_MYID 0x16 @@ -1221,7 +1221,7 @@ unsigned long sun4v_con_write(unsigned long buffer, * EBADALIGNED software state description is not correctly * aligned * - * This allows the guest to report it's soft state to the hypervisor. There + * This allows the guest to report its soft state to the hypervisor. There * are two primary components to this state. The first part states whether * the guest software is running or not. The second containts optional * details specific to the software. @@ -1502,7 +1502,7 @@ struct hv_trap_trace_entry { * configuration error of some sort. * * The dump services provide an opaque buffer into which the - * hypervisor can place it's internal state in order to assist in + * hypervisor can place its internal state in order to assist in * debugging such situations. The contents are opaque and extremely * platform and hypervisor implementation specific. The guest, during * a core dump, requests that the hypervisor update any information in diff --git a/arch/sparc/include/asm/ldc.h b/arch/sparc/include/asm/ldc.h index ca973955ca86..4294738d40be 100644 --- a/arch/sparc/include/asm/ldc.h +++ b/arch/sparc/include/asm/ldc.h @@ -13,7 +13,7 @@ void ldom_power_off(void); * or data becomes available on the receive side. * * For non-RAW links, if the LDC_EVENT_RESET event arrives the - * driver should reset all of it's internal state and reinvoke + * driver should reset all of its internal state and reinvoke * ldc_connect() to try and bring the link up again. * * For RAW links, ldc_connect() is not used. Instead the driver diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 799e797c5cdd..08160bf9a0f4 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -93,7 +93,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str /* We have to be extremely careful here or else we will miss * a TSB grow if we switch back and forth between a kernel - * thread and an address space which has it's TSB size increased + * thread and an address space which has its TSB size increased * on another processor. * * It is possible to play some games in order to optimize the @@ -118,7 +118,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str * * At that point cpu0 continues to use a stale TSB, the one from * before the TSB grow performed on cpu1. cpu1 did not cross-call - * cpu0 to update it's TSB because at that point the cpu_vm_mask + * cpu0 to update its TSB because at that point the cpu_vm_mask * only had cpu1 set in it. */ tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context)); diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h index 14f3c49bfdbc..d93963ff7caa 100644 --- a/arch/sparc/include/asm/switch_to_64.h +++ b/arch/sparc/include/asm/switch_to_64.h @@ -15,7 +15,7 @@ do { \ * for l0/l1. It will use one for 'next' and the other to hold * the output value of 'last'. 'next' is not referenced again * past the invocation of switch_to in the scheduler, so we need - * not preserve it's value. Hairy, but it lets us remove 2 loads + * not preserve its value. Hairy, but it lets us remove 2 loads * and 2 stores in this critical code path. -DaveM */ #define switch_to(prev, next, last) \ diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 72da2e10e255..5280e325d4d6 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -980,7 +980,7 @@ void notrace init_irqwork_curcpu(void) * * On SMP this gets invoked from the CPU trampoline before * the cpu has fully taken over the trap table from OBP, - * and it's kernel stack + %g6 thread register state is + * and its kernel stack + %g6 thread register state is * not fully cooked yet. * * Therefore you cannot make any OBP calls, not even prom_printf, diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index 535c7b35cb59..191bbaca9921 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -230,7 +230,7 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p, return regs->tnpc; } -/* If INSN is an instruction which writes it's PC location +/* If INSN is an instruction which writes its PC location * into a destination register, fix that up. */ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn, diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index c0fa3ef6cf01..7f3cdb6f644d 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1854,7 +1854,7 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size) * This seems the best behavior because this allows * a user of the LDC layer to start with a small * RX buffer for ldc_read() calls and use -EMSGSIZE - * as a cue to enlarge it's read buffer. + * as a cue to enlarge its read buffer. */ err = -EMSGSIZE; break; diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index 60b6bdf7761f..282b49d496ea 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -586,7 +586,7 @@ static void grpci2_hw_init(struct grpci2_priv *priv) REGSTORE(regs->io_map, REGLOAD(regs->io_map) & 0x0000ffff); /* set 1:1 mapping between AHB -> PCI memory space, for all Masters - * Each AHB master has it's own mapping registers. Max 16 AHB masters. + * Each AHB master has its own mapping registers. Max 16 AHB masters. */ for (i = 0; i < 16; i++) REGSTORE(regs->ahbmst_map[i], priv->pci_area); diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index d3842821a5a0..c350c58c7f69 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -560,7 +560,7 @@ static unsigned int __init build_one_device_irq(struct platform_device *op, * * If we hit a bus type or situation we cannot handle, we * stop and assume that the original IRQ number was in a - * format which has special meaning to it's immediate parent. + * format which has special meaning to its immediate parent. */ pp = dp->parent; ip = NULL; diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index f66005ce4cb5..50a0927a84a6 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -311,7 +311,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, /* We can't actually use the firmware value, we have * to read what is in the register right now. One * reason is that in the case of IDE interfaces the - * firmware can sample the value before the the IDE + * firmware can sample the value before the IDE * interface is programmed into native mode. */ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h index f31761f51757..83718876f1d4 100644 --- a/arch/sparc/kernel/pci_impl.h +++ b/arch/sparc/kernel/pci_impl.h @@ -19,9 +19,9 @@ * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules * underneath. Each PCI bus module uses an IOMMU (shared by both * PBMs of a controller, or per-PBM), and if a streaming buffer - * is present, each PCI bus module has it's own. (ie. the IOMMU + * is present, each PCI bus module has its own. (ie. the IOMMU * might be shared between PBMs, the STC is never shared) - * Furthermore, each PCI bus module controls it's own autonomous + * Furthermore, each PCI bus module controls its own autonomous * PCI bus. */ diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 5d8dd4949586..93cd9e5a8099 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -145,7 +145,7 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, /* This is __REALLY__ dangerous. When we put the * streaming buffer into diagnostic mode to probe - * it's tags and error status, we _must_ clear all + * its tags and error status, we _must_ clear all * of the line tag valid bits before re-enabling * the streaming buffer. If any dirty data lives * in the STC when we do this, we will end up @@ -275,7 +275,7 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, pbm->name, type_string); /* Put the IOMMU into diagnostic mode and probe - * it's TLB for entries with error status. + * its TLB for entries with error status. * * It is very possible for another DVMA to occur * while we do this probe, and corrupt the system diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index a58ae9c42803..f02a283a8e8f 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -979,7 +979,7 @@ out: static void sparc_pmu_start(struct perf_event *event, int flags); -/* On this PMU each PIC has it's own PCR control register. */ +/* On this PMU each PIC has its own PCR control register. */ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc) { int i; diff --git a/arch/sparc/kernel/prom_irqtrans.c b/arch/sparc/kernel/prom_irqtrans.c index 426bd08cb2ab..5752bfd73ac0 100644 --- a/arch/sparc/kernel/prom_irqtrans.c +++ b/arch/sparc/kernel/prom_irqtrans.c @@ -394,7 +394,7 @@ static unsigned int schizo_irq_build(struct device_node *dp, iclr = schizo_ino_to_iclr(pbm_regs, ino); /* On Schizo, no inofixup occurs. This is because each - * INO has it's own IMAP register. On Psycho and Sabre + * INO has its own IMAP register. On Psycho and Sabre * there is only one IMAP register for each PCI slot even * though four different INOs can be generated by each * PCI slot. diff --git a/arch/sparc/kernel/psycho_common.c b/arch/sparc/kernel/psycho_common.c index 5ee74b4c0cf4..4557ef18f371 100644 --- a/arch/sparc/kernel/psycho_common.c +++ b/arch/sparc/kernel/psycho_common.c @@ -50,7 +50,7 @@ static void psycho_check_stc_error(struct pci_pbm_info *pbm) spin_lock(&stc_buf_lock); /* This is __REALLY__ dangerous. When we put the streaming - * buffer into diagnostic mode to probe it's tags and error + * buffer into diagnostic mode to probe its tags and error * status, we _must_ clear all of the line tag valid bits * before re-enabling the streaming buffer. If any dirty data * lives in the STC when we do this, we will end up diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 89b93c7136e7..478014d2e59b 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -473,7 +473,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) * * %g7 is used as the "thread register". %g6 is not used in * any fixed manner. %g6 is used as a scratch register and - * a compiler temporary, but it's value is never used across + * a compiler temporary, but its value is never used across * a system call. Therefore %g6 is usable for orig_i0 storage. */ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index b4e410976e0d..2d64566a1f88 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -494,7 +494,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) * * %g7 is used as the "thread register". %g6 is not used in * any fixed manner. %g6 is used as a scratch register and - * a compiler temporary, but it's value is never used across + * a compiler temporary, but its value is never used across * a system call. Therefore %g6 is usable for orig_i0 storage. */ if (pt_regs_is_syscall(regs) && diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 8393faa3e596..852085ada368 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1513,7 +1513,7 @@ static void __init init_viking(void) /* * We need this to make sure old viking takes no hits - * on it's cache for dma snoops to workaround the + * on its cache for dma snoops to workaround the * "load from non-cacheable memory" interrupt bug. * This is only necessary because of the new way in * which we use the IOMMU. diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 6acd8a4c1e2a..5fe52a64c7e7 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -385,7 +385,7 @@ static unsigned long tsb_size_to_rss_limit(unsigned long new_size) * will not trigger any longer. * * The TSB can be anywhere from 8K to 1MB in size, in increasing powers - * of two. The TSB must be aligned to it's size, so f.e. a 512K TSB + * of two. The TSB must be aligned to its size, so f.e. a 512K TSB * must be 512K aligned. It also must be physically contiguous, so we * cannot use vmalloc(). * diff --git a/arch/sparc/net/bpf_jit_comp_32.c b/arch/sparc/net/bpf_jit_comp_32.c index a74e5004c6c8..da2df1e84ed4 100644 --- a/arch/sparc/net/bpf_jit_comp_32.c +++ b/arch/sparc/net/bpf_jit_comp_32.c @@ -300,7 +300,7 @@ do { *prog++ = BR_OPC | WDISP22(OFF); \ * * The most common case is to emit a branch at the end of such * a code sequence. So this would be two instructions, the - * branch and it's delay slot. + * branch and its delay slot. * * Therefore by default the branch emitters calculate the branch * offset field as: @@ -309,13 +309,13 @@ do { *prog++ = BR_OPC | WDISP22(OFF); \ * * This "addrs[i] - 8" is the address of the branch itself or * what "." would be in assembler notation. The "8" part is - * how we take into consideration the branch and it's delay + * how we take into consideration the branch and its delay * slot mentioned above. * * Sometimes we need to emit a branch earlier in the code * sequence. And in these situations we adjust "destination" * to accommodate this difference. For example, if we needed - * to emit a branch (and it's delay slot) right before the + * to emit a branch (and its delay slot) right before the * final instruction emitted for a BPF opcode, we'd use * "destination + 4" instead of just plain "destination" above. * From 079431ea9ed3eef871b7b92bb02d411020000679 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 12:19:50 -0300 Subject: [PATCH 323/814] sparc: vio: make vio_bus_type const Now that the driver core can properly handle constant struct bus_type, move the vio_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Acked-by: Sam Ravnborg Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240204-bus_cleanup-sparc-v1-1-4ca7fe8de5f7@marliere.net --- arch/sparc/kernel/vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index b78df3a15a72..846a55f942d4 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -149,7 +149,7 @@ static struct attribute *vio_dev_attrs[] = { }; ATTRIBUTE_GROUPS(vio_dev); -static struct bus_type vio_bus_type = { +static const struct bus_type vio_bus_type = { .name = "vio", .dev_groups = vio_dev_groups, .uevent = vio_hotplug, From 3ed7c61e49d65dacb96db798c0ab6fcd55a1f20f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Feb 2024 21:28:02 -0800 Subject: [PATCH 324/814] sparc64: NMI watchdog: fix return value of __setup handler __setup() handlers should return 1 to obsolete_checksetup() in init/main.c to indicate that the boot option has been handled. A return of 0 causes the boot option/value to be listed as an Unknown kernel parameter and added to init's (limited) argument or environment strings. Also, error return codes don't mean anything to obsolete_checksetup() -- only non-zero (usually 1) or zero. So return 1 from setup_nmi_watchdog(). Fixes: e5553a6d0442 ("sparc64: Implement NMI watchdog on capable cpus.") Signed-off-by: Randy Dunlap Reported-by: Igor Zhbanov Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: Sam Ravnborg Cc: Andrew Morton Cc: stable@vger.kernel.org Cc: Arnd Bergmann Cc: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240211052802.22612-1-rdunlap@infradead.org --- arch/sparc/kernel/nmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 17cdfdbf1f3b..149adc094753 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -279,7 +279,7 @@ static int __init setup_nmi_watchdog(char *str) if (!strncmp(str, "panic", 5)) panic_on_timeout = 1; - return 0; + return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); From 5378f00c935bebb846b1fdb0e79cb76c137c56b5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Feb 2024 21:28:08 -0800 Subject: [PATCH 325/814] sparc: vDSO: fix return value of __setup handler __setup() handlers should return 1 to obsolete_checksetup() in init/main.c to indicate that the boot option has been handled. A return of 0 causes the boot option/value to be listed as an Unknown kernel parameter and added to init's (limited) argument or environment strings. Also, error return codes don't mean anything to obsolete_checksetup() -- only non-zero (usually 1) or zero. So return 1 from vdso_setup(). Fixes: 9a08862a5d2e ("vDSO for sparc") Signed-off-by: Randy Dunlap Reported-by: Igor Zhbanov Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: Dan Carpenter Cc: Nick Alcock Cc: Sam Ravnborg Cc: Andrew Morton Cc: stable@vger.kernel.org Cc: Arnd Bergmann Cc: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240211052808.22635-1-rdunlap@infradead.org --- arch/sparc/vdso/vma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c index 136c78f28f8b..1bbf4335de45 100644 --- a/arch/sparc/vdso/vma.c +++ b/arch/sparc/vdso/vma.c @@ -449,9 +449,8 @@ static __init int vdso_setup(char *s) unsigned long val; err = kstrtoul(s, 10, &val); - if (err) - return err; - vdso_enabled = val; - return 0; + if (!err) + vdso_enabled = val; + return 1; } __setup("vdso=", vdso_setup); From 626db6ee8ee1edac206610db407114aa83b53fd3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 15 Feb 2024 22:57:49 +0900 Subject: [PATCH 326/814] sparc: select FRAME_POINTER instead of redefining it Because FRAME_POINTER is defined in lib/Kconfig.debug, the arch Kconfig should select it. Add 'select FRAME_POINTER' to MCOUNT. ARCH_WANT_FRAME_POINTERS must also be selected to avoid the unmet dependency warning. Signed-off-by: Masahiro Yamada Reviewed-by: Randy Dunlap Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240215135749.1909812-1-masahiroy@kernel.org --- arch/sparc/Kconfig.debug | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug index 37e003665de6..d475a056a2e0 100644 --- a/arch/sparc/Kconfig.debug +++ b/arch/sparc/Kconfig.debug @@ -8,11 +8,8 @@ config MCOUNT bool depends on SPARC64 depends on FUNCTION_TRACER - default y - -config FRAME_POINTER - bool - depends on MCOUNT + select ARCH_WANT_FRAME_POINTERS + select FRAME_POINTER default y config HAVE_HARDLOCKUP_DETECTOR_SPARC64 From 6e031ef2c201cea07bea3b286ed151378c4099f3 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Mon, 5 Feb 2024 16:46:01 +0100 Subject: [PATCH 327/814] crypto: ccp - State in dmesg that TSME is enabled In the case when only TSME is enabled, it is useful to state that fact too, so that users are aware that memory encryption is still enabled even when the corresponding software variant of memory encryption is not enabled. Signed-off-by: Borislav Petkov (AMD) Acked-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 124a2e0c8999..56bf832c2947 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -156,11 +156,14 @@ static unsigned int psp_get_capability(struct psp_device *psp) } psp->capability = val; - /* Detect if TSME and SME are both enabled */ + /* Detect TSME and/or SME status */ if (PSP_CAPABILITY(psp, PSP_SECURITY_REPORTING) && - psp->capability & (PSP_SECURITY_TSME_STATUS << PSP_CAPABILITY_PSP_SECURITY_OFFSET) && - cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) - dev_notice(psp->dev, "psp: Both TSME and SME are active, SME is unnecessary when TSME is active.\n"); + psp->capability & (PSP_SECURITY_TSME_STATUS << PSP_CAPABILITY_PSP_SECURITY_OFFSET)) { + if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) + dev_notice(psp->dev, "psp: Both TSME and SME are active, SME is unnecessary when TSME is active.\n"); + else + dev_notice(psp->dev, "psp: TSME enabled\n"); + } return 0; } From 12b8ae68f50de200c038246c2496822f38b18fe2 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Wed, 7 Feb 2024 17:50:59 +0800 Subject: [PATCH 328/814] crypto: hisilicon/qm - add stop function by hardware Hardware V3 could be able to drain function by sending mailbox to hardware which will trigger tasks in device to be flushed out. When the function is reset, the function can be stopped by this way. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 40 ++++++++++++++++++++++++++++------- include/linux/hisi_acc_qm.h | 2 ++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 4b20b94e6371..3b015482b4e6 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -312,6 +312,7 @@ static const struct hisi_qm_cap_info qm_cap_info_comm[] = { {QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0}, {QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1}, {QM_SUPPORT_STOP_QP, 0x3100, 0, BIT(9), 0x0, 0x0, 0x1}, + {QM_SUPPORT_STOP_FUNC, 0x3100, 0, BIT(10), 0x0, 0x0, 0x1}, {QM_SUPPORT_MB_COMMAND, 0x3100, 0, BIT(11), 0x0, 0x0, 0x1}, {QM_SUPPORT_SVA_PREFETCH, 0x3100, 0, BIT(14), 0x0, 0x0, 0x1}, }; @@ -1674,6 +1675,11 @@ unlock: return ret; } +static int qm_drain_qm(struct hisi_qm *qm) +{ + return hisi_qm_mb(qm, QM_MB_CMD_FLUSH_QM, 0, 0, 0); +} + static int qm_stop_qp(struct hisi_qp *qp) { return hisi_qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0); @@ -2088,7 +2094,8 @@ static int qm_drain_qp(struct hisi_qp *qp) static int qm_stop_qp_nolock(struct hisi_qp *qp) { - struct device *dev = &qp->qm->pdev->dev; + struct hisi_qm *qm = qp->qm; + struct device *dev = &qm->pdev->dev; int ret; /* @@ -2104,11 +2111,14 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp) atomic_set(&qp->qp_status.flags, QP_STOP); - ret = qm_drain_qp(qp); - if (ret) - dev_err(dev, "Failed to drain out data for stopping!\n"); + /* V3 supports direct stop function when FLR prepare */ + if (qm->ver < QM_HW_V3 || qm->status.stop_reason == QM_NORMAL) { + ret = qm_drain_qp(qp); + if (ret) + dev_err(dev, "Failed to drain out data for stopping qp(%u)!\n", qp->qp_id); + } - flush_workqueue(qp->qm->wq); + flush_workqueue(qm->wq); if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used))) qp_stop_fail_cb(qp); @@ -3112,16 +3122,29 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) down_write(&qm->qps_lock); - qm->status.stop_reason = r; if (atomic_read(&qm->status.flags) == QM_STOP) goto err_unlock; /* Stop all the request sending at first. */ atomic_set(&qm->status.flags, QM_STOP); + qm->status.stop_reason = r; - if (qm->status.stop_reason == QM_SOFT_RESET || - qm->status.stop_reason == QM_DOWN) { + if (qm->status.stop_reason != QM_NORMAL) { hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); + /* + * When performing soft reset, the hardware will no longer + * do tasks, and the tasks in the device will be flushed + * out directly since the master ooo is closed. + */ + if (test_bit(QM_SUPPORT_STOP_FUNC, &qm->caps) && + r != QM_SOFT_RESET) { + ret = qm_drain_qm(qm); + if (ret) { + dev_err(dev, "failed to drain qm!\n"); + goto err_unlock; + } + } + ret = qm_stop_started_qp(qm); if (ret < 0) { dev_err(dev, "Failed to stop started qp!\n"); @@ -3141,6 +3164,7 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) } qm_clear_queues(qm); + qm->status.stop_reason = QM_NORMAL; err_unlock: up_write(&qm->qps_lock); diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 5f4c74facf6a..720f10874a66 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -43,6 +43,7 @@ #define QM_MB_CMD_CQC_BT 0x5 #define QM_MB_CMD_SQC_VFT_V2 0x6 #define QM_MB_CMD_STOP_QP 0x8 +#define QM_MB_CMD_FLUSH_QM 0x9 #define QM_MB_CMD_SRC 0xc #define QM_MB_CMD_DST 0xd @@ -151,6 +152,7 @@ enum qm_cap_bits { QM_SUPPORT_DB_ISOLATION = 0x0, QM_SUPPORT_FUNC_QOS, QM_SUPPORT_STOP_QP, + QM_SUPPORT_STOP_FUNC, QM_SUPPORT_MB_COMMAND, QM_SUPPORT_SVA_PREFETCH, QM_SUPPORT_RPM, From ce133a22123055f5f988499cd9ac7953d2bf0677 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Wed, 7 Feb 2024 17:51:00 +0800 Subject: [PATCH 329/814] crypto: hisilicon/qm - obtain stop queue status The debugfs files 'dev_state' and 'dev_timeout' are added. Users can query the current queue stop status through these two files. And set the waiting timeout when the queue is released. dev_state: if dev_timeout is set, dev_state indicates the status of stopping the queue. 0 indicates that the queue is stopped successfully. Other values indicate that the queue stops fail. If dev_timeout is not set, the value of dev_state is 0; dev_timeout: if the queue fails to stop, the queue is released after waiting dev_timeout * 20ms. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- Documentation/ABI/testing/debugfs-hisi-hpre | 15 +++ Documentation/ABI/testing/debugfs-hisi-sec | 15 +++ Documentation/ABI/testing/debugfs-hisi-zip | 15 +++ drivers/crypto/hisilicon/debugfs.c | 5 + drivers/crypto/hisilicon/qm.c | 108 +++++++++++++++----- include/linux/hisi_acc_qm.h | 6 ++ 6 files changed, 138 insertions(+), 26 deletions(-) diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre index 6ed9258605c7..d4e16ef9ac9a 100644 --- a/Documentation/ABI/testing/debugfs-hisi-hpre +++ b/Documentation/ABI/testing/debugfs-hisi-hpre @@ -118,6 +118,21 @@ Description: Dump the state of the device. 0: busy, 1: idle. Only available for PF, and take no other effect on HPRE. +What: /sys/kernel/debug/hisi_hpre//qm/dev_timeout +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Set the wait time when stop queue fails. Available for both PF + and VF, and take no other effect on HPRE. + 0: not wait(default), others value: wait dev_timeout * 20 microsecond. + +What: /sys/kernel/debug/hisi_hpre//qm/dev_state +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the stop queue status of the QM. The default value is 0, + if dev_timeout is set, when stop queue fails, the dev_state + will return non-zero value. Available for both PF and VF, + and take no other effect on HPRE. + What: /sys/kernel/debug/hisi_hpre//hpre_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec index 403f5de96318..6c6c9a6e150a 100644 --- a/Documentation/ABI/testing/debugfs-hisi-sec +++ b/Documentation/ABI/testing/debugfs-hisi-sec @@ -98,6 +98,21 @@ Description: Dump the state of the device. 0: busy, 1: idle. Only available for PF, and take no other effect on SEC. +What: /sys/kernel/debug/hisi_sec2//qm/dev_timeout +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Set the wait time when stop queue fails. Available for both PF + and VF, and take no other effect on SEC. + 0: not wait(default), others value: wait dev_timeout * 20 microsecond. + +What: /sys/kernel/debug/hisi_sec2//qm/dev_state +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the stop queue status of the QM. The default value is 0, + if dev_timeout is set, when stop queue fails, the dev_state + will return non-zero value. Available for both PF and VF, + and take no other effect on SEC. + What: /sys/kernel/debug/hisi_sec2//sec_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip index 2394e6a3cfe2..a22dd6942219 100644 --- a/Documentation/ABI/testing/debugfs-hisi-zip +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -111,6 +111,21 @@ Description: Dump the state of the device. 0: busy, 1: idle. Only available for PF, and take no other effect on ZIP. +What: /sys/kernel/debug/hisi_zip//qm/dev_timeout +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Set the wait time when stop queue fails. Available for both PF + and VF, and take no other effect on ZIP. + 0: not wait(default), others value: wait dev_timeout * 20 microsecond. + +What: /sys/kernel/debug/hisi_zip//qm/dev_state +Date: Feb 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the stop queue status of the QM. The default value is 0, + if dev_timeout is set, when stop queue fails, the dev_state + will return non-zero value. Available for both PF and VF, + and take no other effect on ZIP. + What: /sys/kernel/debug/hisi_zip//zip_dfx/diff_regs Date: Mar 2022 Contact: linux-crypto@vger.kernel.org diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 06e67eda409f..cd67fa348ca7 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -1112,6 +1112,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get, void hisi_qm_debug_init(struct hisi_qm *qm) { struct dfx_diff_registers *qm_regs = qm->debug.qm_diff_regs; + struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx; struct qm_dfx *dfx = &qm->debug.dfx; struct dentry *qm_d; void *data; @@ -1140,6 +1141,10 @@ void hisi_qm_debug_init(struct hisi_qm *qm) debugfs_create_file("status", 0444, qm->debug.qm_d, qm, &qm_status_fops); + + debugfs_create_u32("dev_state", 0444, qm->debug.qm_d, &dev_dfx->dev_state); + debugfs_create_u32("dev_timeout", 0644, qm->debug.qm_d, &dev_dfx->dev_timeout); + for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) { data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset); debugfs_create_file(qm_dfx_files[i].name, diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 3b015482b4e6..41dff28326f1 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -236,6 +236,12 @@ #define QM_DEV_ALG_MAX_LEN 256 + /* abnormal status value for stopping queue */ +#define QM_STOP_QUEUE_FAIL 1 +#define QM_DUMP_SQC_FAIL 3 +#define QM_DUMP_CQC_FAIL 4 +#define QM_FINISH_WAIT 5 + #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ @@ -2037,43 +2043,25 @@ static void qp_stop_fail_cb(struct hisi_qp *qp) } } -/** - * qm_drain_qp() - Drain a qp. - * @qp: The qp we want to drain. - * - * Determine whether the queue is cleared by judging the tail pointers of - * sq and cq. - */ -static int qm_drain_qp(struct hisi_qp *qp) +static int qm_wait_qp_empty(struct hisi_qm *qm, u32 *state, u32 qp_id) { - struct hisi_qm *qm = qp->qm; struct device *dev = &qm->pdev->dev; struct qm_sqc sqc; struct qm_cqc cqc; int ret, i = 0; - /* No need to judge if master OOO is blocked. */ - if (qm_check_dev_error(qm)) - return 0; - - /* Kunpeng930 supports drain qp by device */ - if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) { - ret = qm_stop_qp(qp); - if (ret) - dev_err(dev, "Failed to stop qp(%u)!\n", qp->qp_id); - return ret; - } - while (++i) { - ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp->qp_id, 1); + ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1); if (ret) { dev_err_ratelimited(dev, "Failed to dump sqc!\n"); + *state = QM_DUMP_SQC_FAIL; return ret; } - ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp->qp_id, 1); + ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1); if (ret) { dev_err_ratelimited(dev, "Failed to dump cqc!\n"); + *state = QM_DUMP_CQC_FAIL; return ret; } @@ -2082,8 +2070,9 @@ static int qm_drain_qp(struct hisi_qp *qp) break; if (i == MAX_WAIT_COUNTS) { - dev_err(dev, "Fail to empty queue %u!\n", qp->qp_id); - return -EBUSY; + dev_err(dev, "Fail to empty queue %u!\n", qp_id); + *state = QM_STOP_QUEUE_FAIL; + return -ETIMEDOUT; } usleep_range(WAIT_PERIOD_US_MIN, WAIT_PERIOD_US_MAX); @@ -2092,6 +2081,49 @@ static int qm_drain_qp(struct hisi_qp *qp) return 0; } +/** + * qm_drain_qp() - Drain a qp. + * @qp: The qp we want to drain. + * + * If the device does not support stopping queue by sending mailbox, + * determine whether the queue is cleared by judging the tail pointers of + * sq and cq. + */ +static int qm_drain_qp(struct hisi_qp *qp) +{ + struct hisi_qm *qm = qp->qm; + struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(qm->pdev)); + u32 state = 0; + int ret; + + /* No need to judge if master OOO is blocked. */ + if (qm_check_dev_error(pf_qm)) + return 0; + + /* HW V3 supports drain qp by device */ + if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) { + ret = qm_stop_qp(qp); + if (ret) { + dev_err(&qm->pdev->dev, "Failed to stop qp!\n"); + state = QM_STOP_QUEUE_FAIL; + goto set_dev_state; + } + return ret; + } + + ret = qm_wait_qp_empty(qm, &state, qp->qp_id); + if (ret) + goto set_dev_state; + + return 0; + +set_dev_state: + if (qm->debug.dev_dfx.dev_timeout) + qm->debug.dev_dfx.dev_state = state; + + return ret; +} + static int qm_stop_qp_nolock(struct hisi_qp *qp) { struct hisi_qm *qm = qp->qm; @@ -2319,7 +2351,31 @@ static int hisi_qm_uacce_start_queue(struct uacce_queue *q) static void hisi_qm_uacce_stop_queue(struct uacce_queue *q) { - hisi_qm_stop_qp(q->priv); + struct hisi_qp *qp = q->priv; + struct hisi_qm *qm = qp->qm; + struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx; + u32 i = 0; + + hisi_qm_stop_qp(qp); + + if (!dev_dfx->dev_timeout || !dev_dfx->dev_state) + return; + + /* + * After the queue fails to be stopped, + * wait for a period of time before releasing the queue. + */ + while (++i) { + msleep(WAIT_PERIOD); + + /* Since dev_timeout maybe modified, check i >= dev_timeout */ + if (i >= dev_dfx->dev_timeout) { + dev_err(&qm->pdev->dev, "Stop q %u timeout, state %u\n", + qp->qp_id, dev_dfx->dev_state); + dev_dfx->dev_state = QM_FINISH_WAIT; + break; + } + } } static int hisi_qm_is_q_updated(struct uacce_queue *q) diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 720f10874a66..2d14742ad729 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -163,6 +163,11 @@ struct qm_dev_alg { const char *alg; }; +struct qm_dev_dfx { + u32 dev_state; + u32 dev_timeout; +}; + struct dfx_diff_registers { u32 *regs; u32 reg_offset; @@ -191,6 +196,7 @@ struct qm_debug { struct dentry *debug_root; struct dentry *qm_d; struct debugfs_file files[DEBUG_FILE_NUM]; + struct qm_dev_dfx dev_dfx; unsigned int *qm_last_words; /* ACC engines recoreding last regs */ unsigned int *last_words; From 9066ac364d8659ab7c993b83c60a6182c3ec1ef9 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Wed, 7 Feb 2024 17:51:01 +0800 Subject: [PATCH 330/814] crypto: hisilicon/qm - change function type to void The function qm_stop_qp_nolock() always return zero, so function type is changed to void. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 38 ++++++++++------------------------- include/linux/hisi_acc_qm.h | 2 +- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 41dff28326f1..92f0a1d9b4a6 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -2124,7 +2124,7 @@ set_dev_state: return ret; } -static int qm_stop_qp_nolock(struct hisi_qp *qp) +static void qm_stop_qp_nolock(struct hisi_qp *qp) { struct hisi_qm *qm = qp->qm; struct device *dev = &qm->pdev->dev; @@ -2138,7 +2138,7 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp) */ if (atomic_read(&qp->qp_status.flags) != QP_START) { qp->is_resetting = false; - return 0; + return; } atomic_set(&qp->qp_status.flags, QP_STOP); @@ -2155,25 +2155,19 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp) qp_stop_fail_cb(qp); dev_dbg(dev, "stop queue %u!", qp->qp_id); - - return 0; } /** * hisi_qm_stop_qp() - Stop a qp in qm. * @qp: The qp we want to stop. * - * This function is reverse of hisi_qm_start_qp. Return 0 if successful. + * This function is reverse of hisi_qm_start_qp. */ -int hisi_qm_stop_qp(struct hisi_qp *qp) +void hisi_qm_stop_qp(struct hisi_qp *qp) { - int ret; - down_write(&qp->qm->qps_lock); - ret = qm_stop_qp_nolock(qp); + qm_stop_qp_nolock(qp); up_write(&qp->qm->qps_lock); - - return ret; } EXPORT_SYMBOL_GPL(hisi_qm_stop_qp); @@ -3120,25 +3114,18 @@ static int qm_restart(struct hisi_qm *qm) } /* Stop started qps in reset flow */ -static int qm_stop_started_qp(struct hisi_qm *qm) +static void qm_stop_started_qp(struct hisi_qm *qm) { - struct device *dev = &qm->pdev->dev; struct hisi_qp *qp; - int i, ret; + int i; for (i = 0; i < qm->qp_num; i++) { qp = &qm->qp_array[i]; - if (qp && atomic_read(&qp->qp_status.flags) == QP_START) { + if (atomic_read(&qp->qp_status.flags) == QP_START) { qp->is_resetting = true; - ret = qm_stop_qp_nolock(qp); - if (ret < 0) { - dev_err(dev, "Failed to stop qp%d!\n", i); - return ret; - } + qm_stop_qp_nolock(qp); } } - - return 0; } /** @@ -3201,11 +3188,8 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) } } - ret = qm_stop_started_qp(qm); - if (ret < 0) { - dev_err(dev, "Failed to stop started qp!\n"); - goto err_unlock; - } + qm_stop_started_qp(qm); + hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); } diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 2d14742ad729..9d7754ad5e9b 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -531,7 +531,7 @@ void hisi_qm_uninit(struct hisi_qm *qm); int hisi_qm_start(struct hisi_qm *qm); int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r); int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg); -int hisi_qm_stop_qp(struct hisi_qp *qp); +void hisi_qm_stop_qp(struct hisi_qp *qp); int hisi_qp_send(struct hisi_qp *qp, const void *msg); void hisi_qm_debug_init(struct hisi_qm *qm); void hisi_qm_debug_regs_clear(struct hisi_qm *qm); From 3ee2cee56c5e399424bb6d18de3b63be7126f28a Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 8 Feb 2024 10:33:27 +0100 Subject: [PATCH 331/814] MAINTAINERS: adjust file entries after crypto vmx file movement Commit 109303336a0c ("crypto: vmx - Move to arch/powerpc/crypto") moves the crypto vmx files to arch/powerpc, but misses to adjust the file entries for IBM Power VMX Cryptographic instructions and LINUX FOR POWERPC. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about broken references. Adjust these file entries accordingly. To keep the matched files exact after the movement, spell out each file name in the new directory. Signed-off-by: Lukas Bulwahn Signed-off-by: Herbert Xu --- MAINTAINERS | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a69..5a4051996f1e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10294,12 +10294,17 @@ M: Nayna Jain M: Paulo Flabiano Smorigo L: linux-crypto@vger.kernel.org S: Supported -F: drivers/crypto/vmx/Kconfig -F: drivers/crypto/vmx/Makefile -F: drivers/crypto/vmx/aes* -F: drivers/crypto/vmx/ghash* -F: drivers/crypto/vmx/ppc-xlate.pl -F: drivers/crypto/vmx/vmx.c +F: arch/powerpc/crypto/Kconfig +F: arch/powerpc/crypto/Makefile +F: arch/powerpc/crypto/aes.c +F: arch/powerpc/crypto/aes_cbc.c +F: arch/powerpc/crypto/aes_ctr.c +F: arch/powerpc/crypto/aes_xts.c +F: arch/powerpc/crypto/aesp8-ppc.* +F: arch/powerpc/crypto/ghash.c +F: arch/powerpc/crypto/ghashp8-ppc.pl +F: arch/powerpc/crypto/ppc-xlate.pl +F: arch/powerpc/crypto/vmx.c IBM ServeRAID RAID DRIVER S: Orphan @@ -12382,7 +12387,6 @@ F: drivers/*/*/*pasemi* F: drivers/*/*pasemi* F: drivers/char/tpm/tpm_ibmvtpm* F: drivers/crypto/nx/ -F: drivers/crypto/vmx/ F: drivers/i2c/busses/i2c-opal.c F: drivers/net/ethernet/ibm/ibmveth.* F: drivers/net/ethernet/ibm/ibmvnic.* From c2304e1a0b8051a60d4eb9c99a1c509d90380ae5 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 9 Feb 2024 13:42:07 +0100 Subject: [PATCH 332/814] crypto: qat - change SLAs cleanup flow at shutdown The implementation of the Rate Limiting (RL) feature includes the cleanup of all SLAs during device shutdown. For each SLA, the firmware is notified of the removal through an admin message, the data structures that take into account the budgets are updated and the memory is freed. However, this explicit cleanup is not necessary as (1) the device is reset, and the firmware state is lost and (2) all RL data structures are freed anyway. In addition, if the device is unresponsive, for example after a PCI AER error is detected, the admin interface might not be available. This might slow down the shutdown sequence and cause a timeout in the recovery flows which in turn makes the driver believe that the device is not recoverable. Fix by replacing the explicit SLAs removal with just a free of the SLA data structures. Fixes: d9fb8408376e ("crypto: qat - add rate limiting feature to qat_4xxx") Cc: Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_rl.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.c b/drivers/crypto/intel/qat/qat_common/adf_rl.c index de1b214dba1f..d4f2db3c53d8 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.c @@ -788,6 +788,24 @@ static void clear_sla(struct adf_rl *rl_data, struct rl_sla *sla) sla_type_arr[node_id] = NULL; } +static void free_all_sla(struct adf_accel_dev *accel_dev) +{ + struct adf_rl *rl_data = accel_dev->rate_limiting; + int sla_id; + + mutex_lock(&rl_data->rl_lock); + + for (sla_id = 0; sla_id < RL_NODES_CNT_MAX; sla_id++) { + if (!rl_data->sla[sla_id]) + continue; + + kfree(rl_data->sla[sla_id]); + rl_data->sla[sla_id] = NULL; + } + + mutex_unlock(&rl_data->rl_lock); +} + /** * add_update_sla() - handles the creation and the update of an SLA * @accel_dev: pointer to acceleration device structure @@ -1155,7 +1173,7 @@ void adf_rl_stop(struct adf_accel_dev *accel_dev) return; adf_sysfs_rl_rm(accel_dev); - adf_rl_remove_sla_all(accel_dev, true); + free_all_sla(accel_dev); } void adf_rl_exit(struct adf_accel_dev *accel_dev) From 7d42e097607c4d246d99225bf2b195b6167a210c Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 9 Feb 2024 13:43:42 +0100 Subject: [PATCH 333/814] crypto: qat - resolve race condition during AER recovery During the PCI AER system's error recovery process, the kernel driver may encounter a race condition with freeing the reset_data structure's memory. If the device restart will take more than 10 seconds the function scheduling that restart will exit due to a timeout, and the reset_data structure will be freed. However, this data structure is used for completion notification after the restart is completed, which leads to a UAF bug. This results in a KFENCE bug notice. BUG: KFENCE: use-after-free read in adf_device_reset_worker+0x38/0xa0 [intel_qat] Use-after-free read at 0x00000000bc56fddf (in kfence-#142): adf_device_reset_worker+0x38/0xa0 [intel_qat] process_one_work+0x173/0x340 To resolve this race condition, the memory associated to the container of the work_struct is freed on the worker if the timeout expired, otherwise on the function that schedules the worker. The timeout detection can be done by checking if the caller is still waiting for completion or not by using completion_done() function. Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework") Cc: Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 3597e7605a14..9da2278bd5b7 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -130,7 +130,8 @@ static void adf_device_reset_worker(struct work_struct *work) if (adf_dev_restart(accel_dev)) { /* The device hanged and we can't restart it so stop here */ dev_err(&GET_DEV(accel_dev), "Restart device failed\n"); - if (reset_data->mode == ADF_DEV_RESET_ASYNC) + if (reset_data->mode == ADF_DEV_RESET_ASYNC || + completion_done(&reset_data->compl)) kfree(reset_data); WARN(1, "QAT: device restart failed. Device is unusable\n"); return; @@ -146,11 +147,19 @@ static void adf_device_reset_worker(struct work_struct *work) adf_dev_restarted_notify(accel_dev); clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); - /* The dev is back alive. Notify the caller if in sync mode */ - if (reset_data->mode == ADF_DEV_RESET_SYNC) - complete(&reset_data->compl); - else + /* + * The dev is back alive. Notify the caller if in sync mode + * + * If device restart will take a more time than expected, + * the schedule_reset() function can timeout and exit. This can be + * detected by calling the completion_done() function. In this case + * the reset_data structure needs to be freed here. + */ + if (reset_data->mode == ADF_DEV_RESET_ASYNC || + completion_done(&reset_data->compl)) kfree(reset_data); + else + complete(&reset_data->compl); } static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, @@ -183,8 +192,9 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, dev_err(&GET_DEV(accel_dev), "Reset device timeout expired\n"); ret = -EFAULT; + } else { + kfree(reset_data); } - kfree(reset_data); return ret; } return 0; From 1bec7691b32710ea27741f0f8b00c1dc98d92930 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:48:45 -0300 Subject: [PATCH 334/814] pcmcia: ds: make pcmcia_bus_type const Now that the driver core can properly handle constant struct bus_type, move the pcmcia_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 2 +- drivers/pcmcia/ds.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 580369f3c0b0..999332bc4378 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -132,7 +132,7 @@ void pcmcia_put_socket(struct pcmcia_socket *skt); * Stuff internal to module "pcmcia". */ /* ds.c */ -extern struct bus_type pcmcia_bus_type; +extern const struct bus_type pcmcia_bus_type; struct pcmcia_device; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index b4b8363d1de2..d3cfd353fb93 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1406,7 +1406,7 @@ static const struct dev_pm_ops pcmcia_bus_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume) }; -struct bus_type pcmcia_bus_type = { +const struct bus_type pcmcia_bus_type = { .name = "pcmcia", .uevent = pcmcia_bus_uevent, .match = pcmcia_bus_match, From cb0a395578f1b817f9cf7d2a8525781094fec0c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Jan 2024 08:56:16 +0100 Subject: [PATCH 335/814] dt-bindings: i3c: drop "master" node name suffix Drop the requirement of "-master" suffix in node names because: 1. "Master" word is discouraged and MIPI Alliance renamed it to "Controller". 2. Some devices can operate in Controller (Master) or Target mode, thus the name is not accurate in such cases. 3. Other buses, like I2C controllers, use simple "i2c". Signed-off-by: Krzysztof Kozlowski Acked-by: Jeremy Kerr Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240117075618.81932-1-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml | 2 +- Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml | 2 +- Documentation/devicetree/bindings/i3c/i3c.yaml | 4 ++-- Documentation/devicetree/bindings/i3c/mipi-i3c-hci.yaml | 2 +- Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml | 2 +- Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml index fcc3dbff9c9a..47be5d9a32d4 100644 --- a/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml +++ b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml @@ -57,7 +57,7 @@ examples: - | #include - i3c-master@2000 { + i3c@2000 { compatible = "aspeed,ast2600-i3c"; reg = <0x2000 0x1000>; #address-cells = <3>; diff --git a/Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml index cc40d25358ec..cad6d53d0e2e 100644 --- a/Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml @@ -41,7 +41,7 @@ unevaluatedProperties: false examples: - | - i3c-master@d040000 { + i3c@d040000 { compatible = "cdns,i3c-master"; clocks = <&coreclock>, <&i3csysclock>; clock-names = "pclk", "sysclk"; diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml index c816e295d565..c7900a1da8d9 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.yaml +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml @@ -17,7 +17,7 @@ description: | properties: $nodename: - pattern: "^i3c-master@[0-9a-f]+$" + pattern: "^i3c@[0-9a-f]+$" "#address-cells": const: 3 @@ -153,7 +153,7 @@ additionalProperties: true examples: - | - i3c-master@d040000 { + i3c@d040000 { compatible = "cdns,i3c-master"; clocks = <&coreclock>, <&i3csysclock>; clock-names = "pclk", "sysclk"; diff --git a/Documentation/devicetree/bindings/i3c/mipi-i3c-hci.yaml b/Documentation/devicetree/bindings/i3c/mipi-i3c-hci.yaml index 5dda8cb44cdb..39bb1a1784c9 100644 --- a/Documentation/devicetree/bindings/i3c/mipi-i3c-hci.yaml +++ b/Documentation/devicetree/bindings/i3c/mipi-i3c-hci.yaml @@ -43,7 +43,7 @@ unevaluatedProperties: false examples: - | - i3c-master@a0000000 { + i3c@a0000000 { compatible = "mipi-i3c-hci"; reg = <0xa0000000 0x2000>; interrupts = <89>; diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml index 133855f11b4f..c56ff77677f1 100644 --- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml @@ -48,7 +48,7 @@ unevaluatedProperties: false examples: - | - i3c-master@a0000000 { + i3c@a0000000 { compatible = "silvaco,i3c-master-v1"; clocks = <&zynqmp_clk 71>, <&fclk>, <&sclk>; clock-names = "pclk", "fast_clk", "slow_clk"; diff --git a/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml b/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml index 7a76fd32962a..c0e805e531be 100644 --- a/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml @@ -35,7 +35,7 @@ unevaluatedProperties: false examples: - | - i3c-master@2000 { + i3c@2000 { compatible = "snps,dw-i3c-master-1.00a"; #address-cells = <3>; #size-cells = <0>; From 10201396ef6455a68ac671fa0163205d327ebb70 Mon Sep 17 00:00:00 2001 From: Dylan Hung Date: Fri, 19 Jan 2024 13:45:47 +0800 Subject: [PATCH 336/814] i3c: dw: Disable IBI IRQ depends on hot-join and SIR enabling Disable IBI IRQ signal and status only when hot-join and SIR enabling of all target devices attached to the bus are disabled. Fixes: e389b1d72a62 ("i3c: dw: Add support for in-band interrupts") Signed-off-by: Dylan Hung Link: https://lore.kernel.org/r/20240119054547.983693-1-dylan_hung@aspeedtech.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/dw-i3c-master.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index ef5751e91cc9..276153e10f5a 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -1163,8 +1163,10 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, global = reg == 0xffffffff; reg &= ~BIT(idx); } else { - global = reg == 0; + bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK); + reg |= BIT(idx); + global = (reg == 0xffffffff) && hj_rejected; } writel(reg, master->regs + IBI_SIR_REQ_REJECT); From 97a5253d7c3076ba0dbba8bf30179e079c9c912b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Feb 2024 22:58:17 +0900 Subject: [PATCH 337/814] powerpc: remove unused KCSAN_SANITIZE_early_64.o in Makefile Commit 2fb857bc9f9e ("powerpc/kcsan: Add exclusions from instrumentation") added KCSAN_SANITIZE_early_64.o to arch/powerpc/kernel/Makefile, while it does not compile early_64.o. Signed-off-by: Masahiro Yamada Signed-off-by: Michael Ellerman Link: https://msgid.link/20240216135817.2003106-1-masahiroy@kernel.org --- arch/powerpc/kernel/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 2919433be355..d3282fbea4f2 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -55,7 +55,6 @@ CFLAGS_btext.o += -DDISABLE_BRANCH_PROFILING endif KCSAN_SANITIZE_early_32.o := n -KCSAN_SANITIZE_early_64.o := n KCSAN_SANITIZE_cputable.o := n KCSAN_SANITIZE_btext.o := n KCSAN_SANITIZE_paca.o := n From aeddd5b214c8ce7271d7da7aa64ff20fb9032966 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:02 +0000 Subject: [PATCH 338/814] arm64: sysreg: Add missing ID_AA64ISAR[13]_EL1 fields and variants Despite having the control bits for FEAT_SPECRES and FEAT_PACM, the ID registers fields are either incomplete or missing. Fix it. Reviewed-by: Mark Brown Signed-off-by: Marc Zyngier Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20240214131827.2856277-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/tools/sysreg | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index fa3fe0856880..53daaaef46cb 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -1366,6 +1366,7 @@ EndEnum UnsignedEnum 43:40 SPECRES 0b0000 NI 0b0001 IMP + 0b0010 COSP_RCTX EndEnum UnsignedEnum 39:36 SB 0b0000 NI @@ -1492,7 +1493,12 @@ EndEnum EndSysreg Sysreg ID_AA64ISAR3_EL1 3 0 0 6 3 -Res0 63:12 +Res0 63:16 +UnsignedEnum 15:12 PACM + 0b0000 NI + 0b0001 TRIVIAL_IMP + 0b0010 FULL_IMP +EndEnum UnsignedEnum 11:8 TLBIW 0b0000 NI 0b0001 IMP From c62d7a23b9479b946f00d58046e0bdf7f233a2b9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:03 +0000 Subject: [PATCH 339/814] KVM: arm64: Add feature checking helpers In order to make it easier to check whether a particular feature is exposed to a guest, add a new set of helpers, with kvm_has_feat() being the most useful. Let's start making use of them in the PMU code (courtesy of Oliver). Follow-up changes will introduce additional use patterns. Reviewed-by: Suzuki K Poulose Co-developed--by: Oliver Upton Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-3-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 44 +++++++++++++++++++++++++++++++ arch/arm64/kvm/pmu-emul.c | 11 ++++---- arch/arm64/kvm/sys_regs.c | 6 ++--- include/kvm/arm_pmu.h | 11 -------- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 21c57b812569..527da3d2cedb 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1233,4 +1233,48 @@ static inline void kvm_hyp_reserve(void) { } void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu); bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu); +#define __expand_field_sign_unsigned(id, fld, val) \ + ((u64)SYS_FIELD_VALUE(id, fld, val)) + +#define __expand_field_sign_signed(id, fld, val) \ + ({ \ + u64 __val = SYS_FIELD_VALUE(id, fld, val); \ + sign_extend64(__val, id##_##fld##_WIDTH - 1); \ + }) + +#define expand_field_sign(id, fld, val) \ + (id##_##fld##_SIGNED ? \ + __expand_field_sign_signed(id, fld, val) : \ + __expand_field_sign_unsigned(id, fld, val)) + +#define get_idreg_field_unsigned(kvm, id, fld) \ + ({ \ + u64 __val = IDREG((kvm), SYS_##id); \ + FIELD_GET(id##_##fld##_MASK, __val); \ + }) + +#define get_idreg_field_signed(kvm, id, fld) \ + ({ \ + u64 __val = get_idreg_field_unsigned(kvm, id, fld); \ + sign_extend64(__val, id##_##fld##_WIDTH - 1); \ + }) + +#define get_idreg_field_enum(kvm, id, fld) \ + get_idreg_field_unsigned(kvm, id, fld) + +#define get_idreg_field(kvm, id, fld) \ + (id##_##fld##_SIGNED ? \ + get_idreg_field_signed(kvm, id, fld) : \ + get_idreg_field_unsigned(kvm, id, fld)) + +#define kvm_has_feat(kvm, id, fld, limit) \ + (get_idreg_field((kvm), id, fld) >= expand_field_sign(id, fld, limit)) + +#define kvm_has_feat_enum(kvm, id, fld, val) \ + (get_idreg_field_unsigned((kvm), id, fld) == __expand_field_sign_unsigned(id, fld, val)) + +#define kvm_has_feat_range(kvm, id, fld, min, max) \ + (get_idreg_field((kvm), id, fld) >= expand_field_sign(id, fld, min) && \ + get_idreg_field((kvm), id, fld) <= expand_field_sign(id, fld, max)) + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 3d9467ff73bc..925522470b2b 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -64,12 +64,11 @@ u64 kvm_pmu_evtyper_mask(struct kvm *kvm) { u64 mask = ARMV8_PMU_EXCLUDE_EL1 | ARMV8_PMU_EXCLUDE_EL0 | kvm_pmu_event_mask(kvm); - u64 pfr0 = IDREG(kvm, SYS_ID_AA64PFR0_EL1); - if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL2, pfr0)) + if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL2, IMP)) mask |= ARMV8_PMU_INCLUDE_EL2; - if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL3, pfr0)) + if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL3, IMP)) mask |= ARMV8_PMU_EXCLUDE_NS_EL0 | ARMV8_PMU_EXCLUDE_NS_EL1 | ARMV8_PMU_EXCLUDE_EL3; @@ -83,8 +82,10 @@ u64 kvm_pmu_evtyper_mask(struct kvm *kvm) */ static bool kvm_pmc_is_64bit(struct kvm_pmc *pmc) { + struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc); + return (pmc->idx == ARMV8_PMU_CYCLE_IDX || - kvm_pmu_is_3p5(kvm_pmc_to_vcpu(pmc))); + kvm_has_feat(vcpu->kvm, ID_AA64DFR0_EL1, PMUVer, V3P5)); } static bool kvm_pmc_has_64bit_overflow(struct kvm_pmc *pmc) @@ -556,7 +557,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) return; /* Fixup PMCR_EL0 to reconcile the PMU version and the LP bit */ - if (!kvm_pmu_is_3p5(vcpu)) + if (!kvm_has_feat(vcpu->kvm, ID_AA64DFR0_EL1, PMUVer, V3P5)) val &= ~ARMV8_PMU_PMCR_LP; /* The reset bits don't indicate any state, and shouldn't be saved. */ diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 041b11825578..3c31f8cb9eef 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -505,10 +505,9 @@ static bool trap_loregion(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 val = IDREG(vcpu->kvm, SYS_ID_AA64MMFR1_EL1); u32 sr = reg_to_encoding(r); - if (!(val & (0xfUL << ID_AA64MMFR1_EL1_LO_SHIFT))) { + if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, LO, IMP)) { kvm_inject_undefined(vcpu); return false; } @@ -2748,8 +2747,7 @@ static bool trap_dbgdidr(struct kvm_vcpu *vcpu, return ignore_write(vcpu, p); } else { u64 dfr = IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1); - u64 pfr = IDREG(vcpu->kvm, SYS_ID_AA64PFR0_EL1); - u32 el3 = !!SYS_FIELD_GET(ID_AA64PFR0_EL1, EL3, pfr); + u32 el3 = kvm_has_feat(vcpu->kvm, ID_AA64PFR0_EL1, EL3, IMP); p->regval = ((SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr) << 28) | (SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr) << 24) | diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h index 4b9d8fb393a8..eb4c369a79eb 100644 --- a/include/kvm/arm_pmu.h +++ b/include/kvm/arm_pmu.h @@ -90,16 +90,6 @@ void kvm_vcpu_pmu_resync_el0(void); vcpu->arch.pmu.events = *kvm_get_pmu_events(); \ } while (0) -/* - * Evaluates as true when emulating PMUv3p5, and false otherwise. - */ -#define kvm_pmu_is_3p5(vcpu) ({ \ - u64 val = IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1); \ - u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val); \ - \ - pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P5; \ -}) - u8 kvm_arm_pmu_get_pmuver_limit(void); u64 kvm_pmu_evtyper_mask(struct kvm *kvm); int kvm_arm_set_default_pmu(struct kvm *kvm); @@ -168,7 +158,6 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1) } #define kvm_vcpu_has_pmu(vcpu) ({ false; }) -#define kvm_pmu_is_3p5(vcpu) ({ false; }) static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {} static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {} static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {} From 888f0880702293096619b300150cd7e59fcd9743 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:04 +0000 Subject: [PATCH 340/814] KVM: arm64: nv: Add sanitising to VNCR-backed sysregs VNCR-backed "registers" are actually only memory. Which means that there is zero control over what the guest can write, and that it is the hypervisor's job to actually sanitise the content of the backing store. Yeah, this is fun. In order to preserve some form of sanity, add a repainting mechanism that makes use of a per-VM set of RES0/RES1 masks, one pair per VNCR register. These masks get applied on access to the backing store via __vcpu_sys_reg(), ensuring that the state that is consumed by KVM is correct. So far, nothing populates these masks, but stay tuned. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-4-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 22 ++++++++++++++++- arch/arm64/kvm/arm.c | 1 + arch/arm64/kvm/nested.c | 41 ++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 527da3d2cedb..8cda003d6267 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -238,6 +238,8 @@ static inline u16 kvm_mpidr_index(struct kvm_mpidr_data *data, u64 mpidr) return index; } +struct kvm_sysreg_masks; + struct kvm_arch { struct kvm_s2_mmu mmu; @@ -312,6 +314,9 @@ struct kvm_arch { #define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1) u64 id_regs[KVM_ARM_ID_REG_NUM]; + /* Masks for VNCR-baked sysregs */ + struct kvm_sysreg_masks *sysreg_masks; + /* * For an untrusted host VM, 'pkvm.handle' is used to lookup * the associated pKVM instance in the hypervisor. @@ -474,6 +479,13 @@ enum vcpu_sysreg { NR_SYS_REGS /* Nothing after this line! */ }; +struct kvm_sysreg_masks { + struct { + u64 res0; + u64 res1; + } mask[NR_SYS_REGS - __VNCR_START__]; +}; + struct kvm_cpu_context { struct user_pt_regs regs; /* sp = sp_el0 */ @@ -868,7 +880,15 @@ static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r) #define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r)) -#define __vcpu_sys_reg(v,r) (ctxt_sys_reg(&(v)->arch.ctxt, (r))) +u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *, enum vcpu_sysreg); +#define __vcpu_sys_reg(v,r) \ + (*({ \ + const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt; \ + u64 *__r = __ctxt_sys_reg(ctxt, (r)); \ + if (vcpu_has_nv((v)) && (r) >= __VNCR_START__) \ + *__r = kvm_vcpu_sanitise_vncr_reg((v), (r)); \ + __r; \ + })) u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg); void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index a25265aca432..c063e84fc72c 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -206,6 +206,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) pkvm_destroy_hyp_vm(kvm); kfree(kvm->arch.mpidr_data); + kfree(kvm->arch.sysreg_masks); kvm_destroy_vcpus(kvm); kvm_unshare_hyp(kvm, kvm + 1); diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index d55e809e26cb..c976cd4b8379 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -163,15 +163,54 @@ static u64 limit_nv_id_reg(u32 id, u64 val) return val; } + +u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr) +{ + u64 v = ctxt_sys_reg(&vcpu->arch.ctxt, sr); + struct kvm_sysreg_masks *masks; + + masks = vcpu->kvm->arch.sysreg_masks; + + if (masks) { + sr -= __VNCR_START__; + + v &= ~masks->mask[sr].res0; + v |= masks->mask[sr].res1; + } + + return v; +} + +static void __maybe_unused set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1) +{ + int i = sr - __VNCR_START__; + + kvm->arch.sysreg_masks->mask[i].res0 = res0; + kvm->arch.sysreg_masks->mask[i].res1 = res1; +} + int kvm_init_nv_sysregs(struct kvm *kvm) { + int ret = 0; + mutex_lock(&kvm->arch.config_lock); + if (kvm->arch.sysreg_masks) + goto out; + + kvm->arch.sysreg_masks = kzalloc(sizeof(*(kvm->arch.sysreg_masks)), + GFP_KERNEL); + if (!kvm->arch.sysreg_masks) { + ret = -ENOMEM; + goto out; + } + for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++) kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i), kvm->arch.id_regs[i]); +out: mutex_unlock(&kvm->arch.config_lock); - return 0; + return ret; } From 81ffcace31c24b79d2891d72b3f892dd2b5937d9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:05 +0000 Subject: [PATCH 341/814] KVM: arm64: nv: Add sanitising to EL2 configuration registers We can now start making use of our sanitising masks by setting them to values that depend on the guest's configuration. First up are VTTBR_EL2, VTCR_EL2, VMPIDR_EL2 and HCR_EL2. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-5-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/nested.c | 58 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index c976cd4b8379..29ed529681e2 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -181,7 +181,7 @@ u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr) return v; } -static void __maybe_unused set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1) +static void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1) { int i = sr - __VNCR_START__; @@ -191,6 +191,7 @@ static void __maybe_unused set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u int kvm_init_nv_sysregs(struct kvm *kvm) { + u64 res0, res1; int ret = 0; mutex_lock(&kvm->arch.config_lock); @@ -209,6 +210,61 @@ int kvm_init_nv_sysregs(struct kvm *kvm) kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i), kvm->arch.id_regs[i]); + /* VTTBR_EL2 */ + res0 = res1 = 0; + if (!kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16)) + res0 |= GENMASK(63, 56); + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, CnP, IMP)) + res0 |= VTTBR_CNP_BIT; + set_sysreg_masks(kvm, VTTBR_EL2, res0, res1); + + /* VTCR_EL2 */ + res0 = GENMASK(63, 32) | GENMASK(30, 20); + res1 = BIT(31); + set_sysreg_masks(kvm, VTCR_EL2, res0, res1); + + /* VMPIDR_EL2 */ + res0 = GENMASK(63, 40) | GENMASK(30, 24); + res1 = BIT(31); + set_sysreg_masks(kvm, VMPIDR_EL2, res0, res1); + + /* HCR_EL2 */ + res0 = BIT(48); + res1 = HCR_RW; + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, TWED, IMP)) + res0 |= GENMASK(63, 59); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, MTE, MTE2)) + res0 |= (HCR_TID5 | HCR_DCT | HCR_ATA); + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, EVT, TTLBxS)) + res0 |= (HCR_TTLBIS | HCR_TTLBOS); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, CSV2, CSV2_2) && + !kvm_has_feat(kvm, ID_AA64PFR1_EL1, CSV2_frac, CSV2_1p2)) + res0 |= HCR_ENSCXT; + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, EVT, IMP)) + res0 |= (HCR_TOCU | HCR_TICAB | HCR_TID4); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, V1P1)) + res0 |= HCR_AMVOFFEN; + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, V1P1)) + res0 |= HCR_FIEN; + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, FWB, IMP)) + res0 |= HCR_FWB; + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, NV, NV2)) + res0 |= HCR_NV2; + if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, NV, IMP)) + res0 |= (HCR_AT | HCR_NV1 | HCR_NV); + if (!(__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_ADDRESS) && + __vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_GENERIC))) + res0 |= (HCR_API | HCR_APK); + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TME, IMP)) + res0 |= BIT(39); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP)) + res0 |= (HCR_TEA | HCR_TERR); + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, LO, IMP)) + res0 |= HCR_TLOR; + if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, E2H0, IMP)) + res1 |= HCR_E2H; + set_sysreg_masks(kvm, HCR_EL2, res0, res1); + out: mutex_unlock(&kvm->arch.config_lock); From 11adda4010ba332d9977c98faf1848625348fe40 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:06 +0000 Subject: [PATCH 342/814] KVM: arm64: nv: Add sanitising to VNCR-backed FGT sysregs Fine Grained Traps are controlled by a whole bunch of features. Each one of them must be checked and the corresponding masks computed so that we don't let the guest apply traps it shouldn't be using. This takes care of HFG[IRW]TR_EL2, HDFG[RW]TR_EL2, and HAFGRTR_EL2. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-6-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/nested.c | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 29ed529681e2..eda05eb16c0a 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -265,6 +265,134 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res1 |= HCR_E2H; set_sysreg_masks(kvm, HCR_EL2, res0, res1); + /* HFG[RW]TR_EL2 */ + res0 = res1 = 0; + if (!(__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_ADDRESS) && + __vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_GENERIC))) + res0 |= (HFGxTR_EL2_APDAKey | HFGxTR_EL2_APDBKey | + HFGxTR_EL2_APGAKey | HFGxTR_EL2_APIAKey | + HFGxTR_EL2_APIBKey); + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, LO, IMP)) + res0 |= (HFGxTR_EL2_LORC_EL1 | HFGxTR_EL2_LOREA_EL1 | + HFGxTR_EL2_LORID_EL1 | HFGxTR_EL2_LORN_EL1 | + HFGxTR_EL2_LORSA_EL1); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, CSV2, CSV2_2) && + !kvm_has_feat(kvm, ID_AA64PFR1_EL1, CSV2_frac, CSV2_1p2)) + res0 |= (HFGxTR_EL2_SCXTNUM_EL1 | HFGxTR_EL2_SCXTNUM_EL0); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, GIC, IMP)) + res0 |= HFGxTR_EL2_ICC_IGRPENn_EL1; + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP)) + res0 |= (HFGxTR_EL2_ERRIDR_EL1 | HFGxTR_EL2_ERRSELR_EL1 | + HFGxTR_EL2_ERXFR_EL1 | HFGxTR_EL2_ERXCTLR_EL1 | + HFGxTR_EL2_ERXSTATUS_EL1 | HFGxTR_EL2_ERXMISCn_EL1 | + HFGxTR_EL2_ERXPFGF_EL1 | HFGxTR_EL2_ERXPFGCTL_EL1 | + HFGxTR_EL2_ERXPFGCDN_EL1 | HFGxTR_EL2_ERXADDR_EL1); + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA)) + res0 |= HFGxTR_EL2_nACCDATA_EL1; + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, GCS, IMP)) + res0 |= (HFGxTR_EL2_nGCS_EL0 | HFGxTR_EL2_nGCS_EL1); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, SME, IMP)) + res0 |= (HFGxTR_EL2_nSMPRI_EL1 | HFGxTR_EL2_nTPIDR2_EL0); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, THE, IMP)) + res0 |= HFGxTR_EL2_nRCWMASK_EL1; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1PIE, IMP)) + res0 |= (HFGxTR_EL2_nPIRE0_EL1 | HFGxTR_EL2_nPIR_EL1); + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1POE, IMP)) + res0 |= (HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nPOR_EL1); + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S2POE, IMP)) + res0 |= HFGxTR_EL2_nS2POR_EL1; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, AIE, IMP)) + res0 |= (HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nAMAIR2_EL1); + set_sysreg_masks(kvm, HFGRTR_EL2, res0 | __HFGRTR_EL2_RES0, res1); + set_sysreg_masks(kvm, HFGWTR_EL2, res0 | __HFGWTR_EL2_RES0, res1); + + /* HDFG[RW]TR_EL2 */ + res0 = res1 = 0; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, DoubleLock, IMP)) + res0 |= HDFGRTR_EL2_OSDLR_EL1; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, IMP)) + res0 |= (HDFGRTR_EL2_PMEVCNTRn_EL0 | HDFGRTR_EL2_PMEVTYPERn_EL0 | + HDFGRTR_EL2_PMCCFILTR_EL0 | HDFGRTR_EL2_PMCCNTR_EL0 | + HDFGRTR_EL2_PMCNTEN | HDFGRTR_EL2_PMINTEN | + HDFGRTR_EL2_PMOVS | HDFGRTR_EL2_PMSELR_EL0 | + HDFGRTR_EL2_PMMIR_EL1 | HDFGRTR_EL2_PMUSERENR_EL0 | + HDFGRTR_EL2_PMCEIDn_EL0); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, IMP)) + res0 |= (HDFGRTR_EL2_PMBLIMITR_EL1 | HDFGRTR_EL2_PMBPTR_EL1 | + HDFGRTR_EL2_PMBSR_EL1 | HDFGRTR_EL2_PMSCR_EL1 | + HDFGRTR_EL2_PMSEVFR_EL1 | HDFGRTR_EL2_PMSFCR_EL1 | + HDFGRTR_EL2_PMSICR_EL1 | HDFGRTR_EL2_PMSIDR_EL1 | + HDFGRTR_EL2_PMSIRR_EL1 | HDFGRTR_EL2_PMSLATFR_EL1 | + HDFGRTR_EL2_PMBIDR_EL1); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceVer, IMP)) + res0 |= (HDFGRTR_EL2_TRC | HDFGRTR_EL2_TRCAUTHSTATUS | + HDFGRTR_EL2_TRCAUXCTLR | HDFGRTR_EL2_TRCCLAIM | + HDFGRTR_EL2_TRCCNTVRn | HDFGRTR_EL2_TRCID | + HDFGRTR_EL2_TRCIMSPECn | HDFGRTR_EL2_TRCOSLSR | + HDFGRTR_EL2_TRCPRGCTLR | HDFGRTR_EL2_TRCSEQSTR | + HDFGRTR_EL2_TRCSSCSRn | HDFGRTR_EL2_TRCSTATR | + HDFGRTR_EL2_TRCVICTLR); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP)) + res0 |= (HDFGRTR_EL2_TRBBASER_EL1 | HDFGRTR_EL2_TRBIDR_EL1 | + HDFGRTR_EL2_TRBLIMITR_EL1 | HDFGRTR_EL2_TRBMAR_EL1 | + HDFGRTR_EL2_TRBPTR_EL1 | HDFGRTR_EL2_TRBSR_EL1 | + HDFGRTR_EL2_TRBTRG_EL1); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, BRBE, IMP)) + res0 |= (HDFGRTR_EL2_nBRBIDR | HDFGRTR_EL2_nBRBCTL | + HDFGRTR_EL2_nBRBDATA); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, V1P2)) + res0 |= HDFGRTR_EL2_nPMSNEVFR_EL1; + set_sysreg_masks(kvm, HDFGRTR_EL2, res0 | HDFGRTR_EL2_RES0, res1); + + /* Reuse the bits from the read-side and add the write-specific stuff */ + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, IMP)) + res0 |= (HDFGWTR_EL2_PMCR_EL0 | HDFGWTR_EL2_PMSWINC_EL0); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceVer, IMP)) + res0 |= HDFGWTR_EL2_TRCOSLAR; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP)) + res0 |= HDFGWTR_EL2_TRFCR_EL1; + set_sysreg_masks(kvm, HFGWTR_EL2, res0 | HDFGWTR_EL2_RES0, res1); + + /* HFGITR_EL2 */ + res0 = HFGITR_EL2_RES0; + res1 = HFGITR_EL2_RES1; + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, DPB, DPB2)) + res0 |= HFGITR_EL2_DCCVADP; + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, PAN, PAN2)) + res0 |= (HFGITR_EL2_ATS1E1RP | HFGITR_EL2_ATS1E1WP); + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + res0 |= (HFGITR_EL2_TLBIRVAALE1OS | HFGITR_EL2_TLBIRVALE1OS | + HFGITR_EL2_TLBIRVAAE1OS | HFGITR_EL2_TLBIRVAE1OS | + HFGITR_EL2_TLBIVAALE1OS | HFGITR_EL2_TLBIVALE1OS | + HFGITR_EL2_TLBIVAAE1OS | HFGITR_EL2_TLBIASIDE1OS | + HFGITR_EL2_TLBIVAE1OS | HFGITR_EL2_TLBIVMALLE1OS); + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + res0 |= (HFGITR_EL2_TLBIRVAALE1 | HFGITR_EL2_TLBIRVALE1 | + HFGITR_EL2_TLBIRVAAE1 | HFGITR_EL2_TLBIRVAE1 | + HFGITR_EL2_TLBIRVAALE1IS | HFGITR_EL2_TLBIRVALE1IS | + HFGITR_EL2_TLBIRVAAE1IS | HFGITR_EL2_TLBIRVAE1IS | + HFGITR_EL2_TLBIRVAALE1OS | HFGITR_EL2_TLBIRVALE1OS | + HFGITR_EL2_TLBIRVAAE1OS | HFGITR_EL2_TLBIRVAE1OS); + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, SPECRES, IMP)) + res0 |= (HFGITR_EL2_CFPRCTX | HFGITR_EL2_DVPRCTX | + HFGITR_EL2_CPPRCTX); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, BRBE, IMP)) + res0 |= (HFGITR_EL2_nBRBINJ | HFGITR_EL2_nBRBIALL); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, GCS, IMP)) + res0 |= (HFGITR_EL2_nGCSPUSHM_EL1 | HFGITR_EL2_nGCSSTR_EL1 | + HFGITR_EL2_nGCSEPP); + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, SPECRES, COSP_RCTX)) + res0 |= HFGITR_EL2_COSPRCTX; + if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, ATS1A, IMP)) + res0 |= HFGITR_EL2_ATS1E1A; + set_sysreg_masks(kvm, HFGITR_EL2, res0, res1); + + /* HAFGRTR_EL2 - not a lot to see here */ + res0 = HAFGRTR_EL2_RES0; + res1 = HAFGRTR_EL2_RES1; + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, V1P1)) + res0 |= ~(res0 | res1); + set_sysreg_masks(kvm, HAFGRTR_EL2, res0, res1); out: mutex_unlock(&kvm->arch.config_lock); From d39051d39269dff2ec82c61f3da60edec08d5643 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:07 +0000 Subject: [PATCH 343/814] KVM: arm64: nv: Add sanitising to VNCR-backed HCRX_EL2 Just like its little friends, HCRX_EL2 gets the feature set treatment when backed by VNCR. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-7-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/nested.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index eda05eb16c0a..ced30c90521a 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -265,6 +265,48 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res1 |= HCR_E2H; set_sysreg_masks(kvm, HCR_EL2, res0, res1); + /* HCRX_EL2 */ + res0 = HCRX_EL2_RES0; + res1 = HCRX_EL2_RES1; + if (!kvm_has_feat(kvm, ID_AA64ISAR3_EL1, PACM, TRIVIAL_IMP)) + res0 |= HCRX_EL2_PACMEn; + if (!kvm_has_feat(kvm, ID_AA64PFR2_EL1, FPMR, IMP)) + res0 |= HCRX_EL2_EnFPM; + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, GCS, IMP)) + res0 |= HCRX_EL2_GCSEn; + if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, SYSREG_128, IMP)) + res0 |= HCRX_EL2_EnIDCP128; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, ADERR, DEV_ASYNC)) + res0 |= (HCRX_EL2_EnSDERR | HCRX_EL2_EnSNERR); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, DF2, IMP)) + res0 |= HCRX_EL2_TMEA; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, D128, IMP)) + res0 |= HCRX_EL2_D128En; + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, THE, IMP)) + res0 |= HCRX_EL2_PTTWI; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, SCTLRX, IMP)) + res0 |= HCRX_EL2_SCTLR2En; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) + res0 |= HCRX_EL2_TCR2En; + if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, MOPS, IMP)) + res0 |= (HCRX_EL2_MSCEn | HCRX_EL2_MCE2); + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, CMOW, IMP)) + res0 |= HCRX_EL2_CMOW; + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, NMI, IMP)) + res0 |= (HCRX_EL2_VFNMI | HCRX_EL2_VINMI | HCRX_EL2_TALLINT); + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, SME, IMP) || + !(read_sysreg_s(SYS_SMIDR_EL1) & SMIDR_EL1_SMPS)) + res0 |= HCRX_EL2_SMPME; + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP)) + res0 |= (HCRX_EL2_FGTnXS | HCRX_EL2_FnXS); + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_V)) + res0 |= HCRX_EL2_EnASR; + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64)) + res0 |= HCRX_EL2_EnALS; + if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA)) + res0 |= HCRX_EL2_EnAS0; + set_sysreg_masks(kvm, HCRX_EL2, res0, res1); + /* HFG[RW]TR_EL2 */ res0 = res1 = 0; if (!(__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_ADDRESS) && From 76b457a5cdeae453481910b2b3978d775e9563dc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:08 +0000 Subject: [PATCH 344/814] KVM: arm64: nv: Drop sanitised_sys_reg() helper Now that we have the infrastructure to enforce a sanitised register value depending on the VM configuration, drop the helper that only used the architectural RES0 value. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-8-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 431fd429932d..7a4a886adb9d 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1897,14 +1897,6 @@ static bool check_fgt_bit(u64 val, const union trap_config tc) return ((val >> tc.bit) & 1) == tc.pol; } -#define sanitised_sys_reg(vcpu, reg) \ - ({ \ - u64 __val; \ - __val = __vcpu_sys_reg(vcpu, reg); \ - __val &= ~__ ## reg ## _RES0; \ - (__val); \ - }) - bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) { union trap_config tc; @@ -1940,25 +1932,25 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) case HFGxTR_GROUP: if (is_read) - val = sanitised_sys_reg(vcpu, HFGRTR_EL2); + val = __vcpu_sys_reg(vcpu, HFGRTR_EL2); else - val = sanitised_sys_reg(vcpu, HFGWTR_EL2); + val = __vcpu_sys_reg(vcpu, HFGWTR_EL2); break; case HDFGRTR_GROUP: case HDFGWTR_GROUP: if (is_read) - val = sanitised_sys_reg(vcpu, HDFGRTR_EL2); + val = __vcpu_sys_reg(vcpu, HDFGRTR_EL2); else - val = sanitised_sys_reg(vcpu, HDFGWTR_EL2); + val = __vcpu_sys_reg(vcpu, HDFGWTR_EL2); break; case HAFGRTR_GROUP: - val = sanitised_sys_reg(vcpu, HAFGRTR_EL2); + val = __vcpu_sys_reg(vcpu, HAFGRTR_EL2); break; case HFGITR_GROUP: - val = sanitised_sys_reg(vcpu, HFGITR_EL2); + val = __vcpu_sys_reg(vcpu, HFGITR_EL2); switch (tc.fgf) { u64 tmp; @@ -1966,7 +1958,7 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) break; case HCRX_FGTnXS: - tmp = sanitised_sys_reg(vcpu, HCRX_EL2); + tmp = __vcpu_sys_reg(vcpu, HCRX_EL2); if (tmp & HCRX_EL2_FGTnXS) tc.fgt = __NO_FGT_GROUP__; } From 0beb14de740df93a5af0edc0bd4941dc037e6688 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:09 +0000 Subject: [PATCH 345/814] KVM: arm64: Unify HDFG[WR]TR_GROUP FGT identifiers There is no reason to have separate FGT group identifiers for the debug fine grain trapping. The sole requirement is to provide the *names* so that the SR_FGF() macro can do its magic of picking the correct bit definition. So let's alias HDFGWTR_GROUP and HDFGRTR_GROUP. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-9-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 7a4a886adb9d..8a1cfcf553a2 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1010,7 +1010,7 @@ enum fgt_group_id { __NO_FGT_GROUP__, HFGxTR_GROUP, HDFGRTR_GROUP, - HDFGWTR_GROUP, + HDFGWTR_GROUP = HDFGRTR_GROUP, HFGITR_GROUP, HAFGRTR_GROUP, @@ -1938,7 +1938,6 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) break; case HDFGRTR_GROUP: - case HDFGWTR_GROUP: if (is_read) val = __vcpu_sys_reg(vcpu, HDFGRTR_EL2); else From 9958d58779c92b72ef5b29284d073ecaa2a28764 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:10 +0000 Subject: [PATCH 346/814] KVM: arm64: nv: Correctly handle negative polarity FGTs Negative trap bits are a massive pain. They are, on the surface, indistinguishable from RES0 bits. Do you trap? or do you ignore? Thankfully, we now have the right infrastructure to check for RES0 bits as long as the register is backed by VNCR, which is the case for the FGT registers. Use that information as a discriminant when handling a trap that is potentially caused by a FGT. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-10-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 59 +++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 8a1cfcf553a2..ef46c2e45307 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1892,9 +1892,61 @@ static enum trap_behaviour compute_trap_behaviour(struct kvm_vcpu *vcpu, return __compute_trap_behaviour(vcpu, tc.cgt, b); } -static bool check_fgt_bit(u64 val, const union trap_config tc) +static u64 kvm_get_sysreg_res0(struct kvm *kvm, enum vcpu_sysreg sr) { - return ((val >> tc.bit) & 1) == tc.pol; + struct kvm_sysreg_masks *masks; + + /* Only handle the VNCR-backed regs for now */ + if (sr < __VNCR_START__) + return 0; + + masks = kvm->arch.sysreg_masks; + + return masks->mask[sr - __VNCR_START__].res0; +} + +static bool check_fgt_bit(struct kvm *kvm, bool is_read, + u64 val, const union trap_config tc) +{ + enum vcpu_sysreg sr; + + if (tc.pol) + return (val & BIT(tc.bit)); + + /* + * FGTs with negative polarities are an absolute nightmare, as + * we need to evaluate the bit in the light of the feature + * that defines it. WTF were they thinking? + * + * So let's check if the bit has been earmarked as RES0, as + * this indicates an unimplemented feature. + */ + if (val & BIT(tc.bit)) + return false; + + switch ((enum fgt_group_id)tc.fgt) { + case HFGxTR_GROUP: + sr = is_read ? HFGRTR_EL2 : HFGWTR_EL2; + break; + + case HDFGRTR_GROUP: + sr = is_read ? HDFGRTR_EL2 : HDFGWTR_EL2; + break; + + case HAFGRTR_GROUP: + sr = HAFGRTR_EL2; + break; + + case HFGITR_GROUP: + sr = HFGITR_EL2; + break; + + default: + WARN_ONCE(1, "Unhandled FGT group"); + return false; + } + + return !(kvm_get_sysreg_res0(kvm, sr) & BIT(tc.bit)); } bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) @@ -1969,7 +2021,8 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) return false; } - if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(val, tc)) + if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu->kvm, is_read, + val, tc)) goto inject; b = compute_trap_behaviour(vcpu, tc); From fdd8e3452359d513cdad1bb8467791b69697181a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:11 +0000 Subject: [PATCH 347/814] KVM: arm64: nv: Turn encoding ranges into discrete XArray stores In order to be able to store different values for member of an encoding range, replace xa_store_range() calls with discrete xa_store() calls and an encoding iterator. We end-up using a bit more memory, but we gain some flexibility that we will make use of shortly. Take this opportunity to tidy up the error handling path. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-11-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 49 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index ef46c2e45307..42f5b4483c80 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1757,6 +1757,28 @@ static __init void print_nv_trap_error(const struct encoding_to_trap_config *tc, err); } +static u32 encoding_next(u32 encoding) +{ + u8 op0, op1, crn, crm, op2; + + op0 = sys_reg_Op0(encoding); + op1 = sys_reg_Op1(encoding); + crn = sys_reg_CRn(encoding); + crm = sys_reg_CRm(encoding); + op2 = sys_reg_Op2(encoding); + + if (op2 < Op2_mask) + return sys_reg(op0, op1, crn, crm, op2 + 1); + if (crm < CRm_mask) + return sys_reg(op0, op1, crn, crm + 1, 0); + if (crn < CRn_mask) + return sys_reg(op0, op1, crn + 1, 0, 0); + if (op1 < Op1_mask) + return sys_reg(op0, op1 + 1, 0, 0, 0); + + return sys_reg(op0 + 1, 0, 0, 0, 0); +} + int __init populate_nv_trap_config(void) { int ret = 0; @@ -1775,23 +1797,18 @@ int __init populate_nv_trap_config(void) ret = -EINVAL; } - if (cgt->encoding != cgt->end) { - prev = xa_store_range(&sr_forward_xa, - cgt->encoding, cgt->end, - xa_mk_value(cgt->tc.val), - GFP_KERNEL); - } else { - prev = xa_store(&sr_forward_xa, cgt->encoding, + for (u32 enc = cgt->encoding; enc <= cgt->end; enc = encoding_next(enc)) { + prev = xa_store(&sr_forward_xa, enc, xa_mk_value(cgt->tc.val), GFP_KERNEL); if (prev && !xa_is_err(prev)) { ret = -EINVAL; print_nv_trap_error(cgt, "Duplicate CGT", ret); } - } - if (xa_is_err(prev)) { - ret = xa_err(prev); - print_nv_trap_error(cgt, "Failed CGT insertion", ret); + if (xa_is_err(prev)) { + ret = xa_err(prev); + print_nv_trap_error(cgt, "Failed CGT insertion", ret); + } } } @@ -1804,6 +1821,7 @@ int __init populate_nv_trap_config(void) for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) { const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i]; union trap_config tc; + void *prev; if (fgt->tc.fgt >= __NR_FGT_GROUP_IDS__) { ret = -EINVAL; @@ -1818,8 +1836,13 @@ int __init populate_nv_trap_config(void) } tc.val |= fgt->tc.val; - xa_store(&sr_forward_xa, fgt->encoding, - xa_mk_value(tc.val), GFP_KERNEL); + prev = xa_store(&sr_forward_xa, fgt->encoding, + xa_mk_value(tc.val), GFP_KERNEL); + + if (xa_is_err(prev)) { + ret = xa_err(prev); + print_nv_trap_error(fgt, "Failed FGT insertion", ret); + } } kvm_info("nv: %ld fine grained trap handlers\n", From 52571d058b0775d57c9d1bc62d8a19b2da51ef39 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:12 +0000 Subject: [PATCH 348/814] KVM: arm64: Drop the requirement for XARRAY_MULTI Now that we don't use xa_store_range() anymore, drop the added complexity of XARRAY_MULTI for KVM. It is likely still pulled in by other bits of the kernel though. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-12-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 6c3c8ca73e7f..5c2a672c06a8 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -39,7 +39,6 @@ menuconfig KVM select HAVE_KVM_VCPU_RUN_PID_CHANGE select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS - select XARRAY_MULTI help Support hosting virtualized guest machines. From 89bc63fabc8af0897b7ed4fb127006c205dc622c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:13 +0000 Subject: [PATCH 349/814] KVM: arm64: nv: Move system instructions to their own sys_reg_desc array As NV results in a bunch of system instructions being trapped, it makes sense to pull the system instructions into their own little array, where they will eventually be joined by AT, TLBI and a bunch of other CMOs. Based on an initial patch by Jintack Lim. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-13-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 61 +++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 3c31f8cb9eef..70043bd78cd4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2196,16 +2196,6 @@ static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) * guest... */ static const struct sys_reg_desc sys_reg_descs[] = { - { SYS_DESC(SYS_DC_ISW), access_dcsw }, - { SYS_DESC(SYS_DC_IGSW), access_dcgsw }, - { SYS_DESC(SYS_DC_IGDSW), access_dcgsw }, - { SYS_DESC(SYS_DC_CSW), access_dcsw }, - { SYS_DESC(SYS_DC_CGSW), access_dcgsw }, - { SYS_DESC(SYS_DC_CGDSW), access_dcgsw }, - { SYS_DESC(SYS_DC_CISW), access_dcsw }, - { SYS_DESC(SYS_DC_CIGSW), access_dcgsw }, - { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw }, - DBG_BCR_BVR_WCR_WVR_EL1(0), DBG_BCR_BVR_WCR_WVR_EL1(1), { SYS_DESC(SYS_MDCCINT_EL1), trap_debug_regs, reset_val, MDCCINT_EL1, 0 }, @@ -2737,6 +2727,18 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG(SP_EL2, NULL, reset_unknown, 0), }; +static struct sys_reg_desc sys_insn_descs[] = { + { SYS_DESC(SYS_DC_ISW), access_dcsw }, + { SYS_DESC(SYS_DC_IGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_IGDSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CSW), access_dcsw }, + { SYS_DESC(SYS_DC_CGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CGDSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CISW), access_dcsw }, + { SYS_DESC(SYS_DC_CIGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw }, +}; + static const struct sys_reg_desc *first_idreg; static bool trap_dbgdidr(struct kvm_vcpu *vcpu, @@ -3429,6 +3431,24 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu, return false; } +static int emulate_sys_instr(struct kvm_vcpu *vcpu, struct sys_reg_params *p) +{ + const struct sys_reg_desc *r; + + /* Search from the system instruction table. */ + r = find_reg(p, sys_insn_descs, ARRAY_SIZE(sys_insn_descs)); + + if (likely(r)) { + perform_access(vcpu, p, r); + } else { + kvm_err("Unsupported guest sys instruction at: %lx\n", + *vcpu_pc(vcpu)); + print_sys_reg_instr(p); + kvm_inject_undefined(vcpu); + } + return 1; +} + static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) { const struct sys_reg_desc *idreg = first_idreg; @@ -3476,7 +3496,8 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu) } /** - * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access + * kvm_handle_sys_reg -- handles a system instruction or mrs/msr instruction + * trap on a guest execution * @vcpu: The VCPU pointer */ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu) @@ -3493,12 +3514,19 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu) params = esr_sys64_to_params(esr); params.regval = vcpu_get_reg(vcpu, Rt); - if (!emulate_sys_reg(vcpu, ¶ms)) - return 1; + /* System registers have Op0=={2,3}, as per DDI487 J.a C5.1.2 */ + if (params.Op0 == 2 || params.Op0 == 3) { + if (!emulate_sys_reg(vcpu, ¶ms)) + return 1; - if (!params.is_write) - vcpu_set_reg(vcpu, Rt, params.regval); - return 1; + if (!params.is_write) + vcpu_set_reg(vcpu, Rt, params.regval); + + return 1; + } + + /* Hints, PSTATE (Op0 == 0) and System instructions (Op0 == 1) */ + return emulate_sys_instr(vcpu, ¶ms); } /****************************************************************************** @@ -3952,6 +3980,7 @@ int __init kvm_sys_reg_table_init(void) valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true); valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true); valid &= check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs), false); + valid &= check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs), false); if (!valid) return -EINVAL; From 7fd498f473f121db10997d720628423e6538f3b7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:14 +0000 Subject: [PATCH 350/814] KVM: arm64: Always populate the trap configuration xarray As we are going to rely more and more on the global xarray that contains the trap configuration, always populate it, even in the non-NV case. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-14-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 70043bd78cd4..57f3d0c53fc3 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3995,8 +3995,5 @@ int __init kvm_sys_reg_table_init(void) if (!first_idreg) return -EINVAL; - if (kvm_get_mode() == KVM_MODE_NV) - return populate_nv_trap_config(); - - return 0; + return populate_nv_trap_config(); } From 19f3e7ea29f8f485f06b47f7c38f9e9e81013ada Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:15 +0000 Subject: [PATCH 351/814] KVM: arm64: Register AArch64 system register entries with the sysreg xarray In order to reduce the number of lookups that we have to perform when handling a sysreg, register each AArch64 sysreg descriptor with the global xarray. The index of the descriptor is stored as a 10 bit field in the data word. Subsequent patches will retrieve and use the stored index. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-15-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/emulate-nested.c | 39 +++++++++++++++++++++++++++++-- arch/arm64/kvm/sys_regs.c | 11 ++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8cda003d6267..914fd54179bb 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1078,6 +1078,9 @@ int kvm_handle_cp10_id(struct kvm_vcpu *vcpu); void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); int __init kvm_sys_reg_table_init(void); +struct sys_reg_desc; +int __init populate_sysreg_config(const struct sys_reg_desc *sr, + unsigned int idx); int __init populate_nv_trap_config(void); bool lock_all_vcpus(struct kvm *kvm); diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 42f5b4483c80..ddf760b4dda5 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -427,12 +427,14 @@ static const complex_condition_check ccc[] = { * [19:14] bit number in the FGT register (6 bits) * [20] trap polarity (1 bit) * [25:21] FG filter (5 bits) - * [62:26] Unused (37 bits) + * [35:26] Main SysReg table index (10 bits) + * [62:36] Unused (27 bits) * [63] RES0 - Must be zero, as lost on insertion in the xarray */ #define TC_CGT_BITS 10 #define TC_FGT_BITS 4 #define TC_FGF_BITS 5 +#define TC_SRI_BITS 10 union trap_config { u64 val; @@ -442,7 +444,8 @@ union trap_config { unsigned long bit:6; /* Bit number */ unsigned long pol:1; /* Polarity */ unsigned long fgf:TC_FGF_BITS; /* Fine Grained Filter */ - unsigned long unused:37; /* Unused, should be zero */ + unsigned long sri:TC_SRI_BITS; /* SysReg Index */ + unsigned long unused:27; /* Unused, should be zero */ unsigned long mbz:1; /* Must Be Zero */ }; }; @@ -1868,6 +1871,38 @@ check_mcb: return ret; } +int __init populate_sysreg_config(const struct sys_reg_desc *sr, + unsigned int idx) +{ + union trap_config tc; + u32 encoding; + void *ret; + + /* + * 0 is a valid value for the index, but not for the storage. + * We'll store (idx+1), so check against an offset'd limit. + */ + if (idx >= (BIT(TC_SRI_BITS) - 1)) { + kvm_err("sysreg %s (%d) out of range\n", sr->name, idx); + return -EINVAL; + } + + encoding = sys_reg(sr->Op0, sr->Op1, sr->CRn, sr->CRm, sr->Op2); + tc = get_trap_config(encoding); + + if (tc.sri) { + kvm_err("sysreg %s (%d) duplicate entry (%d)\n", + sr->name, idx - 1, tc.sri); + return -EINVAL; + } + + tc.sri = idx + 1; + ret = xa_store(&sr_forward_xa, encoding, + xa_mk_value(tc.val), GFP_KERNEL); + + return xa_err(ret); +} + static enum trap_behaviour get_behaviour(struct kvm_vcpu *vcpu, const struct trap_bits *tb) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 57f3d0c53fc3..a410e99f827e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3972,6 +3972,7 @@ int __init kvm_sys_reg_table_init(void) struct sys_reg_params params; bool valid = true; unsigned int i; + int ret = 0; /* Make sure tables are unique and in order. */ valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false); @@ -3995,5 +3996,13 @@ int __init kvm_sys_reg_table_init(void) if (!first_idreg) return -EINVAL; - return populate_nv_trap_config(); + ret = populate_nv_trap_config(); + + for (i = 0; !ret && i < ARRAY_SIZE(sys_reg_descs); i++) + ret = populate_sysreg_config(sys_reg_descs + i, i); + + for (i = 0; !ret && i < ARRAY_SIZE(sys_insn_descs); i++) + ret = populate_sysreg_config(sys_insn_descs + i, i); + + return ret; } From cc5f84fbb008ff0904e0a8c0fb207cee2eb99bc9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:16 +0000 Subject: [PATCH 352/814] KVM: arm64: Use the xarray as the primary sysreg/sysinsn walker Since we always start sysreg/sysinsn handling by searching the xarray, use it as the source of the index in the correct sys_reg_desc array. This allows some cleanup, such as moving the handling of unknown sysregs in a single location. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-16-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_nested.h | 2 +- arch/arm64/kvm/emulate-nested.c | 40 +++++++++++++----- arch/arm64/kvm/sys_regs.c | 63 +++++++++-------------------- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 4882905357f4..68465f87d308 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -60,7 +60,7 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0) return ttbr0 & ~GENMASK_ULL(63, 48); } -extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu); +extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu, int *sr_idx); int kvm_init_nv_sysregs(struct kvm *kvm); diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index ddf760b4dda5..5aeaa688755f 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -2007,7 +2007,7 @@ static bool check_fgt_bit(struct kvm *kvm, bool is_read, return !(kvm_get_sysreg_res0(kvm, sr) & BIT(tc.bit)); } -bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) +bool __check_nv_sr_forward(struct kvm_vcpu *vcpu, int *sr_index) { union trap_config tc; enum trap_behaviour b; @@ -2015,9 +2015,6 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) u32 sysreg; u64 esr, val; - if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) - return false; - esr = kvm_vcpu_get_esr(vcpu); sysreg = esr_sys64_to_sysreg(esr); is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ; @@ -2028,13 +2025,16 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) * A value of 0 for the whole entry means that we know nothing * for this sysreg, and that it cannot be re-injected into the * nested hypervisor. In this situation, let's cut it short. - * - * Note that ultimately, we could also make use of the xarray - * to store the index of the sysreg in the local descriptor - * array, avoiding another search... Hint, hint... */ if (!tc.val) - return false; + goto local; + + /* + * If we're not nesting, immediately return to the caller, with the + * sysreg index, should we have it. + */ + if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) + goto local; switch ((enum fgt_group_id)tc.fgt) { case __NO_FGT_GROUP__: @@ -2076,7 +2076,7 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) case __NR_FGT_GROUP_IDS__: /* Something is really wrong, bail out */ WARN_ONCE(1, "__NR_FGT_GROUP_IDS__"); - return false; + goto local; } if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu->kvm, is_read, @@ -2089,6 +2089,26 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) ((b & BEHAVE_FORWARD_WRITE) && !is_read)) goto inject; +local: + if (!tc.sri) { + struct sys_reg_params params; + + params = esr_sys64_to_params(esr); + + /* + * Check for the IMPDEF range, as per DDI0487 J.a, + * D18.3.2 Reserved encodings for IMPLEMENTATION + * DEFINED registers. + */ + if (!(params.Op0 == 3 && (params.CRn & 0b1011) == 0b1011)) + print_sys_reg_msg(¶ms, + "Unsupported guest access at: %lx\n", + *vcpu_pc(vcpu)); + kvm_inject_undefined(vcpu); + return true; + } + + *sr_index = tc.sri - 1; return false; inject: diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a410e99f827e..bc076ef8440b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3395,12 +3395,6 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu) return kvm_handle_cp_32(vcpu, ¶ms, cp14_regs, ARRAY_SIZE(cp14_regs)); } -static bool is_imp_def_sys_reg(struct sys_reg_params *params) -{ - // See ARM DDI 0487E.a, section D12.3.2 - return params->Op0 == 3 && (params->CRn & 0b1011) == 0b1011; -} - /** * emulate_sys_reg - Emulate a guest access to an AArch64 system register * @vcpu: The VCPU pointer @@ -3409,46 +3403,24 @@ static bool is_imp_def_sys_reg(struct sys_reg_params *params) * Return: true if the system register access was successful, false otherwise. */ static bool emulate_sys_reg(struct kvm_vcpu *vcpu, - struct sys_reg_params *params) + struct sys_reg_params *params) { const struct sys_reg_desc *r; r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); - if (likely(r)) { perform_access(vcpu, params, r); return true; } - if (is_imp_def_sys_reg(params)) { - kvm_inject_undefined(vcpu); - } else { - print_sys_reg_msg(params, - "Unsupported guest sys_reg access at: %lx [%08lx]\n", - *vcpu_pc(vcpu), *vcpu_cpsr(vcpu)); - kvm_inject_undefined(vcpu); - } + print_sys_reg_msg(params, + "Unsupported guest sys_reg access at: %lx [%08lx]\n", + *vcpu_pc(vcpu), *vcpu_cpsr(vcpu)); + kvm_inject_undefined(vcpu); + return false; } -static int emulate_sys_instr(struct kvm_vcpu *vcpu, struct sys_reg_params *p) -{ - const struct sys_reg_desc *r; - - /* Search from the system instruction table. */ - r = find_reg(p, sys_insn_descs, ARRAY_SIZE(sys_insn_descs)); - - if (likely(r)) { - perform_access(vcpu, p, r); - } else { - kvm_err("Unsupported guest sys instruction at: %lx\n", - *vcpu_pc(vcpu)); - print_sys_reg_instr(p); - kvm_inject_undefined(vcpu); - } - return 1; -} - static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) { const struct sys_reg_desc *idreg = first_idreg; @@ -3502,31 +3474,34 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu) */ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu) { + const struct sys_reg_desc *desc = NULL; struct sys_reg_params params; unsigned long esr = kvm_vcpu_get_esr(vcpu); int Rt = kvm_vcpu_sys_get_rt(vcpu); + int sr_idx; trace_kvm_handle_sys_reg(esr); - if (__check_nv_sr_forward(vcpu)) + if (__check_nv_sr_forward(vcpu, &sr_idx)) return 1; params = esr_sys64_to_params(esr); params.regval = vcpu_get_reg(vcpu, Rt); /* System registers have Op0=={2,3}, as per DDI487 J.a C5.1.2 */ - if (params.Op0 == 2 || params.Op0 == 3) { - if (!emulate_sys_reg(vcpu, ¶ms)) - return 1; + if (params.Op0 == 2 || params.Op0 == 3) + desc = &sys_reg_descs[sr_idx]; + else + desc = &sys_insn_descs[sr_idx]; - if (!params.is_write) - vcpu_set_reg(vcpu, Rt, params.regval); + perform_access(vcpu, ¶ms, desc); - return 1; - } + /* Read from system register? */ + if (!params.is_write && + (params.Op0 == 2 || params.Op0 == 3)) + vcpu_set_reg(vcpu, Rt, params.regval); - /* Hints, PSTATE (Op0 == 0) and System instructions (Op0 == 1) */ - return emulate_sys_instr(vcpu, ¶ms); + return 1; } /****************************************************************************** From 085eabaa74a12345b7dd083b160519fe3a52f2ce Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:17 +0000 Subject: [PATCH 353/814] KVM: arm64: Rename __check_nv_sr_forward() to triage_sysreg_trap() __check_nv_sr_forward() is not specific to NV anymore, and does a lot more. Rename it to triage_sysreg_trap(), making it plain that its role is to handle where an exception is to be handled. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-17-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_nested.h | 1 - arch/arm64/kvm/emulate-nested.c | 2 +- arch/arm64/kvm/sys_regs.c | 2 +- arch/arm64/kvm/sys_regs.h | 2 ++ 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 68465f87d308..c77d795556e1 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -60,7 +60,6 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0) return ttbr0 & ~GENMASK_ULL(63, 48); } -extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu, int *sr_idx); int kvm_init_nv_sysregs(struct kvm *kvm); diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 5aeaa688755f..4f2a32a8f247 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -2007,7 +2007,7 @@ static bool check_fgt_bit(struct kvm *kvm, bool is_read, return !(kvm_get_sysreg_res0(kvm, sr) & BIT(tc.bit)); } -bool __check_nv_sr_forward(struct kvm_vcpu *vcpu, int *sr_index) +bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index) { union trap_config tc; enum trap_behaviour b; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index bc076ef8440b..938df5dc3684 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3482,7 +3482,7 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu) trace_kvm_handle_sys_reg(esr); - if (__check_nv_sr_forward(vcpu, &sr_idx)) + if (triage_sysreg_trap(vcpu, &sr_idx)) return 1; params = esr_sys64_to_params(esr); diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index c65c129b3500..997eea21ba2a 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -233,6 +233,8 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num); +bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index); + #define AA32(_x) .aarch32_map = AA32_##_x #define Op0(_x) .Op0 = _x #define Op1(_x) .Op1 = _x From 2fd8f31c32f061822c18d13d17c1ea6a531cc443 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:18 +0000 Subject: [PATCH 354/814] KVM: arm64: Add Fine-Grained UNDEF tracking information In order to efficiently handle system register access being disabled, and this resulting in an UNDEF exception being injected, we introduce the (slightly dubious) concept of Fine-Grained UNDEF, modeled after the architectural Fine-Grained Traps. For each FGT group, we keep a 64 bit word that has the exact same bit assignment as the corresponding FGT register, where a 1 indicates that trapping this register should result in an UNDEF exception being reinjected. So far, nothing populates this information, nor sets the corresponding trap bits. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-18-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 21 +++++++++++++++++++++ arch/arm64/kvm/emulate-nested.c | 12 ------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 914fd54179bb..c69b258fc989 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -240,9 +240,30 @@ static inline u16 kvm_mpidr_index(struct kvm_mpidr_data *data, u64 mpidr) struct kvm_sysreg_masks; +enum fgt_group_id { + __NO_FGT_GROUP__, + HFGxTR_GROUP, + HDFGRTR_GROUP, + HDFGWTR_GROUP = HDFGRTR_GROUP, + HFGITR_GROUP, + HAFGRTR_GROUP, + + /* Must be last */ + __NR_FGT_GROUP_IDS__ +}; + struct kvm_arch { struct kvm_s2_mmu mmu; + /* + * Fine-Grained UNDEF, mimicking the FGT layout defined by the + * architecture. We track them globally, as we present the + * same feature-set to all vcpus. + * + * Index 0 is currently spare. + */ + u64 fgu[__NR_FGT_GROUP_IDS__]; + /* Interrupt controller */ struct vgic_dist vgic; diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 4f2a32a8f247..b67078b8271b 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1009,18 +1009,6 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { static DEFINE_XARRAY(sr_forward_xa); -enum fgt_group_id { - __NO_FGT_GROUP__, - HFGxTR_GROUP, - HDFGRTR_GROUP, - HDFGWTR_GROUP = HDFGRTR_GROUP, - HFGITR_GROUP, - HAFGRTR_GROUP, - - /* Must be last */ - __NR_FGT_GROUP_IDS__ -}; - enum fg_filter_id { __NO_FGF__, HCRX_FGTnXS, From f5a5a406b4b8bb6c1fc7a1e92a872bd86061a53f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:19 +0000 Subject: [PATCH 355/814] KVM: arm64: Propagate and handle Fine-Grained UNDEF bits In order to correctly honor our FGU bits, they must be converted into a set of FGT bits. They get merged as part of the existing FGT setting. Similarly, the UNDEF injection phase takes place when handling the trap. This results in a bit of rework in the FGT macros in order to help with the code generation, as burying per-CPU accesses in macros results in a lot of expansion, not to mention the vcpu->kvm access on nvhe (kern_hyp_va() is not optimisation-friendly). Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-19-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 11 ++++ arch/arm64/kvm/hyp/include/hyp/switch.h | 81 +++++++++++++++++++------ 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index b67078b8271b..4697ba41b3a9 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -2017,6 +2017,17 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index) if (!tc.val) goto local; + /* + * If a sysreg can be trapped using a FGT, first check whether we + * trap for the purpose of forbidding the feature. In that case, + * inject an UNDEF. + */ + if (tc.fgt != __NO_FGT_GROUP__ && + (vcpu->kvm->arch.fgu[tc.fgt] & BIT(tc.bit))) { + kvm_inject_undefined(vcpu); + return true; + } + /* * If we're not nesting, immediately return to the caller, with the * sysreg index, should we have it. diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index a038320cdb08..a09149fd91ed 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -79,14 +79,48 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu) clr |= ~hfg & __ ## reg ## _nMASK; \ } while(0) -#define update_fgt_traps_cs(vcpu, reg, clr, set) \ +#define reg_to_fgt_group_id(reg) \ + ({ \ + enum fgt_group_id id; \ + switch(reg) { \ + case HFGRTR_EL2: \ + case HFGWTR_EL2: \ + id = HFGxTR_GROUP; \ + break; \ + case HFGITR_EL2: \ + id = HFGITR_GROUP; \ + break; \ + case HDFGRTR_EL2: \ + case HDFGWTR_EL2: \ + id = HDFGRTR_GROUP; \ + break; \ + case HAFGRTR_EL2: \ + id = HAFGRTR_GROUP; \ + break; \ + default: \ + BUILD_BUG_ON(1); \ + } \ + \ + id; \ + }) + +#define compute_undef_clr_set(vcpu, kvm, reg, clr, set) \ + do { \ + u64 hfg = kvm->arch.fgu[reg_to_fgt_group_id(reg)]; \ + set |= hfg & __ ## reg ## _MASK; \ + clr |= hfg & __ ## reg ## _nMASK; \ + } while(0) + +#define update_fgt_traps_cs(hctxt, vcpu, kvm, reg, clr, set) \ do { \ - struct kvm_cpu_context *hctxt = \ - &this_cpu_ptr(&kvm_host_data)->host_ctxt; \ u64 c = 0, s = 0; \ \ ctxt_sys_reg(hctxt, reg) = read_sysreg_s(SYS_ ## reg); \ - compute_clr_set(vcpu, reg, c, s); \ + if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) \ + compute_clr_set(vcpu, reg, c, s); \ + \ + compute_undef_clr_set(vcpu, kvm, reg, c, s); \ + \ s |= set; \ c |= clr; \ if (c || s) { \ @@ -97,8 +131,8 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu) } \ } while(0) -#define update_fgt_traps(vcpu, reg) \ - update_fgt_traps_cs(vcpu, reg, 0, 0) +#define update_fgt_traps(hctxt, vcpu, kvm, reg) \ + update_fgt_traps_cs(hctxt, vcpu, kvm, reg, 0, 0) /* * Validate the fine grain trap masks. @@ -122,6 +156,7 @@ static inline bool cpu_has_amu(void) static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *hctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; + struct kvm *kvm = kern_hyp_va(vcpu->kvm); u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp; u64 r_val, w_val; @@ -157,6 +192,9 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set); } + compute_undef_clr_set(vcpu, kvm, HFGRTR_EL2, r_clr, r_set); + compute_undef_clr_set(vcpu, kvm, HFGWTR_EL2, w_clr, w_set); + /* The default to trap everything not handled or supported in KVM. */ tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 | HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1; @@ -172,20 +210,26 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) write_sysreg_s(r_val, SYS_HFGRTR_EL2); write_sysreg_s(w_val, SYS_HFGWTR_EL2); - if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) - return; - - update_fgt_traps(vcpu, HFGITR_EL2); - update_fgt_traps(vcpu, HDFGRTR_EL2); - update_fgt_traps(vcpu, HDFGWTR_EL2); + update_fgt_traps(hctxt, vcpu, kvm, HFGITR_EL2); + update_fgt_traps(hctxt, vcpu, kvm, HDFGRTR_EL2); + update_fgt_traps(hctxt, vcpu, kvm, HDFGWTR_EL2); if (cpu_has_amu()) - update_fgt_traps(vcpu, HAFGRTR_EL2); + update_fgt_traps(hctxt, vcpu, kvm, HAFGRTR_EL2); } +#define __deactivate_fgt(htcxt, vcpu, kvm, reg) \ + do { \ + if ((vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) || \ + kvm->arch.fgu[reg_to_fgt_group_id(reg)]) \ + write_sysreg_s(ctxt_sys_reg(hctxt, reg), \ + SYS_ ## reg); \ + } while(0) + static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *hctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; + struct kvm *kvm = kern_hyp_va(vcpu->kvm); if (!cpus_have_final_cap(ARM64_HAS_FGT)) return; @@ -193,15 +237,12 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) write_sysreg_s(ctxt_sys_reg(hctxt, HFGRTR_EL2), SYS_HFGRTR_EL2); write_sysreg_s(ctxt_sys_reg(hctxt, HFGWTR_EL2), SYS_HFGWTR_EL2); - if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) - return; - - write_sysreg_s(ctxt_sys_reg(hctxt, HFGITR_EL2), SYS_HFGITR_EL2); - write_sysreg_s(ctxt_sys_reg(hctxt, HDFGRTR_EL2), SYS_HDFGRTR_EL2); - write_sysreg_s(ctxt_sys_reg(hctxt, HDFGWTR_EL2), SYS_HDFGWTR_EL2); + __deactivate_fgt(hctxt, vcpu, kvm, HFGITR_EL2); + __deactivate_fgt(hctxt, vcpu, kvm, HDFGRTR_EL2); + __deactivate_fgt(hctxt, vcpu, kvm, HDFGWTR_EL2); if (cpu_has_amu()) - write_sysreg_s(ctxt_sys_reg(hctxt, HAFGRTR_EL2), SYS_HAFGRTR_EL2); + __deactivate_fgt(hctxt, vcpu, kvm, HAFGRTR_EL2); } static inline void __activate_traps_common(struct kvm_vcpu *vcpu) From c5bac1ef7df6bcce4feaa5a609119cab5d5e4730 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:20 +0000 Subject: [PATCH 356/814] KVM: arm64: Move existing feature disabling over to FGU infrastructure We already trap a bunch of existing features for the purpose of disabling them (MAIR2, POR, ACCDATA, SME...). Let's move them over to our brand new FGU infrastructure. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-20-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 4 ++++ arch/arm64/kvm/arm.c | 6 ++++++ arch/arm64/kvm/hyp/include/hyp/switch.h | 17 +++-------------- arch/arm64/kvm/sys_regs.c | 23 +++++++++++++++++++++++ 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index c69b258fc989..968a997b3f02 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -297,6 +297,8 @@ struct kvm_arch { #define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 6 /* Initial ID reg values loaded */ #define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 7 + /* Fine-Grained UNDEF initialised */ +#define KVM_ARCH_FLAG_FGU_INITIALIZED 8 unsigned long flags; /* VM-wide vCPU feature set */ @@ -1107,6 +1109,8 @@ int __init populate_nv_trap_config(void); bool lock_all_vcpus(struct kvm *kvm); void unlock_all_vcpus(struct kvm *kvm); +void kvm_init_sysreg(struct kvm_vcpu *); + /* MMIO helpers */ void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index c063e84fc72c..9f806c9b7d5d 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -675,6 +675,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) return ret; } + /* + * This needs to happen after NV has imposed its own restrictions on + * the feature set + */ + kvm_init_sysreg(vcpu); + ret = kvm_timer_enable(vcpu); if (ret) return ret; diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index a09149fd91ed..245f9c1ca666 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -157,7 +157,7 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *hctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; struct kvm *kvm = kern_hyp_va(vcpu->kvm); - u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp; + u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0; u64 r_val, w_val; CHECK_FGT_MASKS(HFGRTR_EL2); @@ -174,13 +174,6 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) ctxt_sys_reg(hctxt, HFGRTR_EL2) = read_sysreg_s(SYS_HFGRTR_EL2); ctxt_sys_reg(hctxt, HFGWTR_EL2) = read_sysreg_s(SYS_HFGWTR_EL2); - if (cpus_have_final_cap(ARM64_SME)) { - tmp = HFGxTR_EL2_nSMPRI_EL1_MASK | HFGxTR_EL2_nTPIDR2_EL0_MASK; - - r_clr |= tmp; - w_clr |= tmp; - } - /* * Trap guest writes to TCR_EL1 to prevent it from enabling HA or HD. */ @@ -195,15 +188,11 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) compute_undef_clr_set(vcpu, kvm, HFGRTR_EL2, r_clr, r_set); compute_undef_clr_set(vcpu, kvm, HFGWTR_EL2, w_clr, w_set); - /* The default to trap everything not handled or supported in KVM. */ - tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 | - HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1; - - r_val = __HFGRTR_EL2_nMASK & ~tmp; + r_val = __HFGRTR_EL2_nMASK; r_val |= r_set; r_val &= ~r_clr; - w_val = __HFGWTR_EL2_nMASK & ~tmp; + w_val = __HFGWTR_EL2_nMASK; w_val |= w_set; w_val &= ~w_clr; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 938df5dc3684..39e7c7f74717 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3942,6 +3942,29 @@ int kvm_vm_ioctl_get_reg_writable_masks(struct kvm *kvm, struct reg_mask_range * return 0; } +void kvm_init_sysreg(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + + mutex_lock(&kvm->arch.config_lock); + + if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags)) + goto out; + + kvm->arch.fgu[HFGxTR_GROUP] = (HFGxTR_EL2_nAMAIR2_EL1 | + HFGxTR_EL2_nMAIR2_EL1 | + HFGxTR_EL2_nS2POR_EL1 | + HFGxTR_EL2_nPOR_EL1 | + HFGxTR_EL2_nPOR_EL0 | + HFGxTR_EL2_nACCDATA_EL1 | + HFGxTR_EL2_nSMPRI_EL1_MASK | + HFGxTR_EL2_nTPIDR2_EL0_MASK); + + set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags); +out: + mutex_unlock(&kvm->arch.config_lock); +} + int __init kvm_sys_reg_table_init(void) { struct sys_reg_params params; From d196c20c6e58686fa46285c6528acc0b19357b84 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:21 +0000 Subject: [PATCH 357/814] KVM: arm64: Streamline save/restore of HFG[RW]TR_EL2 The way we save/restore HFG[RW]TR_EL2 can now be simplified, and the Ampere erratum hack is the only thing that still stands out. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-21-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/include/hyp/switch.h | 42 ++++++------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 245f9c1ca666..2d5891518006 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -157,8 +157,6 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *hctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; struct kvm *kvm = kern_hyp_va(vcpu->kvm); - u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0; - u64 r_val, w_val; CHECK_FGT_MASKS(HFGRTR_EL2); CHECK_FGT_MASKS(HFGWTR_EL2); @@ -171,34 +169,10 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) if (!cpus_have_final_cap(ARM64_HAS_FGT)) return; - ctxt_sys_reg(hctxt, HFGRTR_EL2) = read_sysreg_s(SYS_HFGRTR_EL2); - ctxt_sys_reg(hctxt, HFGWTR_EL2) = read_sysreg_s(SYS_HFGWTR_EL2); - - /* - * Trap guest writes to TCR_EL1 to prevent it from enabling HA or HD. - */ - if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38)) - w_set |= HFGxTR_EL2_TCR_EL1_MASK; - - if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) { - compute_clr_set(vcpu, HFGRTR_EL2, r_clr, r_set); - compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set); - } - - compute_undef_clr_set(vcpu, kvm, HFGRTR_EL2, r_clr, r_set); - compute_undef_clr_set(vcpu, kvm, HFGWTR_EL2, w_clr, w_set); - - r_val = __HFGRTR_EL2_nMASK; - r_val |= r_set; - r_val &= ~r_clr; - - w_val = __HFGWTR_EL2_nMASK; - w_val |= w_set; - w_val &= ~w_clr; - - write_sysreg_s(r_val, SYS_HFGRTR_EL2); - write_sysreg_s(w_val, SYS_HFGWTR_EL2); - + update_fgt_traps(hctxt, vcpu, kvm, HFGRTR_EL2); + update_fgt_traps_cs(hctxt, vcpu, kvm, HFGWTR_EL2, 0, + cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38) ? + HFGxTR_EL2_TCR_EL1_MASK : 0); update_fgt_traps(hctxt, vcpu, kvm, HFGITR_EL2); update_fgt_traps(hctxt, vcpu, kvm, HDFGRTR_EL2); update_fgt_traps(hctxt, vcpu, kvm, HDFGWTR_EL2); @@ -223,9 +197,11 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) if (!cpus_have_final_cap(ARM64_HAS_FGT)) return; - write_sysreg_s(ctxt_sys_reg(hctxt, HFGRTR_EL2), SYS_HFGRTR_EL2); - write_sysreg_s(ctxt_sys_reg(hctxt, HFGWTR_EL2), SYS_HFGWTR_EL2); - + __deactivate_fgt(hctxt, vcpu, kvm, HFGRTR_EL2); + if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38)) + write_sysreg_s(ctxt_sys_reg(hctxt, HFGWTR_EL2), SYS_HFGWTR_EL2); + else + __deactivate_fgt(hctxt, vcpu, kvm, HFGWTR_EL2); __deactivate_fgt(hctxt, vcpu, kvm, HFGITR_EL2); __deactivate_fgt(hctxt, vcpu, kvm, HDFGRTR_EL2); __deactivate_fgt(hctxt, vcpu, kvm, HDFGWTR_EL2); From 8ecdccb9e5dbbddfe5eb2d4201c1b921461b1bd4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:22 +0000 Subject: [PATCH 358/814] KVM: arm64: Make TLBI OS/Range UNDEF if not advertised to the guest Outer Shareable and Range TLBI instructions shouldn't be made available to the guest if they are not advertised. Use FGU to disable those, and set HCR_EL2.TLBIOS in the case the host doesn't have FGT. Note that in that later case, we cannot efficiently disable TLBI Range instructions, as this would require to trap all TLBIs. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-22-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 39e7c7f74717..f07ee7c89822 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3948,6 +3948,14 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) mutex_lock(&kvm->arch.config_lock); + /* + * In the absence of FGT, we cannot independently trap TLBI + * Range instructions. This isn't great, but trapping all + * TLBIs would be far worse. Live with it... + */ + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + vcpu->arch.hcr_el2 |= HCR_TTLBOS; + if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags)) goto out; @@ -3960,6 +3968,32 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) HFGxTR_EL2_nSMPRI_EL1_MASK | HFGxTR_EL2_nTPIDR2_EL0_MASK); + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_TLBIRVAALE1OS| + HFGITR_EL2_TLBIRVALE1OS | + HFGITR_EL2_TLBIRVAAE1OS | + HFGITR_EL2_TLBIRVAE1OS | + HFGITR_EL2_TLBIVAALE1OS | + HFGITR_EL2_TLBIVALE1OS | + HFGITR_EL2_TLBIVAAE1OS | + HFGITR_EL2_TLBIASIDE1OS | + HFGITR_EL2_TLBIVAE1OS | + HFGITR_EL2_TLBIVMALLE1OS); + + if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_TLBIRVAALE1 | + HFGITR_EL2_TLBIRVALE1 | + HFGITR_EL2_TLBIRVAAE1 | + HFGITR_EL2_TLBIRVAE1 | + HFGITR_EL2_TLBIRVAALE1IS| + HFGITR_EL2_TLBIRVALE1IS | + HFGITR_EL2_TLBIRVAAE1IS | + HFGITR_EL2_TLBIRVAE1IS | + HFGITR_EL2_TLBIRVAALE1OS| + HFGITR_EL2_TLBIRVALE1OS | + HFGITR_EL2_TLBIRVAAE1OS | + HFGITR_EL2_TLBIRVAE1OS); + set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags); out: mutex_unlock(&kvm->arch.config_lock); From 58627b722ee2e6cfd0b6ebe27d056f7c23acc99d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:23 +0000 Subject: [PATCH 359/814] KVM: arm64: Make PIR{,E0}_EL1 UNDEF if S1PIE is not advertised to the guest As part of the ongoing effort to honor the guest configuration, add the necessary checks to make PIR_EL1 and co UNDEF if not advertised to the guest, and avoid context switching them. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-23-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 24 +++++++++++++++++++--- arch/arm64/kvm/sys_regs.c | 4 ++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h index bb6b571ec627..4be6a7fa0070 100644 --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -27,16 +27,34 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt) ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0); } -static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt) +static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt) { struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu; if (!vcpu) vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt); + return vcpu; +} + +static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt) +{ + struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt); + return kvm_has_mte(kern_hyp_va(vcpu->kvm)); } +static inline bool ctxt_has_s1pie(struct kvm_cpu_context *ctxt) +{ + struct kvm_vcpu *vcpu; + + if (!cpus_have_final_cap(ARM64_HAS_S1PIE)) + return false; + + vcpu = ctxt_to_vcpu(ctxt); + return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1PIE, IMP); +} + static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) { ctxt_sys_reg(ctxt, SCTLR_EL1) = read_sysreg_el1(SYS_SCTLR); @@ -55,7 +73,7 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) ctxt_sys_reg(ctxt, CONTEXTIDR_EL1) = read_sysreg_el1(SYS_CONTEXTIDR); ctxt_sys_reg(ctxt, AMAIR_EL1) = read_sysreg_el1(SYS_AMAIR); ctxt_sys_reg(ctxt, CNTKCTL_EL1) = read_sysreg_el1(SYS_CNTKCTL); - if (cpus_have_final_cap(ARM64_HAS_S1PIE)) { + if (ctxt_has_s1pie(ctxt)) { ctxt_sys_reg(ctxt, PIR_EL1) = read_sysreg_el1(SYS_PIR); ctxt_sys_reg(ctxt, PIRE0_EL1) = read_sysreg_el1(SYS_PIRE0); } @@ -131,7 +149,7 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) write_sysreg_el1(ctxt_sys_reg(ctxt, CONTEXTIDR_EL1), SYS_CONTEXTIDR); write_sysreg_el1(ctxt_sys_reg(ctxt, AMAIR_EL1), SYS_AMAIR); write_sysreg_el1(ctxt_sys_reg(ctxt, CNTKCTL_EL1), SYS_CNTKCTL); - if (cpus_have_final_cap(ARM64_HAS_S1PIE)) { + if (ctxt_has_s1pie(ctxt)) { write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1), SYS_PIR); write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1), SYS_PIRE0); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index f07ee7c89822..da9db99c77e7 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3994,6 +3994,10 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) HFGITR_EL2_TLBIRVAAE1OS | HFGITR_EL2_TLBIRVAE1OS); + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1PIE, IMP)) + kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPIRE0_EL1 | + HFGxTR_EL2_nPIR_EL1); + set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags); out: mutex_unlock(&kvm->arch.config_lock); From b03e8bb5a906ab0b67fe90e636c3ebff8eb0e91c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:24 +0000 Subject: [PATCH 360/814] KVM: arm64: Make AMU sysreg UNDEF if FEAT_AMU is not advertised to the guest No AMU? No AMU! IF we see an AMU-related trap, let's turn it into an UNDEF! Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-24-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index da9db99c77e7..38ed47bd29db 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3998,6 +3998,10 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPIRE0_EL1 | HFGxTR_EL2_nPIR_EL1); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP)) + kvm->arch.fgu[HAFGRTR_GROUP] |= ~(HAFGRTR_EL2_RES0 | + HAFGRTR_EL2_RES1); + set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags); out: mutex_unlock(&kvm->arch.config_lock); From 84de212d739ecd16c6289ec4ed47e27b0080bac6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:25 +0000 Subject: [PATCH 361/814] KVM: arm64: Make FEAT_MOPS UNDEF if not advertised to the guest We unconditionally enable FEAT_MOPS, which is obviously wrong. So let's only do that when it is advertised to the guest. Which means we need to rely on a per-vcpu HCRX_EL2 shadow register. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20240214131827.2856277-25-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_arm.h | 4 +--- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +- arch/arm64/kvm/sys_regs.c | 7 +++++++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 3c6f8ba1e479..a1769e415d72 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -102,9 +102,7 @@ #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC) #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) -#define HCRX_GUEST_FLAGS \ - (HCRX_EL2_SMPME | HCRX_EL2_TCR2En | \ - (cpus_have_final_cap(ARM64_HAS_MOPS) ? (HCRX_EL2_MSCEn | HCRX_EL2_MCE2) : 0)) +#define HCRX_GUEST_FLAGS (HCRX_EL2_SMPME | HCRX_EL2_TCR2En) #define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En) /* TCR_EL2 Registers bits */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 968a997b3f02..3feabde9c926 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -584,6 +584,7 @@ struct kvm_vcpu_arch { /* Values of trap registers for the guest. */ u64 hcr_el2; + u64 hcrx_el2; u64 mdcr_el2; u64 cptr_el2; diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 2d5891518006..e3fcf8c4d5b4 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -236,7 +236,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu) write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); if (cpus_have_final_cap(ARM64_HAS_HCX)) { - u64 hcrx = HCRX_GUEST_FLAGS; + u64 hcrx = vcpu->arch.hcrx_el2; if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) { u64 clr = 0, set = 0; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 38ed47bd29db..2cb69efac1dc 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3956,6 +3956,13 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) vcpu->arch.hcr_el2 |= HCR_TTLBOS; + if (cpus_have_final_cap(ARM64_HAS_HCX)) { + vcpu->arch.hcrx_el2 = HCRX_GUEST_FLAGS; + + if (kvm_has_feat(kvm, ID_AA64ISAR2_EL1, MOPS, IMP)) + vcpu->arch.hcrx_el2 |= (HCRX_EL2_MSCEn | HCRX_EL2_MCE2); + } + if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags)) goto out; From b80b701d5a67d07f4df4a21e09cb31f6bc1feeca Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:26 +0000 Subject: [PATCH 362/814] KVM: arm64: Snapshot all non-zero RES0/RES1 sysreg fields for later checking As KVM now strongly relies on accurately handling the RES0/RES1 bits on a number of paths, add a compile-time checker that will blow in the face of the innocent bystander, should they try to sneak in an update that changes any of these RES0/RES1 fields. It is expected that such an update will come with the relevant KVM update if needed. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-26-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/check-res-bits.h | 121 ++++++++++++++++++++++++++++++++ arch/arm64/kvm/sys_regs.c | 3 + 2 files changed, 124 insertions(+) create mode 100644 arch/arm64/kvm/check-res-bits.h diff --git a/arch/arm64/kvm/check-res-bits.h b/arch/arm64/kvm/check-res-bits.h new file mode 100644 index 000000000000..967b5d171d53 --- /dev/null +++ b/arch/arm64/kvm/check-res-bits.h @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 - Google LLC + * Author: Marc Zyngier + */ + +#include + +/* + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * If any of these BUILD_BUG_ON() fails, that's because some bits that + * were reserved have gained some other meaning, and KVM needs to know + * about those. + * + * In such case, do *NOT* blindly change the assertion so that it + * passes, but also teach the rest of the code about the actual + * change. + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ +static inline void check_res_bits(void) +{ + BUILD_BUG_ON(OSDTRRX_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(MDCCINT_EL1_RES0 != (GENMASK_ULL(63, 31) | GENMASK_ULL(28, 0))); + BUILD_BUG_ON(MDSCR_EL1_RES0 != (GENMASK_ULL(63, 36) | GENMASK_ULL(28, 28) | GENMASK_ULL(25, 24) | GENMASK_ULL(20, 20) | GENMASK_ULL(18, 16) | GENMASK_ULL(11, 7) | GENMASK_ULL(5, 1))); + BUILD_BUG_ON(OSDTRTX_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(OSECCR_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(OSLAR_EL1_RES0 != (GENMASK_ULL(63, 1))); + BUILD_BUG_ON(ID_PFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_PFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_DFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_AFR0_EL1_RES0 != (GENMASK_ULL(63, 16))); + BUILD_BUG_ON(ID_MMFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_MMFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_MMFR2_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_MMFR3_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_ISAR0_EL1_RES0 != (GENMASK_ULL(63, 28))); + BUILD_BUG_ON(ID_ISAR1_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_ISAR2_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_ISAR3_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_ISAR4_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_ISAR5_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(23, 20))); + BUILD_BUG_ON(ID_ISAR6_EL1_RES0 != (GENMASK_ULL(63, 28))); + BUILD_BUG_ON(ID_MMFR4_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(MVFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(MVFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(MVFR2_EL1_RES0 != (GENMASK_ULL(63, 8))); + BUILD_BUG_ON(ID_PFR2_EL1_RES0 != (GENMASK_ULL(63, 12))); + BUILD_BUG_ON(ID_DFR1_EL1_RES0 != (GENMASK_ULL(63, 8))); + BUILD_BUG_ON(ID_MMFR5_EL1_RES0 != (GENMASK_ULL(63, 8))); + BUILD_BUG_ON(ID_AA64PFR1_EL1_RES0 != (GENMASK_ULL(23, 20))); + BUILD_BUG_ON(ID_AA64PFR2_EL1_RES0 != (GENMASK_ULL(63, 36) | GENMASK_ULL(31, 12))); + BUILD_BUG_ON(ID_AA64ZFR0_EL1_RES0 != (GENMASK_ULL(63, 60) | GENMASK_ULL(51, 48) | GENMASK_ULL(39, 36) | GENMASK_ULL(31, 28) | GENMASK_ULL(15, 8))); + BUILD_BUG_ON(ID_AA64SMFR0_EL1_RES0 != (GENMASK_ULL(62, 61) | GENMASK_ULL(51, 49) | GENMASK_ULL(31, 31) | GENMASK_ULL(27, 0))); + BUILD_BUG_ON(ID_AA64FPFR0_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 2))); + BUILD_BUG_ON(ID_AA64DFR0_EL1_RES0 != (GENMASK_ULL(27, 24) | GENMASK_ULL(19, 16))); + BUILD_BUG_ON(ID_AA64DFR1_EL1_RES0 != (GENMASK_ULL(63, 0))); + BUILD_BUG_ON(ID_AA64AFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(ID_AA64AFR1_EL1_RES0 != (GENMASK_ULL(63, 0))); + BUILD_BUG_ON(ID_AA64ISAR0_EL1_RES0 != (GENMASK_ULL(3, 0))); + BUILD_BUG_ON(ID_AA64ISAR2_EL1_RES0 != (GENMASK_ULL(47, 44))); + BUILD_BUG_ON(ID_AA64ISAR3_EL1_RES0 != (GENMASK_ULL(63, 16))); + BUILD_BUG_ON(ID_AA64MMFR0_EL1_RES0 != (GENMASK_ULL(55, 48))); + BUILD_BUG_ON(ID_AA64MMFR2_EL1_RES0 != (GENMASK_ULL(47, 44))); + BUILD_BUG_ON(ID_AA64MMFR3_EL1_RES0 != (GENMASK_ULL(51, 48))); + BUILD_BUG_ON(ID_AA64MMFR4_EL1_RES0 != (GENMASK_ULL(63, 40) | GENMASK_ULL(35, 28) | GENMASK_ULL(3, 0))); + BUILD_BUG_ON(SCTLR_EL1_RES0 != (GENMASK_ULL(17, 17))); + BUILD_BUG_ON(CPACR_ELx_RES0 != (GENMASK_ULL(63, 30) | GENMASK_ULL(27, 26) | GENMASK_ULL(23, 22) | GENMASK_ULL(19, 18) | GENMASK_ULL(15, 0))); + BUILD_BUG_ON(SMPRI_EL1_RES0 != (GENMASK_ULL(63, 4))); + BUILD_BUG_ON(ZCR_ELx_RES0 != (GENMASK_ULL(63, 9))); + BUILD_BUG_ON(SMCR_ELx_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(29, 9))); + BUILD_BUG_ON(GCSCR_ELx_RES0 != (GENMASK_ULL(63, 10) | GENMASK_ULL(7, 7) | GENMASK_ULL(4, 1))); + BUILD_BUG_ON(GCSPR_ELx_RES0 != (GENMASK_ULL(2, 0))); + BUILD_BUG_ON(GCSCRE0_EL1_RES0 != (GENMASK_ULL(63, 11) | GENMASK_ULL(7, 6) | GENMASK_ULL(4, 1))); + BUILD_BUG_ON(ALLINT_RES0 != (GENMASK_ULL(63, 14) | GENMASK_ULL(12, 0))); + BUILD_BUG_ON(PMSCR_EL1_RES0 != (GENMASK_ULL(63, 8) | GENMASK_ULL(2, 2))); + BUILD_BUG_ON(PMSICR_EL1_RES0 != (GENMASK_ULL(55, 32))); + BUILD_BUG_ON(PMSIRR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(7, 1))); + BUILD_BUG_ON(PMSFCR_EL1_RES0 != (GENMASK_ULL(63, 19) | GENMASK_ULL(15, 4))); + BUILD_BUG_ON(PMSLATFR_EL1_RES0 != (GENMASK_ULL(63, 16))); + BUILD_BUG_ON(PMSIDR_EL1_RES0 != (GENMASK_ULL(63, 25) | GENMASK_ULL(7, 7))); + BUILD_BUG_ON(PMBLIMITR_EL1_RES0 != (GENMASK_ULL(11, 6) | GENMASK_ULL(4, 3))); + BUILD_BUG_ON(PMBSR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(25, 20))); + BUILD_BUG_ON(PMBIDR_EL1_RES0 != (GENMASK_ULL(63, 12) | GENMASK_ULL(7, 6))); + BUILD_BUG_ON(CONTEXTIDR_ELx_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(CCSIDR_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(CLIDR_EL1_RES0 != (GENMASK_ULL(63, 47))); + BUILD_BUG_ON(CCSIDR2_EL1_RES0 != (GENMASK_ULL(63, 24))); + BUILD_BUG_ON(GMID_EL1_RES0 != (GENMASK_ULL(63, 4))); + BUILD_BUG_ON(SMIDR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(14, 12))); + BUILD_BUG_ON(CSSELR_EL1_RES0 != (GENMASK_ULL(63, 5))); + BUILD_BUG_ON(CTR_EL0_RES0 != (GENMASK_ULL(63, 38) | GENMASK_ULL(30, 30) | GENMASK_ULL(13, 4))); + BUILD_BUG_ON(CTR_EL0_RES1 != (GENMASK_ULL(31, 31))); + BUILD_BUG_ON(DCZID_EL0_RES0 != (GENMASK_ULL(63, 5))); + BUILD_BUG_ON(SVCR_RES0 != (GENMASK_ULL(63, 2))); + BUILD_BUG_ON(FPMR_RES0 != (GENMASK_ULL(63, 38) | GENMASK_ULL(23, 23) | GENMASK_ULL(13, 9))); + BUILD_BUG_ON(HFGxTR_EL2_RES0 != (GENMASK_ULL(51, 51))); + BUILD_BUG_ON(HFGITR_EL2_RES0 != (GENMASK_ULL(63, 63) | GENMASK_ULL(61, 61))); + BUILD_BUG_ON(HDFGRTR_EL2_RES0 != (GENMASK_ULL(49, 49) | GENMASK_ULL(42, 42) | GENMASK_ULL(39, 38) | GENMASK_ULL(21, 20) | GENMASK_ULL(8, 8))); + BUILD_BUG_ON(HDFGWTR_EL2_RES0 != (GENMASK_ULL(63, 63) | GENMASK_ULL(59, 58) | GENMASK_ULL(51, 51) | GENMASK_ULL(47, 47) | GENMASK_ULL(43, 43) | GENMASK_ULL(40, 38) | GENMASK_ULL(34, 34) | GENMASK_ULL(30, 30) | GENMASK_ULL(22, 22) | GENMASK_ULL(9, 9) | GENMASK_ULL(6, 6))); + BUILD_BUG_ON(HAFGRTR_EL2_RES0 != (GENMASK_ULL(63, 50) | GENMASK_ULL(16, 5))); + BUILD_BUG_ON(HCRX_EL2_RES0 != (GENMASK_ULL(63, 25) | GENMASK_ULL(13, 12))); + BUILD_BUG_ON(DACR32_EL2_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(PMSCR_EL2_RES0 != (GENMASK_ULL(63, 8) | GENMASK_ULL(2, 2))); + BUILD_BUG_ON(TCR2_EL1x_RES0 != (GENMASK_ULL(63, 16) | GENMASK_ULL(13, 12) | GENMASK_ULL(9, 6))); + BUILD_BUG_ON(TCR2_EL2_RES0 != (GENMASK_ULL(63, 16))); + BUILD_BUG_ON(LORSA_EL1_RES0 != (GENMASK_ULL(63, 52) | GENMASK_ULL(15, 1))); + BUILD_BUG_ON(LOREA_EL1_RES0 != (GENMASK_ULL(63, 52) | GENMASK_ULL(15, 0))); + BUILD_BUG_ON(LORN_EL1_RES0 != (GENMASK_ULL(63, 8))); + BUILD_BUG_ON(LORC_EL1_RES0 != (GENMASK_ULL(63, 10) | GENMASK_ULL(1, 1))); + BUILD_BUG_ON(LORID_EL1_RES0 != (GENMASK_ULL(63, 24) | GENMASK_ULL(15, 8))); + BUILD_BUG_ON(ISR_EL1_RES0 != (GENMASK_ULL(63, 11) | GENMASK_ULL(5, 0))); + BUILD_BUG_ON(ICC_NMIAR1_EL1_RES0 != (GENMASK_ULL(63, 24))); + BUILD_BUG_ON(TRBLIMITR_EL1_RES0 != (GENMASK_ULL(11, 7))); + BUILD_BUG_ON(TRBBASER_EL1_RES0 != (GENMASK_ULL(11, 0))); + BUILD_BUG_ON(TRBSR_EL1_RES0 != (GENMASK_ULL(63, 56) | GENMASK_ULL(25, 24) | GENMASK_ULL(19, 19) | GENMASK_ULL(16, 16))); + BUILD_BUG_ON(TRBMAR_EL1_RES0 != (GENMASK_ULL(63, 12))); + BUILD_BUG_ON(TRBTRG_EL1_RES0 != (GENMASK_ULL(63, 32))); + BUILD_BUG_ON(TRBIDR_EL1_RES0 != (GENMASK_ULL(63, 12) | GENMASK_ULL(7, 6))); +} diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 2cb69efac1dc..b5335e5a6e6e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -31,6 +31,7 @@ #include +#include "check-res-bits.h" #include "sys_regs.h" #include "trace.h" @@ -4021,6 +4022,8 @@ int __init kvm_sys_reg_table_init(void) unsigned int i; int ret = 0; + check_res_bits(); + /* Make sure tables are unique and in order. */ valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false); valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), true); From 891766581deaf84919911c6a046592ce0ac49bc6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 14 Feb 2024 13:18:27 +0000 Subject: [PATCH 363/814] KVM: arm64: Add debugfs file for guest's ID registers Debugging ID register setup can be a complicated affair. Give the kernel hacker a way to dump that state in an easy to parse way. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20240214131827.2856277-27-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 3 ++ arch/arm64/kvm/sys_regs.c | 81 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 3feabde9c926..181fef12e8e8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -319,6 +319,9 @@ struct kvm_arch { /* PMCR_EL0.N value for the guest */ u8 pmcr_n; + /* Iterator for idreg debugfs */ + u8 idreg_debugfs_iter; + /* Hypercall features firmware registers' descriptor */ struct kvm_smccc_features smccc_feat; struct maple_tree smccc_filter; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index b5335e5a6e6e..e3faedc8b7a3 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -3422,6 +3423,81 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu, return false; } +static void *idregs_debug_start(struct seq_file *s, loff_t *pos) +{ + struct kvm *kvm = s->private; + u8 *iter; + + mutex_lock(&kvm->arch.config_lock); + + iter = &kvm->arch.idreg_debugfs_iter; + if (*iter == (u8)~0) { + *iter = *pos; + if (*iter >= KVM_ARM_ID_REG_NUM) + iter = NULL; + } else { + iter = ERR_PTR(-EBUSY); + } + + mutex_unlock(&kvm->arch.config_lock); + + return iter; +} + +static void *idregs_debug_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct kvm *kvm = s->private; + + (*pos)++; + + if ((kvm->arch.idreg_debugfs_iter + 1) < KVM_ARM_ID_REG_NUM) { + kvm->arch.idreg_debugfs_iter++; + + return &kvm->arch.idreg_debugfs_iter; + } + + return NULL; +} + +static void idregs_debug_stop(struct seq_file *s, void *v) +{ + struct kvm *kvm = s->private; + + if (IS_ERR(v)) + return; + + mutex_lock(&kvm->arch.config_lock); + + kvm->arch.idreg_debugfs_iter = ~0; + + mutex_unlock(&kvm->arch.config_lock); +} + +static int idregs_debug_show(struct seq_file *s, void *v) +{ + struct kvm *kvm = s->private; + const struct sys_reg_desc *desc; + + desc = first_idreg + kvm->arch.idreg_debugfs_iter; + + if (!desc->name) + return 0; + + seq_printf(s, "%20s:\t%016llx\n", + desc->name, IDREG(kvm, IDX_IDREG(kvm->arch.idreg_debugfs_iter))); + + return 0; +} + +static const struct seq_operations idregs_debug_sops = { + .start = idregs_debug_start, + .next = idregs_debug_next, + .stop = idregs_debug_stop, + .show = idregs_debug_show, +}; + +DEFINE_SEQ_ATTRIBUTE(idregs_debug); + static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) { const struct sys_reg_desc *idreg = first_idreg; @@ -3441,6 +3517,11 @@ static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) id = reg_to_encoding(idreg); } + kvm->arch.idreg_debugfs_iter = ~0; + + debugfs_create_file("idregs", 0444, kvm->debugfs_dentry, kvm, + &idregs_debug_fops); + set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags); } From 8f06fb45853900b4deaa52e2a9e16f3d9550b011 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:37:31 -0300 Subject: [PATCH 364/814] i3c: Make i3c_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the i3c_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240213-bus_cleanup-i3c-v1-1-403aea18f05a@marliere.net Signed-off-by: Alexandre Belloni --- drivers/i3c/internals.h | 2 +- drivers/i3c/master.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h index 908a807badaf..4d99a3524171 100644 --- a/drivers/i3c/internals.h +++ b/drivers/i3c/internals.h @@ -10,7 +10,7 @@ #include -extern struct bus_type i3c_bus_type; +extern const struct bus_type i3c_bus_type; void i3c_bus_normaluse_lock(struct i3c_bus *bus); void i3c_bus_normaluse_unlock(struct i3c_bus *bus); diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 3afa530c5e32..f32c591ae325 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -335,7 +335,7 @@ static void i3c_device_remove(struct device *dev) i3c_device_free_ibi(i3cdev); } -struct bus_type i3c_bus_type = { +const struct bus_type i3c_bus_type = { .name = "i3c", .match = i3c_device_match, .probe = i3c_device_probe, From a77dabc8e8e4686f542f35e9e3ef09310b018b23 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:47 +0000 Subject: [PATCH 365/814] MIPS: Unify define of CP0 registers for uasm code Definitions of uasm variant of CP0 registers are unified to mipsregs.h, so they lay together with uasm variant of the code. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mipsregs.h | 249 ++++++++++++++++++++++++------- arch/mips/kvm/entry.c | 27 +--- arch/mips/mm/tlbex.c | 18 +-- 3 files changed, 200 insertions(+), 94 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index ec58cb76d076..59ea637c5975 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -42,59 +42,198 @@ /* * Coprocessor 0 register names + * + * CP0_REGISTER variant is meant to be used in assembly code, C0_REGISTER + * variant is meant to be used in C (uasm) code. */ -#define CP0_INDEX $0 -#define CP0_RANDOM $1 -#define CP0_ENTRYLO0 $2 -#define CP0_ENTRYLO1 $3 -#define CP0_CONF $3 -#define CP0_GLOBALNUMBER $3, 1 -#define CP0_CONTEXT $4 -#define CP0_PAGEMASK $5 -#define CP0_PAGEGRAIN $5, 1 -#define CP0_SEGCTL0 $5, 2 -#define CP0_SEGCTL1 $5, 3 -#define CP0_SEGCTL2 $5, 4 -#define CP0_WIRED $6 -#define CP0_INFO $7 -#define CP0_HWRENA $7 -#define CP0_BADVADDR $8 -#define CP0_BADINSTR $8, 1 -#define CP0_COUNT $9 -#define CP0_ENTRYHI $10 -#define CP0_GUESTCTL1 $10, 4 -#define CP0_GUESTCTL2 $10, 5 -#define CP0_GUESTCTL3 $10, 6 -#define CP0_COMPARE $11 -#define CP0_GUESTCTL0EXT $11, 4 -#define CP0_STATUS $12 -#define CP0_GUESTCTL0 $12, 6 -#define CP0_GTOFFSET $12, 7 -#define CP0_CAUSE $13 -#define CP0_EPC $14 -#define CP0_PRID $15 -#define CP0_EBASE $15, 1 -#define CP0_CMGCRBASE $15, 3 -#define CP0_CONFIG $16 -#define CP0_CONFIG3 $16, 3 -#define CP0_CONFIG5 $16, 5 -#define CP0_CONFIG6 $16, 6 -#define CP0_LLADDR $17 -#define CP0_WATCHLO $18 -#define CP0_WATCHHI $19 -#define CP0_XCONTEXT $20 -#define CP0_FRAMEMASK $21 -#define CP0_DIAGNOSTIC $22 -#define CP0_DIAGNOSTIC1 $22, 1 -#define CP0_DEBUG $23 -#define CP0_DEPC $24 -#define CP0_PERFORMANCE $25 -#define CP0_ECC $26 -#define CP0_CACHEERR $27 -#define CP0_TAGLO $28 -#define CP0_TAGHI $29 -#define CP0_ERROREPC $30 -#define CP0_DESAVE $31 +#define CP0_INDEX $0 +#define C0_INDEX 0, 0 + +#define CP0_RANDOM $1 +#define C0_RANDOM 1, 0 + +#define CP0_ENTRYLO0 $2 +#define C0_ENTRYLO0 2, 0 + +#define CP0_ENTRYLO1 $3 +#define C0_ENTRYLO1 3, 0 + +#define CP0_CONF $3 +#define C0_CONF 3, 0 + +#define CP0_GLOBALNUMBER $3, 1 +#define C0_GLOBALNUMBER 3, 1 + +#define CP0_CONTEXT $4 +#define C0_CONTEXT 4, 0 + +#define CP0_PAGEMASK $5 +#define C0_PAGEMASK 5, 0 + +#define CP0_PAGEGRAIN $5, 1 +#define C0_PAGEGRAIN 5, 1 + +#define CP0_SEGCTL0 $5, 2 +#define C0_SEGCTL0 5, 2 + +#define CP0_SEGCTL1 $5, 3 +#define C0_SEGCTL1 5, 3 + +#define CP0_SEGCTL2 $5, 4 +#define C0_SEGCTL2 5, 4 + +#define CP0_PWBASE $5, 5 +#define C0_PWBASE 5, 5 + +#define CP0_PWFIELD $5, 6 +#define C0_PWFIELD 5, 6 + +#define CP0_PWCTL $5, 7 +#define C0_PWCTL 5, 7 + +#define CP0_WIRED $6 +#define C0_WIRED 6, 0 + +#define CP0_INFO $7 +#define C0_INFO 7, 0 + +#define CP0_HWRENA $7 +#define C0_HWRENA 7, 0 + +#define CP0_BADVADDR $8 +#define C0_BADVADDR 8, 0 + +#define CP0_BADINSTR $8, 1 +#define C0_BADINSTR 8, 1 + +#define CP0_BADINSTRP $8, 2 +#define C0_BADINSTRP 8, 2 + +#define CP0_COUNT $9 +#define C0_COUNT 9, 0 + +#define CP0_PGD $9, 7 +#define C0_PGD 9, 7 + +#define CP0_ENTRYHI $10 +#define C0_ENTRYHI 10, 0 + +#define CP0_GUESTCTL1 $10, 4 +#define C0_GUESTCTL1 10, 5 + +#define CP0_GUESTCTL2 $10, 5 +#define C0_GUESTCTL2 10, 5 + +#define CP0_GUESTCTL3 $10, 6 +#define C0_GUESTCTL3 10, 6 + +#define CP0_COMPARE $11 +#define C0_COMPARE 11, 0 + +#define CP0_GUESTCTL0EXT $11, 4 +#define C0_GUESTCTL0EXT 11, 4 + +#define CP0_STATUS $12 +#define C0_STATUS 12, 0 + +#define CP0_GUESTCTL0 $12, 6 +#define C0_GUESTCTL0 12, 6 + +#define CP0_GTOFFSET $12, 7 +#define C0_GTOFFSET 12, 7 + +#define CP0_CAUSE $13 +#define C0_CAUSE 13, 0 + +#define CP0_EPC $14 +#define C0_EPC 14, 0 + +#define CP0_PRID $15 +#define C0_PRID 15, 0 + +#define CP0_EBASE $15, 1 +#define C0_EBASE 15, 1 + +#define CP0_CMGCRBASE $15, 3 +#define C0_CMGCRBASE 15, 3 + +#define CP0_CONFIG $16 +#define C0_CONFIG 16, 0 + +#define CP0_CONFIG1 $16, 1 +#define C0_CONFIG1 16, 1 + +#define CP0_CONFIG2 $16, 2 +#define C0_CONFIG2 16, 2 + +#define CP0_CONFIG3 $16, 3 +#define C0_CONFIG3 16, 3 + +#define CP0_CONFIG4 $16, 4 +#define C0_CONFIG4 16, 4 + +#define CP0_CONFIG5 $16, 5 +#define C0_CONFIG5 16, 5 + +#define CP0_CONFIG6 $16, 6 +#define C0_CONFIG6 16, 6 + +#define CP0_LLADDR $17 +#define C0_LLADDR 17, 0 + +#define CP0_WATCHLO $18 +#define C0_WATCHLO 18, 0 + +#define CP0_WATCHHI $19 +#define C0_WATCHHI 19, 0 + +#define CP0_XCONTEXT $20 +#define C0_XCONTEXT 20, 0 + +#define CP0_FRAMEMASK $21 +#define C0_FRAMEMASK 21, 0 + +#define CP0_DIAGNOSTIC $22 +#define C0_DIAGNOSTIC 22, 0 + +#define CP0_DIAGNOSTIC1 $22, 1 +#define C0_DIAGNOSTIC1 22, 1 + +#define CP0_DEBUG $23 +#define C0_DEBUG 23, 0 + +#define CP0_DEPC $24 +#define C0_DEPC 24, 0 + +#define CP0_PERFORMANCE $25 +#define C0_PERFORMANCE 25, 0 + +#define CP0_ECC $26 +#define C0_ECC 26, 0 + +#define CP0_CACHEERR $27 +#define C0_CACHEERR 27, 0 + +#define CP0_TAGLO $28 +#define C0_TAGLO 28, 0 + +#define CP0_DTAGLO $28, 2 +#define C0_DTAGLO 28, 2 + +#define CP0_DDATALO $28, 3 +#define C0_DDATALO 28, 3 + +#define CP0_STAGLO $28, 4 +#define C0_STAGLO 28, 4 + +#define CP0_TAGHI $29 +#define C0_TAGHI 29, 0 + +#define CP0_ERROREPC $30 +#define C0_ERROREPC 30, 0 + +#define CP0_DESAVE $31 +#define C0_DESAVE 31, 0 /* * R4640/R4650 cp0 register names. These registers are listed @@ -291,6 +430,12 @@ #define ST0_DE 0x00010000 #define ST0_CE 0x00020000 +#ifdef CONFIG_64BIT +#define ST0_KX_IF_64 ST0_KX +#else +#define ST0_KX_IF_64 0 +#endif + /* * Setting c0_status.co enables Hit_Writeback and Hit_Writeback_Invalidate * cacheops in userspace. This bit exists only on RM7000 and RM9000 diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c index aceed14aa1f7..96f64a95f51b 100644 --- a/arch/mips/kvm/entry.c +++ b/arch/mips/kvm/entry.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -50,33 +51,9 @@ #define SP 29 #define RA 31 -/* Some CP0 registers */ -#define C0_PWBASE 5, 5 -#define C0_HWRENA 7, 0 -#define C0_BADVADDR 8, 0 -#define C0_BADINSTR 8, 1 -#define C0_BADINSTRP 8, 2 -#define C0_PGD 9, 7 -#define C0_ENTRYHI 10, 0 -#define C0_GUESTCTL1 10, 4 -#define C0_STATUS 12, 0 -#define C0_GUESTCTL0 12, 6 -#define C0_CAUSE 13, 0 -#define C0_EPC 14, 0 -#define C0_EBASE 15, 1 -#define C0_CONFIG5 16, 5 -#define C0_DDATA_LO 28, 3 -#define C0_ERROREPC 30, 0 - #define CALLFRAME_SIZ 32 -#ifdef CONFIG_64BIT -#define ST0_KX_IF_64 ST0_KX -#else -#define ST0_KX_IF_64 0 -#endif - -static unsigned int scratch_vcpu[2] = { C0_DDATA_LO }; +static unsigned int scratch_vcpu[2] = { C0_DDATALO }; static unsigned int scratch_tmp[2] = { C0_ERROREPC }; enum label_id { diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 4017fa0e2f68..c9d00d9cb3c8 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -280,23 +281,6 @@ static inline void dump_handler(const char *symbol, const void *start, const voi #define K0 26 #define K1 27 -/* Some CP0 registers */ -#define C0_INDEX 0, 0 -#define C0_ENTRYLO0 2, 0 -#define C0_TCBIND 2, 2 -#define C0_ENTRYLO1 3, 0 -#define C0_CONTEXT 4, 0 -#define C0_PAGEMASK 5, 0 -#define C0_PWBASE 5, 5 -#define C0_PWFIELD 5, 6 -#define C0_PWSIZE 5, 7 -#define C0_PWCTL 6, 6 -#define C0_BADVADDR 8, 0 -#define C0_PGD 9, 7 -#define C0_ENTRYHI 10, 0 -#define C0_EPC 14, 0 -#define C0_XCONTEXT 20, 0 - #ifdef CONFIG_64BIT # define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_XCONTEXT) #else From 88ca06ec04fab6cdceed5321c74a812ccc2aa519 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:48 +0000 Subject: [PATCH 366/814] MIPS: regdefs.h: Guard all defines with __ASSEMBLY__ Those definitions are only meant to be used in pure assembly code. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/regdef.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/regdef.h b/arch/mips/include/asm/regdef.h index 3c687df1d515..87ba7be1a847 100644 --- a/arch/mips/include/asm/regdef.h +++ b/arch/mips/include/asm/regdef.h @@ -14,6 +14,7 @@ #include +#ifdef __ASSEMBLY__ #if _MIPS_SIM == _MIPS_SIM_ABI32 /* @@ -102,5 +103,6 @@ #define ra $31 /* return address */ #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */ +#endif /* __ASSEMBLY__ */ #endif /* _ASM_REGDEF_H */ From f42058b037053523439f268f4dd328169cef8ab9 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:49 +0000 Subject: [PATCH 367/814] MIPS: regdefs.h: Define a set of register numbers Define a set of register numbers with their symbolic names to help with uasm code. All names are prefixed by GPR_ to prevent naming clash. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/regdef.h | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/arch/mips/include/asm/regdef.h b/arch/mips/include/asm/regdef.h index 87ba7be1a847..236051364f78 100644 --- a/arch/mips/include/asm/regdef.h +++ b/arch/mips/include/asm/regdef.h @@ -14,6 +14,95 @@ #include +#if _MIPS_SIM == _MIPS_SIM_ABI32 + +/* + * General purpose register numbers for 32 bit ABI + */ +#define GPR_ZERO 0 /* wired zero */ +#define GPR_AT 1 /* assembler temp */ +#define GPR_V0 2 /* return value */ +#define GPR_V1 3 +#define GPR_A0 4 /* argument registers */ +#define GPR_A1 5 +#define GPR_A2 6 +#define GPR_A3 7 +#define GPR_T0 8 /* caller saved */ +#define GPR_T1 9 +#define GPR_T2 10 +#define GPR_T3 11 +#define GPR_T4 12 +#define GPR_TA0 12 +#define GPR_T5 13 +#define GPR_TA1 13 +#define GPR_T6 14 +#define GPR_TA2 14 +#define GPR_T7 15 +#define GPR_TA3 15 +#define GPR_S0 16 /* callee saved */ +#define GPR_S1 17 +#define GPR_S2 18 +#define GPR_S3 19 +#define GPR_S4 20 +#define GPR_S5 21 +#define GPR_S6 22 +#define GPR_S7 23 +#define GPR_T8 24 /* caller saved */ +#define GPR_T9 25 +#define GPR_JP 25 /* PIC jump register */ +#define GPR_K0 26 /* kernel scratch */ +#define GPR_K1 27 +#define GPR_GP 28 /* global pointer */ +#define GPR_SP 29 /* stack pointer */ +#define GPR_FP 30 /* frame pointer */ +#define GPR_S8 30 /* same like fp! */ +#define GPR_RA 31 /* return address */ + +#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ + +#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 + +#define GPR_ZERO 0 /* wired zero */ +#define GPR_AT 1 /* assembler temp */ +#define GPR_V0 2 /* return value - caller saved */ +#define GPR_V1 3 +#define GPR_A0 4 /* argument registers */ +#define GPR_A1 5 +#define GPR_A2 6 +#define GPR_A3 7 +#define GPR_A4 8 /* arg reg 64 bit; caller saved in 32 bit */ +#define GPR_TA0 8 +#define GPR_A5 9 +#define GPR_TA1 9 +#define GPR_A6 10 +#define GPR_TA2 10 +#define GPR_A7 11 +#define GPR_TA3 11 +#define GPR_T0 12 /* caller saved */ +#define GPR_T1 13 +#define GPR_T2 14 +#define GPR_T3 15 +#define GPR_S0 16 /* callee saved */ +#define GPR_S1 17 +#define GPR_S2 18 +#define GPR_S3 19 +#define GPR_S4 20 +#define GPR_S5 21 +#define GPR_S6 22 +#define GPR_S7 23 +#define GPR_T8 24 /* caller saved */ +#define GPR_T9 25 /* callee address for PIC/temp */ +#define GPR_JP 25 /* PIC jump register */ +#define GPR_K0 26 /* kernel temporary */ +#define GPR_K1 27 +#define GPR_GP 28 /* global pointer - caller saved for PIC */ +#define GPR_SP 29 /* stack pointer */ +#define GPR_FP 30 /* frame pointer */ +#define GPR_S8 30 /* callee saved */ +#define GPR_RA 31 /* return address */ + +#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */ + #ifdef __ASSEMBLY__ #if _MIPS_SIM == _MIPS_SIM_ABI32 From c2fb9fe40b97867b675edfb595aa3d5281f71bdb Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:50 +0000 Subject: [PATCH 368/814] MIPS: traps: Use GPR number macros Use GPR number macros in uasm code generation parts to reduce code duplication. No functional change. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/traps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a1c1cb5de913..2d95e9971a2d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -2041,13 +2042,12 @@ void __init *set_except_vector(int n, void *addr) unsigned long jump_mask = ~((1 << 28) - 1); #endif u32 *buf = (u32 *)(ebase + 0x200); - unsigned int k0 = 26; if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) { uasm_i_j(&buf, handler & ~jump_mask); uasm_i_nop(&buf); } else { - UASM_i_LA(&buf, k0, handler); - uasm_i_jr(&buf, k0); + UASM_i_LA(&buf, GPR_K0, handler); + uasm_i_jr(&buf, GPR_K0); uasm_i_nop(&buf); } local_flush_icache_range(ebase + 0x200, (unsigned long)buf); From 6aec8e0502febd5eab4d257e9afacfa86ccd3374 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:51 +0000 Subject: [PATCH 369/814] MIPS: page: Use GPR number macros Use GPR number macros in uasm code generation parts to reduce code duplication. No functional change. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/mm/page.c | 202 +++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 107 deletions(-) diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index d3b4459d0fe8..1df237bd4a72 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef CONFIG_SIBYTE_DMA_PAGEOPS @@ -34,19 +35,6 @@ #include -/* Registers used in the assembled routines. */ -#define ZERO 0 -#define AT 2 -#define A0 4 -#define A1 5 -#define A2 6 -#define T0 8 -#define T1 9 -#define T2 10 -#define T3 11 -#define T9 25 -#define RA 31 - /* Handle labels (which must be positive integers). */ enum label_id { label_clear_nopref = 1, @@ -106,16 +94,16 @@ pg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off) IS_ENABLED(CONFIG_CPU_DADDI_WORKAROUNDS) && r4k_daddiu_bug()) { if (off > 0x7fff) { - uasm_i_lui(buf, T9, uasm_rel_hi(off)); - uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); + uasm_i_lui(buf, GPR_T9, uasm_rel_hi(off)); + uasm_i_addiu(buf, GPR_T9, GPR_T9, uasm_rel_lo(off)); } else - uasm_i_addiu(buf, T9, ZERO, off); - uasm_i_daddu(buf, reg1, reg2, T9); + uasm_i_addiu(buf, GPR_T9, GPR_ZERO, off); + uasm_i_daddu(buf, reg1, reg2, GPR_T9); } else { if (off > 0x7fff) { - uasm_i_lui(buf, T9, uasm_rel_hi(off)); - uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); - UASM_i_ADDU(buf, reg1, reg2, T9); + uasm_i_lui(buf, GPR_T9, uasm_rel_hi(off)); + uasm_i_addiu(buf, GPR_T9, GPR_T9, uasm_rel_lo(off)); + UASM_i_ADDU(buf, reg1, reg2, GPR_T9); } else UASM_i_ADDIU(buf, reg1, reg2, off); } @@ -233,9 +221,9 @@ static void set_prefetch_parameters(void) static void build_clear_store(u32 **buf, int off) { if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) { - uasm_i_sd(buf, ZERO, off, A0); + uasm_i_sd(buf, GPR_ZERO, off, GPR_A0); } else { - uasm_i_sw(buf, ZERO, off, A0); + uasm_i_sw(buf, GPR_ZERO, off, GPR_A0); } } @@ -246,10 +234,10 @@ static inline void build_clear_pref(u32 **buf, int off) if (pref_bias_clear_store) { _uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, - A0); + GPR_A0); } else if (cache_line_size == (half_clear_loop_size << 1)) { if (cpu_has_cache_cdex_s) { - uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); + uasm_i_cache(buf, Create_Dirty_Excl_SD, off, GPR_A0); } else if (cpu_has_cache_cdex_p) { if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) && cpu_is_r4600_v1_x()) { @@ -261,9 +249,9 @@ static inline void build_clear_pref(u32 **buf, int off) if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) - uasm_i_lw(buf, ZERO, ZERO, AT); + uasm_i_lw(buf, GPR_ZERO, GPR_ZERO, GPR_AT); - uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); + uasm_i_cache(buf, Create_Dirty_Excl_D, off, GPR_A0); } } } @@ -301,12 +289,12 @@ void build_clear_page(void) off = PAGE_SIZE - pref_bias_clear_store; if (off > 0xffff || !pref_bias_clear_store) - pg_addiu(&buf, A2, A0, off); + pg_addiu(&buf, GPR_A2, GPR_A0, off); else - uasm_i_ori(&buf, A2, A0, off); + uasm_i_ori(&buf, GPR_A2, GPR_A0, off); if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) - uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000)); + uasm_i_lui(&buf, GPR_AT, uasm_rel_hi(0xa0000000)); off = cache_line_size ? min(8, pref_bias_clear_store / cache_line_size) * cache_line_size : 0; @@ -320,36 +308,36 @@ void build_clear_page(void) build_clear_store(&buf, off); off += clear_word_size; } while (off < half_clear_loop_size); - pg_addiu(&buf, A0, A0, 2 * off); + pg_addiu(&buf, GPR_A0, GPR_A0, 2 * off); off = -off; do { build_clear_pref(&buf, off); if (off == -clear_word_size) - uasm_il_bne(&buf, &r, A0, A2, label_clear_pref); + uasm_il_bne(&buf, &r, GPR_A0, GPR_A2, label_clear_pref); build_clear_store(&buf, off); off += clear_word_size; } while (off < 0); if (pref_bias_clear_store) { - pg_addiu(&buf, A2, A0, pref_bias_clear_store); + pg_addiu(&buf, GPR_A2, GPR_A0, pref_bias_clear_store); uasm_l_clear_nopref(&l, buf); off = 0; do { build_clear_store(&buf, off); off += clear_word_size; } while (off < half_clear_loop_size); - pg_addiu(&buf, A0, A0, 2 * off); + pg_addiu(&buf, GPR_A0, GPR_A0, 2 * off); off = -off; do { if (off == -clear_word_size) - uasm_il_bne(&buf, &r, A0, A2, + uasm_il_bne(&buf, &r, GPR_A0, GPR_A2, label_clear_nopref); build_clear_store(&buf, off); off += clear_word_size; } while (off < 0); } - uasm_i_jr(&buf, RA); + uasm_i_jr(&buf, GPR_RA); uasm_i_nop(&buf); BUG_ON(buf > &__clear_page_end); @@ -369,18 +357,18 @@ void build_clear_page(void) static void build_copy_load(u32 **buf, int reg, int off) { if (cpu_has_64bit_gp_regs) { - uasm_i_ld(buf, reg, off, A1); + uasm_i_ld(buf, reg, off, GPR_A1); } else { - uasm_i_lw(buf, reg, off, A1); + uasm_i_lw(buf, reg, off, GPR_A1); } } static void build_copy_store(u32 **buf, int reg, int off) { if (cpu_has_64bit_gp_regs) { - uasm_i_sd(buf, reg, off, A0); + uasm_i_sd(buf, reg, off, GPR_A0); } else { - uasm_i_sw(buf, reg, off, A0); + uasm_i_sw(buf, reg, off, GPR_A0); } } @@ -390,7 +378,7 @@ static inline void build_copy_load_pref(u32 **buf, int off) return; if (pref_bias_copy_load) - _uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); + _uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, GPR_A1); } static inline void build_copy_store_pref(u32 **buf, int off) @@ -400,10 +388,10 @@ static inline void build_copy_store_pref(u32 **buf, int off) if (pref_bias_copy_store) { _uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, - A0); + GPR_A0); } else if (cache_line_size == (half_copy_loop_size << 1)) { if (cpu_has_cache_cdex_s) { - uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); + uasm_i_cache(buf, Create_Dirty_Excl_SD, off, GPR_A0); } else if (cpu_has_cache_cdex_p) { if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) && cpu_is_r4600_v1_x()) { @@ -415,9 +403,9 @@ static inline void build_copy_store_pref(u32 **buf, int off) if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) - uasm_i_lw(buf, ZERO, ZERO, AT); + uasm_i_lw(buf, GPR_ZERO, GPR_ZERO, GPR_AT); - uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); + uasm_i_cache(buf, Create_Dirty_Excl_D, off, GPR_A0); } } } @@ -454,12 +442,12 @@ void build_copy_page(void) off = PAGE_SIZE - pref_bias_copy_load; if (off > 0xffff || !pref_bias_copy_load) - pg_addiu(&buf, A2, A0, off); + pg_addiu(&buf, GPR_A2, GPR_A0, off); else - uasm_i_ori(&buf, A2, A0, off); + uasm_i_ori(&buf, GPR_A2, GPR_A0, off); if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) - uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000)); + uasm_i_lui(&buf, GPR_AT, uasm_rel_hi(0xa0000000)); off = cache_line_size ? min(8, pref_bias_copy_load / cache_line_size) * cache_line_size : 0; @@ -476,126 +464,126 @@ void build_copy_page(void) uasm_l_copy_pref_both(&l, buf); do { build_copy_load_pref(&buf, off); - build_copy_load(&buf, T0, off); + build_copy_load(&buf, GPR_T0, off); build_copy_load_pref(&buf, off + copy_word_size); - build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, GPR_T1, off + copy_word_size); build_copy_load_pref(&buf, off + 2 * copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_load_pref(&buf, off + 3 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); build_copy_store_pref(&buf, off); - build_copy_store(&buf, T0, off); + build_copy_store(&buf, GPR_T0, off); build_copy_store_pref(&buf, off + copy_word_size); - build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, GPR_T1, off + copy_word_size); build_copy_store_pref(&buf, off + 2 * copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_store_pref(&buf, off + 3 * copy_word_size); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < half_copy_loop_size); - pg_addiu(&buf, A1, A1, 2 * off); - pg_addiu(&buf, A0, A0, 2 * off); + pg_addiu(&buf, GPR_A1, GPR_A1, 2 * off); + pg_addiu(&buf, GPR_A0, GPR_A0, 2 * off); off = -off; do { build_copy_load_pref(&buf, off); - build_copy_load(&buf, T0, off); + build_copy_load(&buf, GPR_T0, off); build_copy_load_pref(&buf, off + copy_word_size); - build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, GPR_T1, off + copy_word_size); build_copy_load_pref(&buf, off + 2 * copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_load_pref(&buf, off + 3 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); build_copy_store_pref(&buf, off); - build_copy_store(&buf, T0, off); + build_copy_store(&buf, GPR_T0, off); build_copy_store_pref(&buf, off + copy_word_size); - build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, GPR_T1, off + copy_word_size); build_copy_store_pref(&buf, off + 2 * copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_store_pref(&buf, off + 3 * copy_word_size); if (off == -(4 * copy_word_size)) - uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + uasm_il_bne(&buf, &r, GPR_A2, GPR_A0, label_copy_pref_both); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < 0); if (pref_bias_copy_load - pref_bias_copy_store) { - pg_addiu(&buf, A2, A0, + pg_addiu(&buf, GPR_A2, GPR_A0, pref_bias_copy_load - pref_bias_copy_store); uasm_l_copy_pref_store(&l, buf); off = 0; do { - build_copy_load(&buf, T0, off); - build_copy_load(&buf, T1, off + copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_load(&buf, GPR_T0, off); + build_copy_load(&buf, GPR_T1, off + copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); build_copy_store_pref(&buf, off); - build_copy_store(&buf, T0, off); + build_copy_store(&buf, GPR_T0, off); build_copy_store_pref(&buf, off + copy_word_size); - build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, GPR_T1, off + copy_word_size); build_copy_store_pref(&buf, off + 2 * copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_store_pref(&buf, off + 3 * copy_word_size); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < half_copy_loop_size); - pg_addiu(&buf, A1, A1, 2 * off); - pg_addiu(&buf, A0, A0, 2 * off); + pg_addiu(&buf, GPR_A1, GPR_A1, 2 * off); + pg_addiu(&buf, GPR_A0, GPR_A0, 2 * off); off = -off; do { - build_copy_load(&buf, T0, off); - build_copy_load(&buf, T1, off + copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_load(&buf, GPR_T0, off); + build_copy_load(&buf, GPR_T1, off + copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); build_copy_store_pref(&buf, off); - build_copy_store(&buf, T0, off); + build_copy_store(&buf, GPR_T0, off); build_copy_store_pref(&buf, off + copy_word_size); - build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, GPR_T1, off + copy_word_size); build_copy_store_pref(&buf, off + 2 * copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); build_copy_store_pref(&buf, off + 3 * copy_word_size); if (off == -(4 * copy_word_size)) - uasm_il_bne(&buf, &r, A2, A0, + uasm_il_bne(&buf, &r, GPR_A2, GPR_A0, label_copy_pref_store); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < 0); } if (pref_bias_copy_store) { - pg_addiu(&buf, A2, A0, pref_bias_copy_store); + pg_addiu(&buf, GPR_A2, GPR_A0, pref_bias_copy_store); uasm_l_copy_nopref(&l, buf); off = 0; do { - build_copy_load(&buf, T0, off); - build_copy_load(&buf, T1, off + copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); - build_copy_store(&buf, T0, off); - build_copy_store(&buf, T1, off + copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + build_copy_load(&buf, GPR_T0, off); + build_copy_load(&buf, GPR_T1, off + copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T0, off); + build_copy_store(&buf, GPR_T1, off + copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < half_copy_loop_size); - pg_addiu(&buf, A1, A1, 2 * off); - pg_addiu(&buf, A0, A0, 2 * off); + pg_addiu(&buf, GPR_A1, GPR_A1, 2 * off); + pg_addiu(&buf, GPR_A0, GPR_A0, 2 * off); off = -off; do { - build_copy_load(&buf, T0, off); - build_copy_load(&buf, T1, off + copy_word_size); - build_copy_load(&buf, T2, off + 2 * copy_word_size); - build_copy_load(&buf, T3, off + 3 * copy_word_size); - build_copy_store(&buf, T0, off); - build_copy_store(&buf, T1, off + copy_word_size); - build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T0, off); + build_copy_load(&buf, GPR_T1, off + copy_word_size); + build_copy_load(&buf, GPR_T2, off + 2 * copy_word_size); + build_copy_load(&buf, GPR_T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T0, off); + build_copy_store(&buf, GPR_T1, off + copy_word_size); + build_copy_store(&buf, GPR_T2, off + 2 * copy_word_size); if (off == -(4 * copy_word_size)) - uasm_il_bne(&buf, &r, A2, A0, + uasm_il_bne(&buf, &r, GPR_A2, GPR_A0, label_copy_nopref); - build_copy_store(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, GPR_T3, off + 3 * copy_word_size); off += 4 * copy_word_size; } while (off < 0); } - uasm_i_jr(&buf, RA); + uasm_i_jr(&buf, GPR_RA); uasm_i_nop(&buf); BUG_ON(buf > &__copy_page_end); From 8cc461b85feb5444a78ecbd0d81a70ebfb507574 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:52 +0000 Subject: [PATCH 370/814] MIPS: tlbex: Use GPR number macros Use GPR number macros in uasm code generation parts to reduce code duplication. No functional change. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/mm/tlbex.c | 196 +++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 99 deletions(-) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index c9d00d9cb3c8..69ea54bdc0c3 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -277,10 +278,6 @@ static inline void dump_handler(const char *symbol, const void *start, const voi pr_debug("\tEND(%s)\n", symbol); } -/* The only general purpose registers allowed in TLB handlers. */ -#define K0 26 -#define K1 27 - #ifdef CONFIG_64BIT # define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_XCONTEXT) #else @@ -340,30 +337,30 @@ static struct work_registers build_get_work_registers(u32 **p) if (scratch_reg >= 0) { /* Save in CPU local C0_KScratch? */ UASM_i_MTC0(p, 1, c0_kscratch(), scratch_reg); - r.r1 = K0; - r.r2 = K1; - r.r3 = 1; + r.r1 = GPR_K0; + r.r2 = GPR_K1; + r.r3 = GPR_AT; return r; } if (num_possible_cpus() > 1) { /* Get smp_processor_id */ - UASM_i_CPUID_MFC0(p, K0, SMP_CPUID_REG); - UASM_i_SRL_SAFE(p, K0, K0, SMP_CPUID_REGSHIFT); + UASM_i_CPUID_MFC0(p, GPR_K0, SMP_CPUID_REG); + UASM_i_SRL_SAFE(p, GPR_K0, GPR_K0, SMP_CPUID_REGSHIFT); - /* handler_reg_save index in K0 */ - UASM_i_SLL(p, K0, K0, ilog2(sizeof(struct tlb_reg_save))); + /* handler_reg_save index in GPR_K0 */ + UASM_i_SLL(p, GPR_K0, GPR_K0, ilog2(sizeof(struct tlb_reg_save))); - UASM_i_LA(p, K1, (long)&handler_reg_save); - UASM_i_ADDU(p, K0, K0, K1); + UASM_i_LA(p, GPR_K1, (long)&handler_reg_save); + UASM_i_ADDU(p, GPR_K0, GPR_K0, GPR_K1); } else { - UASM_i_LA(p, K0, (long)&handler_reg_save); + UASM_i_LA(p, GPR_K0, (long)&handler_reg_save); } - /* K0 now points to save area, save $1 and $2 */ - UASM_i_SW(p, 1, offsetof(struct tlb_reg_save, a), K0); - UASM_i_SW(p, 2, offsetof(struct tlb_reg_save, b), K0); + /* GPR_K0 now points to save area, save $1 and $2 */ + UASM_i_SW(p, 1, offsetof(struct tlb_reg_save, a), GPR_K0); + UASM_i_SW(p, 2, offsetof(struct tlb_reg_save, b), GPR_K0); - r.r1 = K1; + r.r1 = GPR_K1; r.r2 = 1; r.r3 = 2; return r; @@ -376,9 +373,9 @@ static void build_restore_work_registers(u32 **p) UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg); return; } - /* K0 already points to save area, restore $1 and $2 */ - UASM_i_LW(p, 1, offsetof(struct tlb_reg_save, a), K0); - UASM_i_LW(p, 2, offsetof(struct tlb_reg_save, b), K0); + /* GPR_K0 already points to save area, restore $1 and $2 */ + UASM_i_LW(p, 1, offsetof(struct tlb_reg_save, a), GPR_K0); + UASM_i_LW(p, 2, offsetof(struct tlb_reg_save, b), GPR_K0); } #ifndef CONFIG_MIPS_PGD_C0_CONTEXT @@ -397,22 +394,22 @@ static void build_r3000_tlb_refill_handler(void) memset(tlb_handler, 0, sizeof(tlb_handler)); p = tlb_handler; - uasm_i_mfc0(&p, K0, C0_BADVADDR); - uasm_i_lui(&p, K1, uasm_rel_hi(pgdc)); /* cp0 delay */ - uasm_i_lw(&p, K1, uasm_rel_lo(pgdc), K1); - uasm_i_srl(&p, K0, K0, 22); /* load delay */ - uasm_i_sll(&p, K0, K0, 2); - uasm_i_addu(&p, K1, K1, K0); - uasm_i_mfc0(&p, K0, C0_CONTEXT); - uasm_i_lw(&p, K1, 0, K1); /* cp0 delay */ - uasm_i_andi(&p, K0, K0, 0xffc); /* load delay */ - uasm_i_addu(&p, K1, K1, K0); - uasm_i_lw(&p, K0, 0, K1); + uasm_i_mfc0(&p, GPR_K0, C0_BADVADDR); + uasm_i_lui(&p, GPR_K1, uasm_rel_hi(pgdc)); /* cp0 delay */ + uasm_i_lw(&p, GPR_K1, uasm_rel_lo(pgdc), GPR_K1); + uasm_i_srl(&p, GPR_K0, GPR_K0, 22); /* load delay */ + uasm_i_sll(&p, GPR_K0, GPR_K0, 2); + uasm_i_addu(&p, GPR_K1, GPR_K1, GPR_K0); + uasm_i_mfc0(&p, GPR_K0, C0_CONTEXT); + uasm_i_lw(&p, GPR_K1, 0, GPR_K1); /* cp0 delay */ + uasm_i_andi(&p, GPR_K0, GPR_K0, 0xffc); /* load delay */ + uasm_i_addu(&p, GPR_K1, GPR_K1, GPR_K0); + uasm_i_lw(&p, GPR_K0, 0, GPR_K1); uasm_i_nop(&p); /* load delay */ - uasm_i_mtc0(&p, K0, C0_ENTRYLO0); - uasm_i_mfc0(&p, K1, C0_EPC); /* cp0 delay */ + uasm_i_mtc0(&p, GPR_K0, C0_ENTRYLO0); + uasm_i_mfc0(&p, GPR_K1, C0_EPC); /* cp0 delay */ uasm_i_tlbwr(&p); /* cp0 delay */ - uasm_i_jr(&p, K1); + uasm_i_jr(&p, GPR_K1); uasm_i_rfe(&p); /* branch delay */ if (p > tlb_handler + 32) @@ -1260,11 +1257,11 @@ static void build_r4000_tlb_refill_handler(void) memset(final_handler, 0, sizeof(final_handler)); if (IS_ENABLED(CONFIG_64BIT) && (scratch_reg >= 0 || scratchpad_available()) && use_bbit_insns()) { - htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, + htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, GPR_K0, GPR_K1, scratch_reg); vmalloc_mode = refill_scratch; } else { - htlb_info.huge_pte = K0; + htlb_info.huge_pte = GPR_K0; htlb_info.restore_scratch = 0; htlb_info.need_reload_pte = true; vmalloc_mode = refill_noscratch; @@ -1274,29 +1271,29 @@ static void build_r4000_tlb_refill_handler(void) if (bcm1250_m3_war()) { unsigned int segbits = 44; - uasm_i_dmfc0(&p, K0, C0_BADVADDR); - uasm_i_dmfc0(&p, K1, C0_ENTRYHI); - uasm_i_xor(&p, K0, K0, K1); - uasm_i_dsrl_safe(&p, K1, K0, 62); - uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); - uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); - uasm_i_or(&p, K0, K0, K1); - uasm_il_bnez(&p, &r, K0, label_leave); + uasm_i_dmfc0(&p, GPR_K0, C0_BADVADDR); + uasm_i_dmfc0(&p, GPR_K1, C0_ENTRYHI); + uasm_i_xor(&p, GPR_K0, GPR_K0, GPR_K1); + uasm_i_dsrl_safe(&p, GPR_K1, GPR_K0, 62); + uasm_i_dsrl_safe(&p, GPR_K0, GPR_K0, 12 + 1); + uasm_i_dsll_safe(&p, GPR_K0, GPR_K0, 64 + 12 + 1 - segbits); + uasm_i_or(&p, GPR_K0, GPR_K0, GPR_K1); + uasm_il_bnez(&p, &r, GPR_K0, label_leave); /* No need for uasm_i_nop */ } #ifdef CONFIG_64BIT - build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ + build_get_pmde64(&p, &l, &r, GPR_K0, GPR_K1); /* get pmd in GPR_K1 */ #else - build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ + build_get_pgde32(&p, GPR_K0, GPR_K1); /* get pgd in GPR_K1 */ #endif #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT - build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); + build_is_huge_pte(&p, &r, GPR_K0, GPR_K1, label_tlb_huge_update); #endif - build_get_ptep(&p, K0, K1); - build_update_entries(&p, K0, K1); + build_get_ptep(&p, GPR_K0, GPR_K1); + build_update_entries(&p, GPR_K0, GPR_K1); build_tlb_write_entry(&p, &l, &r, tlb_random); uasm_l_leave(&l, p); uasm_i_eret(&p); /* return from trap */ @@ -1304,14 +1301,14 @@ static void build_r4000_tlb_refill_handler(void) #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT uasm_l_tlb_huge_update(&l, p); if (htlb_info.need_reload_pte) - UASM_i_LW(&p, htlb_info.huge_pte, 0, K1); - build_huge_update_entries(&p, htlb_info.huge_pte, K1); - build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random, + UASM_i_LW(&p, htlb_info.huge_pte, 0, GPR_K1); + build_huge_update_entries(&p, htlb_info.huge_pte, GPR_K1); + build_huge_tlb_write_entry(&p, &l, &r, GPR_K0, tlb_random, htlb_info.restore_scratch); #endif #ifdef CONFIG_64BIT - build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, vmalloc_mode); + build_get_pgd_vmalloc64(&p, &l, &r, GPR_K0, GPR_K1, vmalloc_mode); #endif /* @@ -1484,34 +1481,35 @@ static void build_loongson3_tlb_refill_handler(void) memset(tlb_handler, 0, sizeof(tlb_handler)); if (check_for_high_segbits) { - uasm_i_dmfc0(&p, K0, C0_BADVADDR); - uasm_i_dsrl_safe(&p, K1, K0, PGDIR_SHIFT + PGD_TABLE_ORDER + PAGE_SHIFT - 3); - uasm_il_beqz(&p, &r, K1, label_vmalloc); + uasm_i_dmfc0(&p, GPR_K0, C0_BADVADDR); + uasm_i_dsrl_safe(&p, GPR_K1, GPR_K0, + PGDIR_SHIFT + PGD_TABLE_ORDER + PAGE_SHIFT - 3); + uasm_il_beqz(&p, &r, GPR_K1, label_vmalloc); uasm_i_nop(&p); - uasm_il_bgez(&p, &r, K0, label_large_segbits_fault); + uasm_il_bgez(&p, &r, GPR_K0, label_large_segbits_fault); uasm_i_nop(&p); uasm_l_vmalloc(&l, p); } - uasm_i_dmfc0(&p, K1, C0_PGD); + uasm_i_dmfc0(&p, GPR_K1, C0_PGD); - uasm_i_lddir(&p, K0, K1, 3); /* global page dir */ + uasm_i_lddir(&p, GPR_K0, GPR_K1, 3); /* global page dir */ #ifndef __PAGETABLE_PMD_FOLDED - uasm_i_lddir(&p, K1, K0, 1); /* middle page dir */ + uasm_i_lddir(&p, GPR_K1, GPR_K0, 1); /* middle page dir */ #endif - uasm_i_ldpte(&p, K1, 0); /* even */ - uasm_i_ldpte(&p, K1, 1); /* odd */ + uasm_i_ldpte(&p, GPR_K1, 0); /* even */ + uasm_i_ldpte(&p, GPR_K1, 1); /* odd */ uasm_i_tlbwr(&p); /* restore page mask */ if (PM_DEFAULT_MASK >> 16) { - uasm_i_lui(&p, K0, PM_DEFAULT_MASK >> 16); - uasm_i_ori(&p, K0, K0, PM_DEFAULT_MASK & 0xffff); - uasm_i_mtc0(&p, K0, C0_PAGEMASK); + uasm_i_lui(&p, GPR_K0, PM_DEFAULT_MASK >> 16); + uasm_i_ori(&p, GPR_K0, GPR_K0, PM_DEFAULT_MASK & 0xffff); + uasm_i_mtc0(&p, GPR_K0, C0_PAGEMASK); } else if (PM_DEFAULT_MASK) { - uasm_i_ori(&p, K0, 0, PM_DEFAULT_MASK); - uasm_i_mtc0(&p, K0, C0_PAGEMASK); + uasm_i_ori(&p, GPR_K0, 0, PM_DEFAULT_MASK); + uasm_i_mtc0(&p, GPR_K0, C0_PAGEMASK); } else { uasm_i_mtc0(&p, 0, C0_PAGEMASK); } @@ -1520,8 +1518,8 @@ static void build_loongson3_tlb_refill_handler(void) if (check_for_high_segbits) { uasm_l_large_segbits_fault(&l, p); - UASM_i_LA(&p, K1, (unsigned long)tlb_do_page_fault_0); - uasm_i_jr(&p, K1); + UASM_i_LA(&p, GPR_K1, (unsigned long)tlb_do_page_fault_0); + uasm_i_jr(&p, GPR_K1); uasm_i_nop(&p); } @@ -1887,11 +1885,11 @@ static void build_r3000_tlb_load_handler(void) memset(labels, 0, sizeof(labels)); memset(relocs, 0, sizeof(relocs)); - build_r3000_tlbchange_handler_head(&p, K0, K1); - build_pte_present(&p, &r, K0, K1, -1, label_nopage_tlbl); + build_r3000_tlbchange_handler_head(&p, GPR_K0, GPR_K1); + build_pte_present(&p, &r, GPR_K0, GPR_K1, -1, label_nopage_tlbl); uasm_i_nop(&p); /* load delay */ - build_make_valid(&p, &r, K0, K1, -1); - build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); + build_make_valid(&p, &r, GPR_K0, GPR_K1, -1); + build_r3000_tlb_reload_write(&p, &l, &r, GPR_K0, GPR_K1); uasm_l_nopage_tlbl(&l, p); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); @@ -1917,11 +1915,11 @@ static void build_r3000_tlb_store_handler(void) memset(labels, 0, sizeof(labels)); memset(relocs, 0, sizeof(relocs)); - build_r3000_tlbchange_handler_head(&p, K0, K1); - build_pte_writable(&p, &r, K0, K1, -1, label_nopage_tlbs); + build_r3000_tlbchange_handler_head(&p, GPR_K0, GPR_K1); + build_pte_writable(&p, &r, GPR_K0, GPR_K1, -1, label_nopage_tlbs); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1, -1); - build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); + build_make_write(&p, &r, GPR_K0, GPR_K1, -1); + build_r3000_tlb_reload_write(&p, &l, &r, GPR_K0, GPR_K1); uasm_l_nopage_tlbs(&l, p); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); @@ -1947,11 +1945,11 @@ static void build_r3000_tlb_modify_handler(void) memset(labels, 0, sizeof(labels)); memset(relocs, 0, sizeof(relocs)); - build_r3000_tlbchange_handler_head(&p, K0, K1); - build_pte_modifiable(&p, &r, K0, K1, -1, label_nopage_tlbm); + build_r3000_tlbchange_handler_head(&p, GPR_K0, GPR_K1); + build_pte_modifiable(&p, &r, GPR_K0, GPR_K1, -1, label_nopage_tlbm); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1, -1); - build_r3000_pte_reload_tlbwi(&p, K0, K1); + build_make_write(&p, &r, GPR_K0, GPR_K1, -1); + build_r3000_pte_reload_tlbwi(&p, GPR_K0, GPR_K1); uasm_l_nopage_tlbm(&l, p); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); @@ -2067,14 +2065,14 @@ static void build_r4000_tlb_load_handler(void) if (bcm1250_m3_war()) { unsigned int segbits = 44; - uasm_i_dmfc0(&p, K0, C0_BADVADDR); - uasm_i_dmfc0(&p, K1, C0_ENTRYHI); - uasm_i_xor(&p, K0, K0, K1); - uasm_i_dsrl_safe(&p, K1, K0, 62); - uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); - uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); - uasm_i_or(&p, K0, K0, K1); - uasm_il_bnez(&p, &r, K0, label_leave); + uasm_i_dmfc0(&p, GPR_K0, C0_BADVADDR); + uasm_i_dmfc0(&p, GPR_K1, C0_ENTRYHI); + uasm_i_xor(&p, GPR_K0, GPR_K0, GPR_K1); + uasm_i_dsrl_safe(&p, GPR_K1, GPR_K0, 62); + uasm_i_dsrl_safe(&p, GPR_K0, GPR_K0, 12 + 1); + uasm_i_dsll_safe(&p, GPR_K0, GPR_K0, 64 + 12 + 1 - segbits); + uasm_i_or(&p, GPR_K0, GPR_K0, GPR_K1); + uasm_il_bnez(&p, &r, GPR_K0, label_leave); /* No need for uasm_i_nop */ } @@ -2217,9 +2215,9 @@ static void build_r4000_tlb_load_handler(void) build_restore_work_registers(&p); #ifdef CONFIG_CPU_MICROMIPS if ((unsigned long)tlb_do_page_fault_0 & 1) { - uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_0)); - uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_0)); - uasm_i_jr(&p, K0); + uasm_i_lui(&p, GPR_K0, uasm_rel_hi((long)tlb_do_page_fault_0)); + uasm_i_addiu(&p, GPR_K0, GPR_K0, uasm_rel_lo((long)tlb_do_page_fault_0)); + uasm_i_jr(&p, GPR_K0); } else #endif uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); @@ -2273,9 +2271,9 @@ static void build_r4000_tlb_store_handler(void) build_restore_work_registers(&p); #ifdef CONFIG_CPU_MICROMIPS if ((unsigned long)tlb_do_page_fault_1 & 1) { - uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1)); - uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1)); - uasm_i_jr(&p, K0); + uasm_i_lui(&p, GPR_K0, uasm_rel_hi((long)tlb_do_page_fault_1)); + uasm_i_addiu(&p, GPR_K0, GPR_K0, uasm_rel_lo((long)tlb_do_page_fault_1)); + uasm_i_jr(&p, GPR_K0); } else #endif uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); @@ -2330,9 +2328,9 @@ static void build_r4000_tlb_modify_handler(void) build_restore_work_registers(&p); #ifdef CONFIG_CPU_MICROMIPS if ((unsigned long)tlb_do_page_fault_1 & 1) { - uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1)); - uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1)); - uasm_i_jr(&p, K0); + uasm_i_lui(&p, GPR_K0, uasm_rel_hi((long)tlb_do_page_fault_1)); + uasm_i_addiu(&p, GPR_K0, GPR_K0, uasm_rel_lo((long)tlb_do_page_fault_1)); + uasm_i_jr(&p, GPR_K0); } else #endif uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); From 881c8e055dc827861e44dcd04857b3f756a569f5 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:53 +0000 Subject: [PATCH 371/814] MIPS: kvm/entry: Use GPR number macros Use GPR number macros in uasm code generation parts to reduce code duplication. No functional change. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kvm/entry.c | 404 +++++++++++++++++++----------------------- 1 file changed, 187 insertions(+), 217 deletions(-) diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c index 96f64a95f51b..ac8e074c6bb7 100644 --- a/arch/mips/kvm/entry.c +++ b/arch/mips/kvm/entry.c @@ -16,41 +16,11 @@ #include #include #include +#include #include #include #include -/* Register names */ -#define ZERO 0 -#define AT 1 -#define V0 2 -#define V1 3 -#define A0 4 -#define A1 5 - -#if _MIPS_SIM == _MIPS_SIM_ABI32 -#define T0 8 -#define T1 9 -#define T2 10 -#define T3 11 -#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ - -#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 -#define T0 12 -#define T1 13 -#define T2 14 -#define T3 15 -#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */ - -#define S0 16 -#define S1 17 -#define T9 25 -#define K0 26 -#define K1 27 -#define GP 28 -#define SP 29 -#define RA 31 - #define CALLFRAME_SIZ 32 static unsigned int scratch_vcpu[2] = { C0_DDATALO }; @@ -189,60 +159,60 @@ void *kvm_mips_build_vcpu_run(void *addr) unsigned int i; /* - * A0: vcpu + * GPR_A0: vcpu */ /* k0/k1 not being used in host kernel context */ - UASM_i_ADDIU(&p, K1, SP, -(int)sizeof(struct pt_regs)); + UASM_i_ADDIU(&p, GPR_K1, GPR_SP, -(int)sizeof(struct pt_regs)); for (i = 16; i < 32; ++i) { if (i == 24) i = 28; - UASM_i_SW(&p, i, offsetof(struct pt_regs, regs[i]), K1); + UASM_i_SW(&p, i, offsetof(struct pt_regs, regs[i]), GPR_K1); } /* Save host status */ - uasm_i_mfc0(&p, V0, C0_STATUS); - UASM_i_SW(&p, V0, offsetof(struct pt_regs, cp0_status), K1); + uasm_i_mfc0(&p, GPR_V0, C0_STATUS); + UASM_i_SW(&p, GPR_V0, offsetof(struct pt_regs, cp0_status), GPR_K1); /* Save scratch registers, will be used to store pointer to vcpu etc */ - kvm_mips_build_save_scratch(&p, V1, K1); + kvm_mips_build_save_scratch(&p, GPR_V1, GPR_K1); /* VCPU scratch register has pointer to vcpu */ - UASM_i_MTC0(&p, A0, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_MTC0(&p, GPR_A0, scratch_vcpu[0], scratch_vcpu[1]); /* Offset into vcpu->arch */ - UASM_i_ADDIU(&p, K1, A0, offsetof(struct kvm_vcpu, arch)); + UASM_i_ADDIU(&p, GPR_K1, GPR_A0, offsetof(struct kvm_vcpu, arch)); /* * Save the host stack to VCPU, used for exception processing * when we exit from the Guest */ - UASM_i_SW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1); + UASM_i_SW(&p, GPR_SP, offsetof(struct kvm_vcpu_arch, host_stack), GPR_K1); /* Save the kernel gp as well */ - UASM_i_SW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1); + UASM_i_SW(&p, GPR_GP, offsetof(struct kvm_vcpu_arch, host_gp), GPR_K1); /* * Setup status register for running the guest in UM, interrupts * are disabled */ - UASM_i_LA(&p, K0, ST0_EXL | KSU_USER | ST0_BEV | ST0_KX_IF_64); - uasm_i_mtc0(&p, K0, C0_STATUS); + UASM_i_LA(&p, GPR_K0, ST0_EXL | KSU_USER | ST0_BEV | ST0_KX_IF_64); + uasm_i_mtc0(&p, GPR_K0, C0_STATUS); uasm_i_ehb(&p); /* load up the new EBASE */ - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1); - build_set_exc_base(&p, K0); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, guest_ebase), GPR_K1); + build_set_exc_base(&p, GPR_K0); /* * Now that the new EBASE has been loaded, unset BEV, set * interrupt mask as it was but make sure that timer interrupts * are enabled */ - uasm_i_addiu(&p, K0, ZERO, ST0_EXL | KSU_USER | ST0_IE | ST0_KX_IF_64); - uasm_i_andi(&p, V0, V0, ST0_IM); - uasm_i_or(&p, K0, K0, V0); - uasm_i_mtc0(&p, K0, C0_STATUS); + uasm_i_addiu(&p, GPR_K0, GPR_ZERO, ST0_EXL | KSU_USER | ST0_IE | ST0_KX_IF_64); + uasm_i_andi(&p, GPR_V0, GPR_V0, ST0_IM); + uasm_i_or(&p, GPR_K0, GPR_K0, GPR_V0); + uasm_i_mtc0(&p, GPR_K0, C0_STATUS); uasm_i_ehb(&p); p = kvm_mips_build_enter_guest(p); @@ -273,15 +243,15 @@ static void *kvm_mips_build_enter_guest(void *addr) memset(relocs, 0, sizeof(relocs)); /* Set Guest EPC */ - UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, pc), K1); - UASM_i_MTC0(&p, T0, C0_EPC); + UASM_i_LW(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, pc), GPR_K1); + UASM_i_MTC0(&p, GPR_T0, C0_EPC); /* Save normal linux process pgd (VZ guarantees pgd_reg is set) */ if (cpu_has_ldpte) - UASM_i_MFC0(&p, K0, C0_PWBASE); + UASM_i_MFC0(&p, GPR_K0, C0_PWBASE); else - UASM_i_MFC0(&p, K0, c0_kscratch(), pgd_reg); - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_pgd), K1); + UASM_i_MFC0(&p, GPR_K0, c0_kscratch(), pgd_reg); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, host_pgd), GPR_K1); /* * Set up KVM GPA pgd. @@ -289,24 +259,24 @@ static void *kvm_mips_build_enter_guest(void *addr) * - call tlbmiss_handler_setup_pgd(mm->pgd) * - write mm->pgd into CP0_PWBase * - * We keep S0 pointing at struct kvm so we can load the ASID below. + * We keep GPR_S0 pointing at struct kvm so we can load the ASID below. */ - UASM_i_LW(&p, S0, (int)offsetof(struct kvm_vcpu, kvm) - - (int)offsetof(struct kvm_vcpu, arch), K1); - UASM_i_LW(&p, A0, offsetof(struct kvm, arch.gpa_mm.pgd), S0); - UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd); - uasm_i_jalr(&p, RA, T9); + UASM_i_LW(&p, GPR_S0, (int)offsetof(struct kvm_vcpu, kvm) - + (int)offsetof(struct kvm_vcpu, arch), GPR_K1); + UASM_i_LW(&p, GPR_A0, offsetof(struct kvm, arch.gpa_mm.pgd), GPR_S0); + UASM_i_LA(&p, GPR_T9, (unsigned long)tlbmiss_handler_setup_pgd); + uasm_i_jalr(&p, GPR_RA, GPR_T9); /* delay slot */ if (cpu_has_htw) - UASM_i_MTC0(&p, A0, C0_PWBASE); + UASM_i_MTC0(&p, GPR_A0, C0_PWBASE); else uasm_i_nop(&p); /* Set GM bit to setup eret to VZ guest context */ - uasm_i_addiu(&p, V1, ZERO, 1); - uasm_i_mfc0(&p, K0, C0_GUESTCTL0); - uasm_i_ins(&p, K0, V1, MIPS_GCTL0_GM_SHIFT, 1); - uasm_i_mtc0(&p, K0, C0_GUESTCTL0); + uasm_i_addiu(&p, GPR_V1, GPR_ZERO, 1); + uasm_i_mfc0(&p, GPR_K0, C0_GUESTCTL0); + uasm_i_ins(&p, GPR_K0, GPR_V1, MIPS_GCTL0_GM_SHIFT, 1); + uasm_i_mtc0(&p, GPR_K0, C0_GUESTCTL0); if (cpu_has_guestid) { /* @@ -315,13 +285,13 @@ static void *kvm_mips_build_enter_guest(void *addr) */ /* Get current GuestID */ - uasm_i_mfc0(&p, T0, C0_GUESTCTL1); + uasm_i_mfc0(&p, GPR_T0, C0_GUESTCTL1); /* Set GuestCtl1.RID = GuestCtl1.ID */ - uasm_i_ext(&p, T1, T0, MIPS_GCTL1_ID_SHIFT, + uasm_i_ext(&p, GPR_T1, GPR_T0, MIPS_GCTL1_ID_SHIFT, MIPS_GCTL1_ID_WIDTH); - uasm_i_ins(&p, T0, T1, MIPS_GCTL1_RID_SHIFT, + uasm_i_ins(&p, GPR_T0, GPR_T1, MIPS_GCTL1_RID_SHIFT, MIPS_GCTL1_RID_WIDTH); - uasm_i_mtc0(&p, T0, C0_GUESTCTL1); + uasm_i_mtc0(&p, GPR_T0, C0_GUESTCTL1); /* GuestID handles dealiasing so we don't need to touch ASID */ goto skip_asid_restore; @@ -330,65 +300,65 @@ static void *kvm_mips_build_enter_guest(void *addr) /* Root ASID Dealias (RAD) */ /* Save host ASID */ - UASM_i_MFC0(&p, K0, C0_ENTRYHI); - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_entryhi), - K1); + UASM_i_MFC0(&p, GPR_K0, C0_ENTRYHI); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, host_entryhi), + GPR_K1); /* Set the root ASID for the Guest */ - UASM_i_ADDIU(&p, T1, S0, + UASM_i_ADDIU(&p, GPR_T1, GPR_S0, offsetof(struct kvm, arch.gpa_mm.context.asid)); /* t1: contains the base of the ASID array, need to get the cpu id */ /* smp_processor_id */ - uasm_i_lw(&p, T2, offsetof(struct thread_info, cpu), GP); + uasm_i_lw(&p, GPR_T2, offsetof(struct thread_info, cpu), GPR_GP); /* index the ASID array */ - uasm_i_sll(&p, T2, T2, ilog2(sizeof(long))); - UASM_i_ADDU(&p, T3, T1, T2); - UASM_i_LW(&p, K0, 0, T3); + uasm_i_sll(&p, GPR_T2, GPR_T2, ilog2(sizeof(long))); + UASM_i_ADDU(&p, GPR_T3, GPR_T1, GPR_T2); + UASM_i_LW(&p, GPR_K0, 0, GPR_T3); #ifdef CONFIG_MIPS_ASID_BITS_VARIABLE /* * reuse ASID array offset * cpuinfo_mips is a multiple of sizeof(long) */ - uasm_i_addiu(&p, T3, ZERO, sizeof(struct cpuinfo_mips)/sizeof(long)); - uasm_i_mul(&p, T2, T2, T3); + uasm_i_addiu(&p, GPR_T3, GPR_ZERO, sizeof(struct cpuinfo_mips)/sizeof(long)); + uasm_i_mul(&p, GPR_T2, GPR_T2, GPR_T3); - UASM_i_LA_mostly(&p, AT, (long)&cpu_data[0].asid_mask); - UASM_i_ADDU(&p, AT, AT, T2); - UASM_i_LW(&p, T2, uasm_rel_lo((long)&cpu_data[0].asid_mask), AT); - uasm_i_and(&p, K0, K0, T2); + UASM_i_LA_mostly(&p, GPR_AT, (long)&cpu_data[0].asid_mask); + UASM_i_ADDU(&p, GPR_AT, GPR_AT, GPR_T2); + UASM_i_LW(&p, GPR_T2, uasm_rel_lo((long)&cpu_data[0].asid_mask), GPR_AT); + uasm_i_and(&p, GPR_K0, GPR_K0, GPR_T2); #else - uasm_i_andi(&p, K0, K0, MIPS_ENTRYHI_ASID); + uasm_i_andi(&p, GPR_K0, GPR_K0, MIPS_ENTRYHI_ASID); #endif /* Set up KVM VZ root ASID (!guestid) */ - uasm_i_mtc0(&p, K0, C0_ENTRYHI); + uasm_i_mtc0(&p, GPR_K0, C0_ENTRYHI); skip_asid_restore: uasm_i_ehb(&p); /* Disable RDHWR access */ - uasm_i_mtc0(&p, ZERO, C0_HWRENA); + uasm_i_mtc0(&p, GPR_ZERO, C0_HWRENA); /* load the guest context from VCPU and return */ for (i = 1; i < 32; ++i) { /* Guest k0/k1 loaded later */ - if (i == K0 || i == K1) + if (i == GPR_K0 || i == GPR_K1) continue; - UASM_i_LW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1); + UASM_i_LW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), GPR_K1); } #ifndef CONFIG_CPU_MIPSR6 /* Restore hi/lo */ - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, hi), K1); - uasm_i_mthi(&p, K0); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, hi), GPR_K1); + uasm_i_mthi(&p, GPR_K0); - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, lo), K1); - uasm_i_mtlo(&p, K0); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, lo), GPR_K1); + uasm_i_mtlo(&p, GPR_K0); #endif /* Restore the guest's k0/k1 registers */ - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1); - UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, gprs[GPR_K0]), GPR_K1); + UASM_i_LW(&p, GPR_K1, offsetof(struct kvm_vcpu_arch, gprs[GPR_K1]), GPR_K1); /* Jump to guest */ uasm_i_eret(&p); @@ -421,13 +391,13 @@ void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler) memset(relocs, 0, sizeof(relocs)); /* Save guest k1 into scratch register */ - UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]); + UASM_i_MTC0(&p, GPR_K1, scratch_tmp[0], scratch_tmp[1]); /* Get the VCPU pointer from the VCPU scratch register */ - UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_MFC0(&p, GPR_K1, scratch_vcpu[0], scratch_vcpu[1]); /* Save guest k0 into VCPU structure */ - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu, arch.gprs[GPR_K0]), GPR_K1); /* * Some of the common tlbex code uses current_cpu_type(). For KVM we @@ -436,13 +406,13 @@ void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler) preempt_disable(); #ifdef CONFIG_CPU_LOONGSON64 - UASM_i_MFC0(&p, K1, C0_PGD); - uasm_i_lddir(&p, K0, K1, 3); /* global page dir */ + UASM_i_MFC0(&p, GPR_K1, C0_PGD); + uasm_i_lddir(&p, GPR_K0, GPR_K1, 3); /* global page dir */ #ifndef __PAGETABLE_PMD_FOLDED - uasm_i_lddir(&p, K1, K0, 1); /* middle page dir */ + uasm_i_lddir(&p, GPR_K1, GPR_K0, 1); /* middle page dir */ #endif - uasm_i_ldpte(&p, K1, 0); /* even */ - uasm_i_ldpte(&p, K1, 1); /* odd */ + uasm_i_ldpte(&p, GPR_K1, 0); /* even */ + uasm_i_ldpte(&p, GPR_K1, 1); /* odd */ uasm_i_tlbwr(&p); #else /* @@ -457,27 +427,27 @@ void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler) */ #ifdef CONFIG_64BIT - build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ + build_get_pmde64(&p, &l, &r, GPR_K0, GPR_K1); /* get pmd in GPR_K1 */ #else - build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ + build_get_pgde32(&p, GPR_K0, GPR_K1); /* get pgd in GPR_K1 */ #endif /* we don't support huge pages yet */ - build_get_ptep(&p, K0, K1); - build_update_entries(&p, K0, K1); + build_get_ptep(&p, GPR_K0, GPR_K1); + build_update_entries(&p, GPR_K0, GPR_K1); build_tlb_write_entry(&p, &l, &r, tlb_random); #endif preempt_enable(); /* Get the VCPU pointer from the VCPU scratch register again */ - UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_MFC0(&p, GPR_K1, scratch_vcpu[0], scratch_vcpu[1]); /* Restore the guest's k0/k1 registers */ - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu, arch.gprs[GPR_K0]), GPR_K1); uasm_i_ehb(&p); - UASM_i_MFC0(&p, K1, scratch_tmp[0], scratch_tmp[1]); + UASM_i_MFC0(&p, GPR_K1, scratch_tmp[0], scratch_tmp[1]); /* Jump to guest */ uasm_i_eret(&p); @@ -507,14 +477,14 @@ void *kvm_mips_build_exception(void *addr, void *handler) memset(relocs, 0, sizeof(relocs)); /* Save guest k1 into scratch register */ - UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]); + UASM_i_MTC0(&p, GPR_K1, scratch_tmp[0], scratch_tmp[1]); /* Get the VCPU pointer from the VCPU scratch register */ - UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]); - UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch)); + UASM_i_MFC0(&p, GPR_K1, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_ADDIU(&p, GPR_K1, GPR_K1, offsetof(struct kvm_vcpu, arch)); /* Save guest k0 into VCPU structure */ - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, gprs[GPR_K0]), GPR_K1); /* Branch to the common handler */ uasm_il_b(&p, &r, label_exit_common); @@ -562,85 +532,85 @@ void *kvm_mips_build_exit(void *addr) /* Start saving Guest context to VCPU */ for (i = 0; i < 32; ++i) { /* Guest k0/k1 saved later */ - if (i == K0 || i == K1) + if (i == GPR_K0 || i == GPR_K1) continue; - UASM_i_SW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1); + UASM_i_SW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), GPR_K1); } #ifndef CONFIG_CPU_MIPSR6 /* We need to save hi/lo and restore them on the way out */ - uasm_i_mfhi(&p, T0); - UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, hi), K1); + uasm_i_mfhi(&p, GPR_T0); + UASM_i_SW(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, hi), GPR_K1); - uasm_i_mflo(&p, T0); - UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1); + uasm_i_mflo(&p, GPR_T0); + UASM_i_SW(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, lo), GPR_K1); #endif /* Finally save guest k1 to VCPU */ uasm_i_ehb(&p); - UASM_i_MFC0(&p, T0, scratch_tmp[0], scratch_tmp[1]); - UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1); + UASM_i_MFC0(&p, GPR_T0, scratch_tmp[0], scratch_tmp[1]); + UASM_i_SW(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, gprs[GPR_K1]), GPR_K1); /* Now that context has been saved, we can use other registers */ /* Restore vcpu */ - UASM_i_MFC0(&p, S0, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_MFC0(&p, GPR_S0, scratch_vcpu[0], scratch_vcpu[1]); /* * Save Host level EPC, BadVaddr and Cause to VCPU, useful to process * the exception */ - UASM_i_MFC0(&p, K0, C0_EPC); - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, pc), K1); + UASM_i_MFC0(&p, GPR_K0, C0_EPC); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, pc), GPR_K1); - UASM_i_MFC0(&p, K0, C0_BADVADDR); - UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_badvaddr), - K1); + UASM_i_MFC0(&p, GPR_K0, C0_BADVADDR); + UASM_i_SW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, host_cp0_badvaddr), + GPR_K1); - uasm_i_mfc0(&p, K0, C0_CAUSE); - uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), K1); + uasm_i_mfc0(&p, GPR_K0, C0_CAUSE); + uasm_i_sw(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), GPR_K1); if (cpu_has_badinstr) { - uasm_i_mfc0(&p, K0, C0_BADINSTR); - uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, - host_cp0_badinstr), K1); + uasm_i_mfc0(&p, GPR_K0, C0_BADINSTR); + uasm_i_sw(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, + host_cp0_badinstr), GPR_K1); } if (cpu_has_badinstrp) { - uasm_i_mfc0(&p, K0, C0_BADINSTRP); - uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, - host_cp0_badinstrp), K1); + uasm_i_mfc0(&p, GPR_K0, C0_BADINSTRP); + uasm_i_sw(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, + host_cp0_badinstrp), GPR_K1); } /* Now restore the host state just enough to run the handlers */ /* Switch EBASE to the one used by Linux */ /* load up the host EBASE */ - uasm_i_mfc0(&p, V0, C0_STATUS); + uasm_i_mfc0(&p, GPR_V0, C0_STATUS); - uasm_i_lui(&p, AT, ST0_BEV >> 16); - uasm_i_or(&p, K0, V0, AT); + uasm_i_lui(&p, GPR_AT, ST0_BEV >> 16); + uasm_i_or(&p, GPR_K0, GPR_V0, GPR_AT); - uasm_i_mtc0(&p, K0, C0_STATUS); + uasm_i_mtc0(&p, GPR_K0, C0_STATUS); uasm_i_ehb(&p); - UASM_i_LA_mostly(&p, K0, (long)&ebase); - UASM_i_LW(&p, K0, uasm_rel_lo((long)&ebase), K0); - build_set_exc_base(&p, K0); + UASM_i_LA_mostly(&p, GPR_K0, (long)&ebase); + UASM_i_LW(&p, GPR_K0, uasm_rel_lo((long)&ebase), GPR_K0); + build_set_exc_base(&p, GPR_K0); if (raw_cpu_has_fpu) { /* * If FPU is enabled, save FCR31 and clear it so that later * ctc1's don't trigger FPE for pending exceptions. */ - uasm_i_lui(&p, AT, ST0_CU1 >> 16); - uasm_i_and(&p, V1, V0, AT); - uasm_il_beqz(&p, &r, V1, label_fpu_1); + uasm_i_lui(&p, GPR_AT, ST0_CU1 >> 16); + uasm_i_and(&p, GPR_V1, GPR_V0, GPR_AT); + uasm_il_beqz(&p, &r, GPR_V1, label_fpu_1); uasm_i_nop(&p); - uasm_i_cfc1(&p, T0, 31); - uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.fcr31), - K1); - uasm_i_ctc1(&p, ZERO, 31); + uasm_i_cfc1(&p, GPR_T0, 31); + uasm_i_sw(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, fpu.fcr31), + GPR_K1); + uasm_i_ctc1(&p, GPR_ZERO, 31); uasm_l_fpu_1(&l, p); } @@ -649,22 +619,22 @@ void *kvm_mips_build_exit(void *addr) * If MSA is enabled, save MSACSR and clear it so that later * instructions don't trigger MSAFPE for pending exceptions. */ - uasm_i_mfc0(&p, T0, C0_CONFIG5); - uasm_i_ext(&p, T0, T0, 27, 1); /* MIPS_CONF5_MSAEN */ - uasm_il_beqz(&p, &r, T0, label_msa_1); + uasm_i_mfc0(&p, GPR_T0, C0_CONFIG5); + uasm_i_ext(&p, GPR_T0, GPR_T0, 27, 1); /* MIPS_CONF5_MSAEN */ + uasm_il_beqz(&p, &r, GPR_T0, label_msa_1); uasm_i_nop(&p); - uasm_i_cfcmsa(&p, T0, MSA_CSR); - uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.msacsr), - K1); - uasm_i_ctcmsa(&p, MSA_CSR, ZERO); + uasm_i_cfcmsa(&p, GPR_T0, MSA_CSR); + uasm_i_sw(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, fpu.msacsr), + GPR_K1); + uasm_i_ctcmsa(&p, MSA_CSR, GPR_ZERO); uasm_l_msa_1(&l, p); } /* Restore host ASID */ if (!cpu_has_guestid) { - UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, host_entryhi), - K1); - UASM_i_MTC0(&p, K0, C0_ENTRYHI); + UASM_i_LW(&p, GPR_K0, offsetof(struct kvm_vcpu_arch, host_entryhi), + GPR_K1); + UASM_i_MTC0(&p, GPR_K0, C0_ENTRYHI); } /* @@ -673,56 +643,56 @@ void *kvm_mips_build_exit(void *addr) * - call tlbmiss_handler_setup_pgd(mm->pgd) * - write mm->pgd into CP0_PWBase */ - UASM_i_LW(&p, A0, - offsetof(struct kvm_vcpu_arch, host_pgd), K1); - UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd); - uasm_i_jalr(&p, RA, T9); + UASM_i_LW(&p, GPR_A0, + offsetof(struct kvm_vcpu_arch, host_pgd), GPR_K1); + UASM_i_LA(&p, GPR_T9, (unsigned long)tlbmiss_handler_setup_pgd); + uasm_i_jalr(&p, GPR_RA, GPR_T9); /* delay slot */ if (cpu_has_htw) - UASM_i_MTC0(&p, A0, C0_PWBASE); + UASM_i_MTC0(&p, GPR_A0, C0_PWBASE); else uasm_i_nop(&p); /* Clear GM bit so we don't enter guest mode when EXL is cleared */ - uasm_i_mfc0(&p, K0, C0_GUESTCTL0); - uasm_i_ins(&p, K0, ZERO, MIPS_GCTL0_GM_SHIFT, 1); - uasm_i_mtc0(&p, K0, C0_GUESTCTL0); + uasm_i_mfc0(&p, GPR_K0, C0_GUESTCTL0); + uasm_i_ins(&p, GPR_K0, GPR_ZERO, MIPS_GCTL0_GM_SHIFT, 1); + uasm_i_mtc0(&p, GPR_K0, C0_GUESTCTL0); /* Save GuestCtl0 so we can access GExcCode after CPU migration */ - uasm_i_sw(&p, K0, - offsetof(struct kvm_vcpu_arch, host_cp0_guestctl0), K1); + uasm_i_sw(&p, GPR_K0, + offsetof(struct kvm_vcpu_arch, host_cp0_guestctl0), GPR_K1); if (cpu_has_guestid) { /* * Clear root mode GuestID, so that root TLB operations use the * root GuestID in the root TLB. */ - uasm_i_mfc0(&p, T0, C0_GUESTCTL1); + uasm_i_mfc0(&p, GPR_T0, C0_GUESTCTL1); /* Set GuestCtl1.RID = MIPS_GCTL1_ROOT_GUESTID (i.e. 0) */ - uasm_i_ins(&p, T0, ZERO, MIPS_GCTL1_RID_SHIFT, + uasm_i_ins(&p, GPR_T0, GPR_ZERO, MIPS_GCTL1_RID_SHIFT, MIPS_GCTL1_RID_WIDTH); - uasm_i_mtc0(&p, T0, C0_GUESTCTL1); + uasm_i_mtc0(&p, GPR_T0, C0_GUESTCTL1); } /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */ - uasm_i_addiu(&p, AT, ZERO, ~(ST0_EXL | KSU_USER | ST0_IE)); - uasm_i_and(&p, V0, V0, AT); - uasm_i_lui(&p, AT, ST0_CU0 >> 16); - uasm_i_or(&p, V0, V0, AT); + uasm_i_addiu(&p, GPR_AT, GPR_ZERO, ~(ST0_EXL | KSU_USER | ST0_IE)); + uasm_i_and(&p, GPR_V0, GPR_V0, GPR_AT); + uasm_i_lui(&p, GPR_AT, ST0_CU0 >> 16); + uasm_i_or(&p, GPR_V0, GPR_V0, GPR_AT); #ifdef CONFIG_64BIT - uasm_i_ori(&p, V0, V0, ST0_SX | ST0_UX); + uasm_i_ori(&p, GPR_V0, GPR_V0, ST0_SX | ST0_UX); #endif - uasm_i_mtc0(&p, V0, C0_STATUS); + uasm_i_mtc0(&p, GPR_V0, C0_STATUS); uasm_i_ehb(&p); - /* Load up host GP */ - UASM_i_LW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1); + /* Load up host GPR_GP */ + UASM_i_LW(&p, GPR_GP, offsetof(struct kvm_vcpu_arch, host_gp), GPR_K1); /* Need a stack before we can jump to "C" */ - UASM_i_LW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1); + UASM_i_LW(&p, GPR_SP, offsetof(struct kvm_vcpu_arch, host_stack), GPR_K1); /* Saved host state */ - UASM_i_ADDIU(&p, SP, SP, -(int)sizeof(struct pt_regs)); + UASM_i_ADDIU(&p, GPR_SP, GPR_SP, -(int)sizeof(struct pt_regs)); /* * XXXKYMA do we need to load the host ASID, maybe not because the @@ -730,12 +700,12 @@ void *kvm_mips_build_exit(void *addr) */ /* Restore host scratch registers, as we'll have clobbered them */ - kvm_mips_build_restore_scratch(&p, K0, SP); + kvm_mips_build_restore_scratch(&p, GPR_K0, GPR_SP); /* Restore RDHWR access */ - UASM_i_LA_mostly(&p, K0, (long)&hwrena); - uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0); - uasm_i_mtc0(&p, K0, C0_HWRENA); + UASM_i_LA_mostly(&p, GPR_K0, (long)&hwrena); + uasm_i_lw(&p, GPR_K0, uasm_rel_lo((long)&hwrena), GPR_K0); + uasm_i_mtc0(&p, GPR_K0, C0_HWRENA); /* Jump to handler */ /* @@ -743,10 +713,10 @@ void *kvm_mips_build_exit(void *addr) * Now jump to the kvm_mips_handle_exit() to see if we can deal * with this in the kernel */ - uasm_i_move(&p, A0, S0); - UASM_i_LA(&p, T9, (unsigned long)kvm_mips_handle_exit); - uasm_i_jalr(&p, RA, T9); - UASM_i_ADDIU(&p, SP, SP, -CALLFRAME_SIZ); + uasm_i_move(&p, GPR_A0, GPR_S0); + UASM_i_LA(&p, GPR_T9, (unsigned long)kvm_mips_handle_exit); + uasm_i_jalr(&p, GPR_RA, GPR_T9); + UASM_i_ADDIU(&p, GPR_SP, GPR_SP, -CALLFRAME_SIZ); uasm_resolve_relocs(relocs, labels); @@ -776,7 +746,7 @@ static void *kvm_mips_build_ret_from_exit(void *addr) memset(relocs, 0, sizeof(relocs)); /* Return from handler Make sure interrupts are disabled */ - uasm_i_di(&p, ZERO); + uasm_i_di(&p, GPR_ZERO); uasm_i_ehb(&p); /* @@ -785,15 +755,15 @@ static void *kvm_mips_build_ret_from_exit(void *addr) * guest, reload k1 */ - uasm_i_move(&p, K1, S0); - UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch)); + uasm_i_move(&p, GPR_K1, GPR_S0); + UASM_i_ADDIU(&p, GPR_K1, GPR_K1, offsetof(struct kvm_vcpu, arch)); /* * Check return value, should tell us if we are returning to the * host (handle I/O etc)or resuming the guest */ - uasm_i_andi(&p, T0, V0, RESUME_HOST); - uasm_il_bnez(&p, &r, T0, label_return_to_host); + uasm_i_andi(&p, GPR_T0, GPR_V0, RESUME_HOST); + uasm_il_bnez(&p, &r, GPR_T0, label_return_to_host); uasm_i_nop(&p); p = kvm_mips_build_ret_to_guest(p); @@ -820,24 +790,24 @@ static void *kvm_mips_build_ret_to_guest(void *addr) u32 *p = addr; /* Put the saved pointer to vcpu (s0) back into the scratch register */ - UASM_i_MTC0(&p, S0, scratch_vcpu[0], scratch_vcpu[1]); + UASM_i_MTC0(&p, GPR_S0, scratch_vcpu[0], scratch_vcpu[1]); /* Load up the Guest EBASE to minimize the window where BEV is set */ - UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1); + UASM_i_LW(&p, GPR_T0, offsetof(struct kvm_vcpu_arch, guest_ebase), GPR_K1); /* Switch EBASE back to the one used by KVM */ - uasm_i_mfc0(&p, V1, C0_STATUS); - uasm_i_lui(&p, AT, ST0_BEV >> 16); - uasm_i_or(&p, K0, V1, AT); - uasm_i_mtc0(&p, K0, C0_STATUS); + uasm_i_mfc0(&p, GPR_V1, C0_STATUS); + uasm_i_lui(&p, GPR_AT, ST0_BEV >> 16); + uasm_i_or(&p, GPR_K0, GPR_V1, GPR_AT); + uasm_i_mtc0(&p, GPR_K0, C0_STATUS); uasm_i_ehb(&p); - build_set_exc_base(&p, T0); + build_set_exc_base(&p, GPR_T0); /* Setup status register for running guest in UM */ - uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE); - UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX | ST0_SX | ST0_UX)); - uasm_i_and(&p, V1, V1, AT); - uasm_i_mtc0(&p, V1, C0_STATUS); + uasm_i_ori(&p, GPR_V1, GPR_V1, ST0_EXL | KSU_USER | ST0_IE); + UASM_i_LA(&p, GPR_AT, ~(ST0_CU0 | ST0_MX | ST0_SX | ST0_UX)); + uasm_i_and(&p, GPR_V1, GPR_V1, GPR_AT); + uasm_i_mtc0(&p, GPR_V1, C0_STATUS); uasm_i_ehb(&p); p = kvm_mips_build_enter_guest(p); @@ -861,31 +831,31 @@ static void *kvm_mips_build_ret_to_host(void *addr) unsigned int i; /* EBASE is already pointing to Linux */ - UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, host_stack), K1); - UASM_i_ADDIU(&p, K1, K1, -(int)sizeof(struct pt_regs)); + UASM_i_LW(&p, GPR_K1, offsetof(struct kvm_vcpu_arch, host_stack), GPR_K1); + UASM_i_ADDIU(&p, GPR_K1, GPR_K1, -(int)sizeof(struct pt_regs)); /* * r2/v0 is the return code, shift it down by 2 (arithmetic) * to recover the err code */ - uasm_i_sra(&p, K0, V0, 2); - uasm_i_move(&p, V0, K0); + uasm_i_sra(&p, GPR_K0, GPR_V0, 2); + uasm_i_move(&p, GPR_V0, GPR_K0); /* Load context saved on the host stack */ for (i = 16; i < 31; ++i) { if (i == 24) i = 28; - UASM_i_LW(&p, i, offsetof(struct pt_regs, regs[i]), K1); + UASM_i_LW(&p, i, offsetof(struct pt_regs, regs[i]), GPR_K1); } /* Restore RDHWR access */ - UASM_i_LA_mostly(&p, K0, (long)&hwrena); - uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0); - uasm_i_mtc0(&p, K0, C0_HWRENA); + UASM_i_LA_mostly(&p, GPR_K0, (long)&hwrena); + uasm_i_lw(&p, GPR_K0, uasm_rel_lo((long)&hwrena), GPR_K0); + uasm_i_mtc0(&p, GPR_K0, C0_HWRENA); - /* Restore RA, which is the address we will return to */ - UASM_i_LW(&p, RA, offsetof(struct pt_regs, regs[RA]), K1); - uasm_i_jr(&p, RA); + /* Restore GPR_RA, which is the address we will return to */ + UASM_i_LW(&p, GPR_RA, offsetof(struct pt_regs, regs[GPR_RA]), GPR_K1); + uasm_i_jr(&p, GPR_RA); uasm_i_nop(&p); return p; From 6d74e0fc0a34ef72365f88a249e351a353f8dc03 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 9 Feb 2024 18:07:54 +0000 Subject: [PATCH 372/814] MIPS: pm-cps: Use GPR number macros Use GPR number macros in uasm code generation parts to reduce code duplication. There are functional change due to difference in register symbolic names between OABI and NABI, while existing code is only using definitions from OABI. Code pieces are carefully inspected to ensure register usages are safe on NABI as well. We changed register allocation of r_pcohctl from T7 to T8 as T7 is not available on NABI and we just want a caller saved scratch register here. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/pm-cps.c | 134 ++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 9bf60d7d44d3..d09ca77e624d 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -69,13 +70,6 @@ DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state); static struct uasm_label labels[32]; static struct uasm_reloc relocs[32]; -enum mips_reg { - zero, at, v0, v1, a0, a1, a2, a3, - t0, t1, t2, t3, t4, t5, t6, t7, - s0, s1, s2, s3, s4, s5, s6, s7, - t8, t9, k0, k1, gp, sp, fp, ra, -}; - bool cps_pm_support_state(enum cps_pm_state state) { return test_bit(state, state_support); @@ -203,13 +197,13 @@ static void cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, return; /* Load base address */ - UASM_i_LA(pp, t0, (long)CKSEG0); + UASM_i_LA(pp, GPR_T0, (long)CKSEG0); /* Calculate end address */ if (cache_size < 0x8000) - uasm_i_addiu(pp, t1, t0, cache_size); + uasm_i_addiu(pp, GPR_T1, GPR_T0, cache_size); else - UASM_i_LA(pp, t1, (long)(CKSEG0 + cache_size)); + UASM_i_LA(pp, GPR_T1, (long)(CKSEG0 + cache_size)); /* Start of cache op loop */ uasm_build_label(pl, *pp, lbl); @@ -217,19 +211,19 @@ static void cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, /* Generate the cache ops */ for (i = 0; i < unroll_lines; i++) { if (cpu_has_mips_r6) { - uasm_i_cache(pp, op, 0, t0); - uasm_i_addiu(pp, t0, t0, cache->linesz); + uasm_i_cache(pp, op, 0, GPR_T0); + uasm_i_addiu(pp, GPR_T0, GPR_T0, cache->linesz); } else { - uasm_i_cache(pp, op, i * cache->linesz, t0); + uasm_i_cache(pp, op, i * cache->linesz, GPR_T0); } } if (!cpu_has_mips_r6) /* Update the base address */ - uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); + uasm_i_addiu(pp, GPR_T0, GPR_T0, unroll_lines * cache->linesz); /* Loop if we haven't reached the end address yet */ - uasm_il_bne(pp, pr, t0, t1, lbl); + uasm_il_bne(pp, pr, GPR_T0, GPR_T1, lbl); uasm_i_nop(pp); } @@ -275,25 +269,25 @@ static int cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, */ /* Preserve perf counter setup */ - uasm_i_mfc0(pp, t2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ - uasm_i_mfc0(pp, t3, 25, (perf_counter * 2) + 1); /* PerfCntN */ + uasm_i_mfc0(pp, GPR_T2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ + uasm_i_mfc0(pp, GPR_T3, 25, (perf_counter * 2) + 1); /* PerfCntN */ /* Setup perf counter to count FSB full pipeline stalls */ - uasm_i_addiu(pp, t0, zero, (perf_event << 5) | 0xf); - uasm_i_mtc0(pp, t0, 25, (perf_counter * 2) + 0); /* PerfCtlN */ + uasm_i_addiu(pp, GPR_T0, GPR_ZERO, (perf_event << 5) | 0xf); + uasm_i_mtc0(pp, GPR_T0, 25, (perf_counter * 2) + 0); /* PerfCtlN */ uasm_i_ehb(pp); - uasm_i_mtc0(pp, zero, 25, (perf_counter * 2) + 1); /* PerfCntN */ + uasm_i_mtc0(pp, GPR_ZERO, 25, (perf_counter * 2) + 1); /* PerfCntN */ uasm_i_ehb(pp); /* Base address for loads */ - UASM_i_LA(pp, t0, (long)CKSEG0); + UASM_i_LA(pp, GPR_T0, (long)CKSEG0); /* Start of clear loop */ uasm_build_label(pl, *pp, lbl); /* Perform some loads to fill the FSB */ for (i = 0; i < num_loads; i++) - uasm_i_lw(pp, zero, i * line_size * line_stride, t0); + uasm_i_lw(pp, GPR_ZERO, i * line_size * line_stride, GPR_T0); /* * Invalidate the new D-cache entries so that the cache will need @@ -301,9 +295,9 @@ static int cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, */ for (i = 0; i < num_loads; i++) { uasm_i_cache(pp, Hit_Invalidate_D, - i * line_size * line_stride, t0); + i * line_size * line_stride, GPR_T0); uasm_i_cache(pp, Hit_Writeback_Inv_SD, - i * line_size * line_stride, t0); + i * line_size * line_stride, GPR_T0); } /* Barrier ensuring previous cache invalidates are complete */ @@ -311,16 +305,16 @@ static int cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, uasm_i_ehb(pp); /* Check whether the pipeline stalled due to the FSB being full */ - uasm_i_mfc0(pp, t1, 25, (perf_counter * 2) + 1); /* PerfCntN */ + uasm_i_mfc0(pp, GPR_T1, 25, (perf_counter * 2) + 1); /* PerfCntN */ /* Loop if it didn't */ - uasm_il_beqz(pp, pr, t1, lbl); + uasm_il_beqz(pp, pr, GPR_T1, lbl); uasm_i_nop(pp); /* Restore perf counter 1. The count may well now be wrong... */ - uasm_i_mtc0(pp, t2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ + uasm_i_mtc0(pp, GPR_T2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ uasm_i_ehb(pp); - uasm_i_mtc0(pp, t3, 25, (perf_counter * 2) + 1); /* PerfCntN */ + uasm_i_mtc0(pp, GPR_T3, 25, (perf_counter * 2) + 1); /* PerfCntN */ uasm_i_ehb(pp); return 0; @@ -330,12 +324,12 @@ static void cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, struct uasm_reloc **pr, unsigned r_addr, int lbl) { - uasm_i_lui(pp, t0, uasm_rel_hi(0x80000000)); + uasm_i_lui(pp, GPR_T0, uasm_rel_hi(0x80000000)); uasm_build_label(pl, *pp, lbl); - uasm_i_ll(pp, t1, 0, r_addr); - uasm_i_or(pp, t1, t1, t0); - uasm_i_sc(pp, t1, 0, r_addr); - uasm_il_beqz(pp, pr, t1, lbl); + uasm_i_ll(pp, GPR_T1, 0, r_addr); + uasm_i_or(pp, GPR_T1, GPR_T1, GPR_T0); + uasm_i_sc(pp, GPR_T1, 0, r_addr); + uasm_il_beqz(pp, pr, GPR_T1, lbl); uasm_i_nop(pp); } @@ -344,9 +338,9 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) struct uasm_label *l = labels; struct uasm_reloc *r = relocs; u32 *buf, *p; - const unsigned r_online = a0; - const unsigned r_nc_count = a1; - const unsigned r_pcohctl = t7; + const unsigned r_online = GPR_A0; + const unsigned r_nc_count = GPR_A1; + const unsigned r_pcohctl = GPR_T8; const unsigned max_instrs = 256; unsigned cpc_cmd; int err; @@ -383,8 +377,8 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * with the return address placed in v0 to avoid clobbering * the ra register before it is saved. */ - UASM_i_LA(&p, t0, (long)mips_cps_pm_save); - uasm_i_jalr(&p, v0, t0); + UASM_i_LA(&p, GPR_T0, (long)mips_cps_pm_save); + uasm_i_jalr(&p, GPR_V0, GPR_T0); uasm_i_nop(&p); } @@ -399,11 +393,11 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) /* Increment ready_count */ uasm_i_sync(&p, __SYNC_mb); uasm_build_label(&l, p, lbl_incready); - uasm_i_ll(&p, t1, 0, r_nc_count); - uasm_i_addiu(&p, t2, t1, 1); - uasm_i_sc(&p, t2, 0, r_nc_count); - uasm_il_beqz(&p, &r, t2, lbl_incready); - uasm_i_addiu(&p, t1, t1, 1); + uasm_i_ll(&p, GPR_T1, 0, r_nc_count); + uasm_i_addiu(&p, GPR_T2, GPR_T1, 1); + uasm_i_sc(&p, GPR_T2, 0, r_nc_count); + uasm_il_beqz(&p, &r, GPR_T2, lbl_incready); + uasm_i_addiu(&p, GPR_T1, GPR_T1, 1); /* Barrier ensuring all CPUs see the updated r_nc_count value */ uasm_i_sync(&p, __SYNC_mb); @@ -412,7 +406,7 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * If this is the last VPE to become ready for non-coherence * then it should branch below. */ - uasm_il_beq(&p, &r, t1, r_online, lbl_disable_coherence); + uasm_il_beq(&p, &r, GPR_T1, r_online, lbl_disable_coherence); uasm_i_nop(&p); if (state < CPS_PM_POWER_GATED) { @@ -422,13 +416,13 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * has been disabled before proceeding, which it will do * by polling for the top bit of ready_count being set. */ - uasm_i_addiu(&p, t1, zero, -1); + uasm_i_addiu(&p, GPR_T1, GPR_ZERO, -1); uasm_build_label(&l, p, lbl_poll_cont); - uasm_i_lw(&p, t0, 0, r_nc_count); - uasm_il_bltz(&p, &r, t0, lbl_secondary_cont); + uasm_i_lw(&p, GPR_T0, 0, r_nc_count); + uasm_il_bltz(&p, &r, GPR_T0, lbl_secondary_cont); uasm_i_ehb(&p); if (cpu_has_mipsmt) - uasm_i_yield(&p, zero, t1); + uasm_i_yield(&p, GPR_ZERO, GPR_T1); uasm_il_b(&p, &r, lbl_poll_cont); uasm_i_nop(&p); } else { @@ -438,16 +432,16 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) */ if (cpu_has_mipsmt) { /* Halt the VPE via C0 tchalt register */ - uasm_i_addiu(&p, t0, zero, TCHALT_H); - uasm_i_mtc0(&p, t0, 2, 4); + uasm_i_addiu(&p, GPR_T0, GPR_ZERO, TCHALT_H); + uasm_i_mtc0(&p, GPR_T0, 2, 4); } else if (cpu_has_vp) { /* Halt the VP via the CPC VP_STOP register */ unsigned int vpe_id; vpe_id = cpu_vpe_id(&cpu_data[cpu]); - uasm_i_addiu(&p, t0, zero, 1 << vpe_id); - UASM_i_LA(&p, t1, (long)addr_cpc_cl_vp_stop()); - uasm_i_sw(&p, t0, 0, t1); + uasm_i_addiu(&p, GPR_T0, GPR_ZERO, 1 << vpe_id); + UASM_i_LA(&p, GPR_T1, (long)addr_cpc_cl_vp_stop()); + uasm_i_sw(&p, GPR_T0, 0, GPR_T1); } else { BUG(); } @@ -482,9 +476,9 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * defined by the interAptiv & proAptiv SUMs as ensuring that the * operation resulting from the preceding store is complete. */ - uasm_i_addiu(&p, t0, zero, 1 << cpu_core(&cpu_data[cpu])); - uasm_i_sw(&p, t0, 0, r_pcohctl); - uasm_i_lw(&p, t0, 0, r_pcohctl); + uasm_i_addiu(&p, GPR_T0, GPR_ZERO, 1 << cpu_core(&cpu_data[cpu])); + uasm_i_sw(&p, GPR_T0, 0, r_pcohctl); + uasm_i_lw(&p, GPR_T0, 0, r_pcohctl); /* Barrier to ensure write to coherence control is complete */ uasm_i_sync(&p, __SYNC_full); @@ -492,8 +486,8 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) } /* Disable coherence */ - uasm_i_sw(&p, zero, 0, r_pcohctl); - uasm_i_lw(&p, t0, 0, r_pcohctl); + uasm_i_sw(&p, GPR_ZERO, 0, r_pcohctl); + uasm_i_lw(&p, GPR_T0, 0, r_pcohctl); if (state >= CPS_PM_CLOCK_GATED) { err = cps_gen_flush_fsb(&p, &l, &r, &cpu_data[cpu], @@ -515,9 +509,9 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) } /* Issue the CPC command */ - UASM_i_LA(&p, t0, (long)addr_cpc_cl_cmd()); - uasm_i_addiu(&p, t1, zero, cpc_cmd); - uasm_i_sw(&p, t1, 0, t0); + UASM_i_LA(&p, GPR_T0, (long)addr_cpc_cl_cmd()); + uasm_i_addiu(&p, GPR_T1, GPR_ZERO, cpc_cmd); + uasm_i_sw(&p, GPR_T1, 0, GPR_T0); if (state == CPS_PM_POWER_GATED) { /* If anything goes wrong just hang */ @@ -564,12 +558,12 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) * will run this. The first will actually re-enable coherence & the * rest will just be performing a rather unusual nop. */ - uasm_i_addiu(&p, t0, zero, mips_cm_revision() < CM_REV_CM3 + uasm_i_addiu(&p, GPR_T0, GPR_ZERO, mips_cm_revision() < CM_REV_CM3 ? CM_GCR_Cx_COHERENCE_COHDOMAINEN : CM3_GCR_Cx_COHERENCE_COHEN); - uasm_i_sw(&p, t0, 0, r_pcohctl); - uasm_i_lw(&p, t0, 0, r_pcohctl); + uasm_i_sw(&p, GPR_T0, 0, r_pcohctl); + uasm_i_lw(&p, GPR_T0, 0, r_pcohctl); /* Barrier to ensure write to coherence control is complete */ uasm_i_sync(&p, __SYNC_full); @@ -579,11 +573,11 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) /* Decrement ready_count */ uasm_build_label(&l, p, lbl_decready); uasm_i_sync(&p, __SYNC_mb); - uasm_i_ll(&p, t1, 0, r_nc_count); - uasm_i_addiu(&p, t2, t1, -1); - uasm_i_sc(&p, t2, 0, r_nc_count); - uasm_il_beqz(&p, &r, t2, lbl_decready); - uasm_i_andi(&p, v0, t1, (1 << fls(smp_num_siblings)) - 1); + uasm_i_ll(&p, GPR_T1, 0, r_nc_count); + uasm_i_addiu(&p, GPR_T2, GPR_T1, -1); + uasm_i_sc(&p, GPR_T2, 0, r_nc_count); + uasm_il_beqz(&p, &r, GPR_T2, lbl_decready); + uasm_i_andi(&p, GPR_V0, GPR_T1, (1 << fls(smp_num_siblings)) - 1); /* Barrier ensuring all CPUs see the updated r_nc_count value */ uasm_i_sync(&p, __SYNC_mb); @@ -612,7 +606,7 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) } /* The core is coherent, time to return to C code */ - uasm_i_jr(&p, ra); + uasm_i_jr(&p, GPR_RA); uasm_i_nop(&p); gen_done: From e40192dabaaae540578339d86b4e3fb105973710 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:10 +0100 Subject: [PATCH 373/814] MIPS: spaces: Define a couple of handy macros Define CKSEGX_SIZE to represent the size of each KSEG segment. Introduce CKSEG0ADDR_OR_64BIT and CKSEG1ADDR_OR_64BIT to get an XPHYS address in 64bits and CKSEG[01]ADDR() in 32 bits mode. Co-developed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/addrspace.h | 5 +++++ arch/mips/include/asm/mach-generic/spaces.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index 59a48c60a065..7e9ef01cb182 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -47,6 +47,11 @@ */ #define KSEGX(a) ((_ACAST32_(a)) & _ACAST32_(0xe0000000)) +/* + * Gives the size of each kernel segment + */ +#define CSEGX_SIZE 0x20000000 + /* * Returns the physical address of a CKSEGx / XKPHYS address */ diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index b247575c5e69..f8783d339fb0 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -49,6 +49,8 @@ #define HIGHMEM_START _AC(0x20000000, UL) #endif +#define CKSEG0ADDR_OR_64BIT(x) CKSEG0ADDR(x) +#define CKSEG1ADDR_OR_64BIT(x) CKSEG1ADDR(x) #endif /* CONFIG_32BIT */ #ifdef CONFIG_64BIT @@ -82,6 +84,8 @@ #define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK)) #define TO_UNCAC(x) (UNCAC_BASE | ((x) & TO_PHYS_MASK)) +#define CKSEG0ADDR_OR_64BIT(x) TO_CAC(x) +#define CKSEG1ADDR_OR_64BIT(x) TO_UNCAC(x) #endif /* CONFIG_64BIT */ /* From 3391b95cf6a0b5b70904857dcc415b832f81866a Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 16 Feb 2024 18:42:11 +0100 Subject: [PATCH 374/814] MIPS: Fix set_uncached_handler for ebase in XKPHYS ebase might reside in XKPHYS if memblock is unable to allocate memory within the KSEG0 physical range. To map EBASE into uncached space, we convert it back to its physical address and utilize the new CKSEG1ADDR_OR_64BIT helper for mapping. Co-developed-by: Vladimir Kondratiev Signed-off-by: Vladimir Kondratiev Co-developed-by: Gregory CLEMENT Signed-off-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 2d95e9971a2d..a0085445f440 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2299,7 +2299,7 @@ static const char panic_null_cerr[] = void set_uncached_handler(unsigned long offset, void *addr, unsigned long size) { - unsigned long uncached_ebase = CKSEG1ADDR(ebase); + unsigned long uncached_ebase = CKSEG1ADDR_OR_64BIT(__pa(ebase)); if (!addr) panic(panic_null_cerr); From 5e9d13bd3de8c34ee81b9db8c50887fea5b93834 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 16 Feb 2024 18:42:12 +0100 Subject: [PATCH 375/814] MIPS: Allows relocation exception vectors everywhere Now the exception vector for CPS systems are allocated on-fly with memblock as well. It will try to allocate from KSEG1 first, and then try to allocate in low 4G if possible. The main reset vector is now generated by uasm, to avoid tons of patches to the code. Other vectors are copied to the location later. move 64bits fix in an other patch fix cache issue with mips_cps_core_entry rewrite the patch to reduce the diff stat move extern in header use cache address for copying vector gc: use the new macro CKSEG[0A1]DDR_OR_64BIT() Signed-off-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mips-cm.h | 1 + arch/mips/include/asm/smp-cps.h | 9 +- arch/mips/kernel/cps-vec.S | 48 ++--------- arch/mips/kernel/smp-cps.c | 141 ++++++++++++++++++++++++++------ 4 files changed, 133 insertions(+), 66 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 23c67c0871b1..15d8d69de455 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -311,6 +311,7 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other) /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */ GCR_CX_ACCESSOR_RW(32, 0x020, reset_base) #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE GENMASK(31, 12) +#define CM_GCR_Cx_RESET_BASE_MODE BIT(1) /* GCR_Cx_ID - Identify the current core */ GCR_CX_ACCESSOR_RO(32, 0x028, id) diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index 22a572b70fe3..ab94e50f62b8 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -24,7 +24,7 @@ struct core_boot_config { extern struct core_boot_config *mips_cps_core_bootcfg; -extern void mips_cps_core_entry(void); +extern void mips_cps_core_boot(int cca, void __iomem *gcr_base); extern void mips_cps_core_init(void); extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe); @@ -32,7 +32,12 @@ extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe); extern void mips_cps_pm_save(void); extern void mips_cps_pm_restore(void); -extern void *mips_cps_core_entry_patch_end; +extern void excep_tlbfill(void); +extern void excep_xtlbfill(void); +extern void excep_cache(void); +extern void excep_genex(void); +extern void excep_intex(void); +extern void excep_ejtag(void); #ifdef CONFIG_MIPS_CPS diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 64ecfdac6580..df610c006b44 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -4,6 +4,7 @@ * Author: Paul Burton */ +#include #include #include #include @@ -82,39 +83,10 @@ .endm -.balign 0x1000 - -LEAF(mips_cps_core_entry) - /* - * These first several instructions will be patched by cps_smp_setup to load the - * CCA to use into register s0 and GCR base address to register s1. - */ - .rept CPS_ENTRY_PATCH_INSNS - nop - .endr - - .global mips_cps_core_entry_patch_end -mips_cps_core_entry_patch_end: - - /* Check whether we're here due to an NMI */ - mfc0 k0, CP0_STATUS - and k0, k0, ST0_NMI - beqz k0, not_nmi - nop - - /* This is an NMI */ - PTR_LA k0, nmi_handler - jr k0 - nop - -not_nmi: - /* Setup Cause */ - li t0, CAUSEF_IV - mtc0 t0, CP0_CAUSE - - /* Setup Status */ - li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS - mtc0 t0, CP0_STATUS +LEAF(mips_cps_core_boot) + /* Save CCA and GCR base */ + move s0, a0 + move s1, a1 /* We don't know how to do coherence setup on earlier ISA */ #if MIPS_ISA_REV > 0 @@ -178,49 +150,45 @@ not_nmi: PTR_L sp, VPEBOOTCFG_SP(v1) jr t1 nop - END(mips_cps_core_entry) + END(mips_cps_core_boot) -.org 0x200 + __INIT LEAF(excep_tlbfill) DUMP_EXCEP("TLB Fill") b . nop END(excep_tlbfill) -.org 0x280 LEAF(excep_xtlbfill) DUMP_EXCEP("XTLB Fill") b . nop END(excep_xtlbfill) -.org 0x300 LEAF(excep_cache) DUMP_EXCEP("Cache") b . nop END(excep_cache) -.org 0x380 LEAF(excep_genex) DUMP_EXCEP("General") b . nop END(excep_genex) -.org 0x400 LEAF(excep_intex) DUMP_EXCEP("Interrupt") b . nop END(excep_intex) -.org 0x480 LEAF(excep_ejtag) PTR_LA k0, ejtag_debug_handler jr k0 nop END(excep_ejtag) + __FINIT LEAF(mips_cps_core_init) #ifdef CONFIG_MIPS_MT_SMP diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index f6c37d407f36..9cc087dd1c19 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -20,12 +21,24 @@ #include #include #include +#include #include #include #include #include +#define BEV_VEC_SIZE 0x500 +#define BEV_VEC_ALIGN 0x1000 + +enum label_id { + label_not_nmi = 1, +}; + +UASM_L_LA(_not_nmi) + static DECLARE_BITMAP(core_power, NR_CPUS); +static uint32_t core_entry_reg; +static phys_addr_t cps_vec_pa; struct core_boot_config *mips_cps_core_bootcfg; @@ -34,10 +47,100 @@ static unsigned __init core_vpe_count(unsigned int cluster, unsigned core) return min(smp_max_threads, mips_cps_numvps(cluster, core)); } +static void __init *mips_cps_build_core_entry(void *addr) +{ + extern void (*nmi_handler)(void); + u32 *p = addr; + u32 val; + struct uasm_label labels[2]; + struct uasm_reloc relocs[2]; + struct uasm_label *l = labels; + struct uasm_reloc *r = relocs; + + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + + uasm_i_mfc0(&p, GPR_K0, C0_STATUS); + UASM_i_LA(&p, GPR_T9, ST0_NMI); + uasm_i_and(&p, GPR_K0, GPR_K0, GPR_T9); + + uasm_il_bnez(&p, &r, GPR_K0, label_not_nmi); + uasm_i_nop(&p); + UASM_i_LA(&p, GPR_K0, (long)&nmi_handler); + + uasm_l_not_nmi(&l, p); + + val = CAUSEF_IV; + uasm_i_lui(&p, GPR_K0, val >> 16); + uasm_i_ori(&p, GPR_K0, GPR_K0, val & 0xffff); + uasm_i_mtc0(&p, GPR_K0, C0_CAUSE); + val = ST0_CU1 | ST0_CU0 | ST0_BEV | ST0_KX_IF_64; + uasm_i_lui(&p, GPR_K0, val >> 16); + uasm_i_ori(&p, GPR_K0, GPR_K0, val & 0xffff); + uasm_i_mtc0(&p, GPR_K0, C0_STATUS); + uasm_i_ehb(&p); + uasm_i_ori(&p, GPR_A0, 0, read_c0_config() & CONF_CM_CMASK); + UASM_i_LA(&p, GPR_A1, (long)mips_gcr_base); +#if defined(KBUILD_64BIT_SYM32) || defined(CONFIG_32BIT) + UASM_i_LA(&p, GPR_T9, CKSEG1ADDR(__pa_symbol(mips_cps_core_boot))); +#else + UASM_i_LA(&p, GPR_T9, TO_UNCAC(__pa_symbol(mips_cps_core_boot))); +#endif + uasm_i_jr(&p, GPR_T9); + uasm_i_nop(&p); + + uasm_resolve_relocs(relocs, labels); + + return p; +} + +static int __init allocate_cps_vecs(void) +{ + /* Try to allocate in KSEG1 first */ + cps_vec_pa = memblock_phys_alloc_range(BEV_VEC_SIZE, BEV_VEC_ALIGN, + 0x0, CSEGX_SIZE - 1); + + if (cps_vec_pa) + core_entry_reg = CKSEG1ADDR(cps_vec_pa) & + CM_GCR_Cx_RESET_BASE_BEVEXCBASE; + + if (!cps_vec_pa && mips_cm_is64) { + cps_vec_pa = memblock_phys_alloc_range(BEV_VEC_SIZE, BEV_VEC_ALIGN, + 0x0, SZ_4G - 1); + if (cps_vec_pa) + core_entry_reg = (cps_vec_pa & CM_GCR_Cx_RESET_BASE_BEVEXCBASE) | + CM_GCR_Cx_RESET_BASE_MODE; + } + + if (!cps_vec_pa) + return -ENOMEM; + + return 0; +} + +static void __init setup_cps_vecs(void) +{ + void *cps_vec; + + cps_vec = (void *)CKSEG1ADDR_OR_64BIT(cps_vec_pa); + mips_cps_build_core_entry(cps_vec); + + memcpy(cps_vec + 0x200, &excep_tlbfill, 0x80); + memcpy(cps_vec + 0x280, &excep_xtlbfill, 0x80); + memcpy(cps_vec + 0x300, &excep_cache, 0x80); + memcpy(cps_vec + 0x380, &excep_genex, 0x80); + memcpy(cps_vec + 0x400, &excep_intex, 0x80); + memcpy(cps_vec + 0x480, &excep_ejtag, 0x80); + + /* Make sure no prefetched data in cache */ + blast_inv_dcache_range(CKSEG0ADDR_OR_64BIT(cps_vec_pa), CKSEG0ADDR_OR_64BIT(cps_vec_pa) + BEV_VEC_SIZE); + bc_inv(CKSEG0ADDR_OR_64BIT(cps_vec_pa), BEV_VEC_SIZE); + __sync(); +} + static void __init cps_smp_setup(void) { unsigned int nclusters, ncores, nvpes, core_vpes; - unsigned long core_entry; int cl, c, v; /* Detect & record VPE topology */ @@ -94,10 +197,11 @@ static void __init cps_smp_setup(void) /* Make core 0 coherent with everything */ write_gcr_cl_coherence(0xff); - if (mips_cm_revision() >= CM_REV_CM3) { - core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); - write_gcr_bev_base(core_entry); - } + if (allocate_cps_vecs()) + pr_err("Failed to allocate CPS vectors\n"); + + if (core_entry_reg && mips_cm_revision() >= CM_REV_CM3) + write_gcr_bev_base(core_entry_reg); #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ @@ -110,10 +214,14 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) { unsigned ncores, core_vpes, c, cca; bool cca_unsuitable, cores_limited; - u32 *entry_code; mips_mt_set_cpuoptions(); + if (!core_entry_reg) { + pr_err("core_entry address unsuitable, disabling smp-cps\n"); + goto err_out; + } + /* Detect whether the CCA is unsuited to multi-core SMP */ cca = read_c0_config() & CONF_CM_CMASK; switch (cca) { @@ -145,20 +253,7 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) (cca_unsuitable && cpu_has_dc_aliases) ? " & " : "", cpu_has_dc_aliases ? "dcache aliasing" : ""); - /* - * Patch the start of mips_cps_core_entry to provide: - * - * s0 = kseg0 CCA - */ - entry_code = (u32 *)&mips_cps_core_entry; - uasm_i_addiu(&entry_code, 16, 0, cca); - UASM_i_LA(&entry_code, 17, (long)mips_gcr_base); - BUG_ON((void *)entry_code > (void *)&mips_cps_core_entry_patch_end); - blast_dcache_range((unsigned long)&mips_cps_core_entry, - (unsigned long)entry_code); - bc_wback_inv((unsigned long)&mips_cps_core_entry, - (void *)entry_code - (void *)&mips_cps_core_entry); - __sync(); + setup_cps_vecs(); /* Allocate core boot configuration structs */ ncores = mips_cps_numcores(0); @@ -213,7 +308,7 @@ static void boot_core(unsigned int core, unsigned int vpe_id) mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL); /* Set its reset vector */ - write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry)); + write_gcr_co_reset_base(core_entry_reg); /* Ensure its coherency is disabled */ write_gcr_co_coherence(0); @@ -290,7 +385,6 @@ static int cps_boot_secondary(int cpu, struct task_struct *idle) unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id]; - unsigned long core_entry; unsigned int remote; int err; @@ -314,8 +408,7 @@ static int cps_boot_secondary(int cpu, struct task_struct *idle) if (cpu_has_vp) { mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL); - core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); - write_gcr_co_reset_base(core_entry); + write_gcr_co_reset_base(core_entry_reg); mips_cm_unlock_other(); } From 524aa6b17ab5ebb55ad909fbc2ac6cda0995e0db Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:13 +0100 Subject: [PATCH 376/814] MIPS: traps: Give more explanations if ebase doesn't belong to KSEG0 With the expanded support for placing the kernel in XPHYS rather than just KSEG0, scenarios where ebase doesn't belong to KSEG0 are more likely to occur. In such cases, we currently experience a substantial and perplexing stack dump without any accompanying explanation. To rectify this, we aim to replace the uninformative stack dump with a warning that offers a clear explanation of the issue. Reviewed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/traps.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a0085445f440..dc29bd9656b0 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2351,10 +2351,13 @@ void __init trap_init(void) * EVA is special though as it allows segments to be rearranged * and to become uncached during cache error handling. */ - if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000)) + if (!IS_ENABLED(CONFIG_EVA) && ebase_pa < 0x20000000) ebase = CKSEG0ADDR(ebase_pa); else ebase = (unsigned long)phys_to_virt(ebase_pa); + if (ebase_pa >= 0x20000000) + pr_warn("ebase(%pa) should better be in KSeg0", + &ebase_pa); } if (cpu_has_mmips) { From b1264ad8a4a072013e0c119ead699165edcd7734 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:14 +0100 Subject: [PATCH 377/814] MIPS: cps-vec: Use macros for 64bits access Some access are 32 bits only while they seems better to be done in 64bis for 64 bit kernel. This was extract from an initial patch from Jiaxun Co-developed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/cps-vec.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index df610c006b44..f876309130ad 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -396,7 +396,7 @@ LEAF(mips_cps_boot_vpes) /* Calculate a pointer to the VPEs struct vpe_boot_config */ li t0, VPEBOOTCFG_SIZE mul t0, t0, ta1 - addu t0, t0, ta3 + PTR_ADDU t0, t0, ta3 /* Set the TC restart PC */ lw t1, VPEBOOTCFG_PC(t0) @@ -571,10 +571,10 @@ dcache_done: lw $1, TI_CPU(gp) sll $1, $1, LONGLOG PTR_LA \dest, __per_cpu_offset - addu $1, $1, \dest + PTR_ADDU $1, $1, \dest lw $1, 0($1) PTR_LA \dest, cps_cpu_state - addu \dest, \dest, $1 + PTR_ADDU \dest, \dest, $1 .set pop .endm From 179771efacd7bbdd9bac5c5961ac4ac03df6585d Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:15 +0100 Subject: [PATCH 378/814] dt-bindings: Add vendor prefix for Mobileye Vision Technologies Ltd. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobileye Vision Technologies Ltd. is a company developing autonomous driving technologies and advanced driver-assistance systems (ADAS) including cameras, computer chips and software. Reviewed-by: Philippe Mathieu-Daudé Acked-by: Rob Herring Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 1a0dc04f1db4..fb088d9c6f5b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -911,6 +911,8 @@ patternProperties: description: Miyoo "^mntre,.*": description: MNT Research GmbH + "^mobileye,.*": + description: Mobileye Vision Technologies Ltd. "^modtronix,.*": description: Modtronix Engineering "^moortec,.*": From ef39583440ab3e7e9186200a451250172f96572b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:16 +0100 Subject: [PATCH 379/814] dt-bindings: mips: cpus: Sort the entries The entries were nearly sorted but there were still some entries at the wrong places. Let's fix it. Reviewed-by: Serge Semin Acked-by: Krzysztof Kozlowski Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/mips/cpus.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/mips/cpus.yaml b/Documentation/devicetree/bindings/mips/cpus.yaml index cf382dea3922..9bc47868d28b 100644 --- a/Documentation/devicetree/bindings/mips/cpus.yaml +++ b/Documentation/devicetree/bindings/mips/cpus.yaml @@ -23,22 +23,22 @@ properties: - brcm,bmips4380 - brcm,bmips5000 - brcm,bmips5200 - - ingenic,xburst-mxu1.0 - ingenic,xburst-fpu1.0-mxu1.1 - ingenic,xburst-fpu2.0-mxu2.0 + - ingenic,xburst-mxu1.0 - ingenic,xburst2-fpu2.1-mxu2.1-smt - loongson,gs264 - mips,m14Kc - - mips,mips4Kc - - mips,mips4KEc - - mips,mips24Kc - - mips,mips24KEc - - mips,mips74Kc - mips,mips1004Kc + - mips,mips24KEc + - mips,mips24Kc + - mips,mips4KEc + - mips,mips4Kc + - mips,mips74Kc - mti,interaptiv - - mti,mips24KEc - mti,mips14KEc - mti,mips14Kc + - mti,mips24KEc reg: maxItems: 1 From c401814730b057461f1b3c95f71a5980447c953b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:17 +0100 Subject: [PATCH 380/814] dt-bindings: mips: cpu: Add I-Class I6500 Multiprocessor Core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MIPS Warrior I-class I6500 was announced by Imagination Technologies in 2016 and is used in the Mobileye SoC EyeQ5. Acked-by: Arnd Bergmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Serge Semin Acked-by: Krzysztof Kozlowski Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/mips/cpus.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mips/cpus.yaml b/Documentation/devicetree/bindings/mips/cpus.yaml index 9bc47868d28b..a85137add668 100644 --- a/Documentation/devicetree/bindings/mips/cpus.yaml +++ b/Documentation/devicetree/bindings/mips/cpus.yaml @@ -23,6 +23,7 @@ properties: - brcm,bmips4380 - brcm,bmips5000 - brcm,bmips5200 + - img,i6500 - ingenic,xburst-fpu1.0-mxu1.1 - ingenic,xburst-fpu2.0-mxu2.0 - ingenic,xburst-mxu1.0 From 7c8697ef033f2a500d0c5de8f844ad312991fe61 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:18 +0100 Subject: [PATCH 381/814] dt-bindings: mips: Add bindings for Mobileye SoCs Add the yaml bindings for Mobileye SoCs. Currently only EyeQ5 is supported Reviewed-by: Rob Herring Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- .../devicetree/bindings/mips/mobileye.yaml | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/mobileye.yaml diff --git a/Documentation/devicetree/bindings/mips/mobileye.yaml b/Documentation/devicetree/bindings/mips/mobileye.yaml new file mode 100644 index 000000000000..831975f6b479 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/mobileye.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright 2023 Mobileye Vision Technologies Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mips/mobileye.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mobileye SoC series + +maintainers: + - Vladimir Kondratiev + - Gregory CLEMENT + - Théo Lebrun + +description: + Boards with a Mobileye SoC shall have the following properties. + +properties: + $nodename: + const: '/' + + compatible: + oneOf: + - description: Boards with Mobileye EyeQ5 SoC + items: + - enum: + - mobileye,eyeq5-epm5 + - const: mobileye,eyeq5 + +additionalProperties: true + +... From 8f6fd33b728eddb90db7b950e85b07aecfeada44 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:19 +0100 Subject: [PATCH 382/814] MIPS: mobileye: Add EyeQ5 dtsi Add a device tree include file for the Mobileye EyeQ5 SoC. Based on the work of Slava Samsonov Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/Makefile | 1 + .../boot/dts/mobileye/eyeq5-fixed-clocks.dtsi | 292 ++++++++++++++++++ arch/mips/boot/dts/mobileye/eyeq5.dtsi | 124 ++++++++ 3 files changed, 417 insertions(+) create mode 100644 arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi create mode 100644 arch/mips/boot/dts/mobileye/eyeq5.dtsi diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile index 928f38a79dff..efff87cb33a9 100644 --- a/arch/mips/boot/dts/Makefile +++ b/arch/mips/boot/dts/Makefile @@ -8,6 +8,7 @@ subdir-$(CONFIG_LANTIQ) += lantiq subdir-$(CONFIG_MACH_LOONGSON64) += loongson subdir-$(CONFIG_SOC_VCOREIII) += mscc subdir-$(CONFIG_MIPS_MALTA) += mti +subdir-$(CONFIG_MACH_EYEQ5) += mobileye subdir-$(CONFIG_LEGACY_BOARD_SEAD3) += mti subdir-$(CONFIG_FIT_IMAGE_FDT_NI169445) += ni subdir-$(CONFIG_MACH_PIC32) += pic32 diff --git a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi new file mode 100644 index 000000000000..78f5533a95c6 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2023 Mobileye Vision Technologies Ltd. + */ + +/ { + /* Fixed clock */ + pll_cpu: pll-cpu { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1500000000>; + }; + + pll_vdi: pll-vdi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1280000000>; + }; + + pll_per: pll-per { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2000000000>; + }; + + pll_ddr0: pll-ddr0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1857210000>; + }; + + pll_ddr1: pll-ddr1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1857210000>; + }; + +/* PLL_CPU derivatives */ + occ_cpu: occ-cpu { + compatible = "fixed-factor-clock"; + clocks = <&pll_cpu>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + si_css0_ref_clk: si-css0-ref-clk { /* gate ClkRstGen_si_css0_ref */ + compatible = "fixed-factor-clock"; + clocks = <&occ_cpu>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + cpc_clk: cpc-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + core0_clk: core0-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + core1_clk: core1-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + core2_clk: core2-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + core3_clk: core3-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + cm_clk: cm-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + mem_clk: mem-clk { + compatible = "fixed-factor-clock"; + clocks = <&si_css0_ref_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + occ_isram: occ-isram { + compatible = "fixed-factor-clock"; + clocks = <&pll_cpu>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; + isram_clk: isram-clk { /* gate ClkRstGen_isram */ + compatible = "fixed-factor-clock"; + clocks = <&occ_isram>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + occ_dbu: occ-dbu { + compatible = "fixed-factor-clock"; + clocks = <&pll_cpu>; + #clock-cells = <0>; + clock-div = <10>; + clock-mult = <1>; + }; + si_dbu_tp_pclk: si-dbu-tp-pclk { /* gate ClkRstGen_dbu */ + compatible = "fixed-factor-clock"; + clocks = <&occ_dbu>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; +/* PLL_VDI derivatives */ + occ_vdi: occ-vdi { + compatible = "fixed-factor-clock"; + clocks = <&pll_vdi>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; + vdi_clk: vdi-clk { /* gate ClkRstGen_vdi */ + compatible = "fixed-factor-clock"; + clocks = <&occ_vdi>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + occ_can_ser: occ-can-ser { + compatible = "fixed-factor-clock"; + clocks = <&pll_vdi>; + #clock-cells = <0>; + clock-div = <16>; + clock-mult = <1>; + }; + can_ser_clk: can-ser-clk { /* gate ClkRstGen_can_ser */ + compatible = "fixed-factor-clock"; + clocks = <&occ_can_ser>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + i2c_ser_clk: i2c-ser-clk { + compatible = "fixed-factor-clock"; + clocks = <&pll_vdi>; + #clock-cells = <0>; + clock-div = <20>; + clock-mult = <1>; + }; +/* PLL_PER derivatives */ + occ_periph: occ-periph { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <16>; + clock-mult = <1>; + }; + periph_clk: periph-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + can_clk: can-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + spi_clk: spi-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + uart_clk: uart-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + i2c_clk: i2c-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clock-output-names = "i2c_clk"; + }; + timer_clk: timer-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clock-output-names = "timer_clk"; + }; + gpio_clk: gpio-clk { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clock-output-names = "gpio_clk"; + }; + emmc_sys_clk: emmc-sys-clk { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <10>; + clock-mult = <1>; + clock-output-names = "emmc_sys_clk"; + }; + ccf_ctrl_clk: ccf-ctrl-clk { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <4>; + clock-mult = <1>; + clock-output-names = "ccf_ctrl_clk"; + }; + occ_mjpeg_core: occ-mjpeg-core { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + clock-output-names = "occ_mjpeg_core"; + }; + hsm_clk: hsm-clk { /* gate ClkRstGen_hsm */ + compatible = "fixed-factor-clock"; + clocks = <&occ_mjpeg_core>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clock-output-names = "hsm_clk"; + }; + mjpeg_core_clk: mjpeg-core-clk { /* gate ClkRstGen_mjpeg_gen */ + compatible = "fixed-factor-clock"; + clocks = <&occ_mjpeg_core>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clock-output-names = "mjpeg_core_clk"; + }; + fcmu_a_clk: fcmu-a-clk { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <20>; + clock-mult = <1>; + clock-output-names = "fcmu_a_clk"; + }; + occ_pci_sys: occ-pci-sys { + compatible = "fixed-factor-clock"; + clocks = <&pll_per>; + #clock-cells = <0>; + clock-div = <8>; + clock-mult = <1>; + clock-output-names = "occ_pci_sys"; + }; + pclk: pclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; /* 250MHz */ + }; + tsu_clk: tsu-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; /* 125MHz */ + }; +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi new file mode 100644 index 000000000000..6cc5980e2fa1 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* +* Copyright 2023 Mobileye Vision Technologies Ltd. +*/ + +#include + +#include "eyeq5-fixed-clocks.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "img,i6500"; + reg = <0>; + clocks = <&core0_clk>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* These reserved memory regions are also defined in bootmanager + * for configuring inbound translation for BARS, don't change + * these without syncing with bootmanager + */ + shmem0_reserved: shmem@804000000 { + reg = <0x8 0x04000000 0x0 0x1000000>; + }; + shmem1_reserved: shmem@805000000 { + reg = <0x8 0x05000000 0x0 0x1000000>; + }; + pci0_msi_reserved: pci0-msi@806000000 { + reg = <0x8 0x06000000 0x0 0x100000>; + }; + pci1_msi_reserved: pci1-msi@806100000 { + reg = <0x8 0x06100000 0x0 0x100000>; + }; + + mini_coredump0_reserved: mini-coredump0@806200000 { + reg = <0x8 0x06200000 0x0 0x100000>; + }; + mhm_reserved_0: the-mhm-reserved-0@0 { + reg = <0x8 0x00000000 0x0 0x0000800>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + soc: soc { + #address-cells = <2>; + #size-cells = <2>; + ranges; + compatible = "simple-bus"; + + uart0: serial@800000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0 0x800000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&uart_clk>, <&occ_periph>; + clock-names = "uartclk", "apb_pclk"; + }; + + uart1: serial@900000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0 0x900000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&uart_clk>, <&occ_periph>; + clock-names = "uartclk", "apb_pclk"; + }; + + uart2: serial@a00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0 0xa00000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&uart_clk>, <&occ_periph>; + clock-names = "uartclk", "apb_pclk"; + }; + + gic: interrupt-controller@140000 { + compatible = "mti,gic"; + reg = <0x0 0x140000 0x0 0x20000>; + interrupt-controller; + #interrupt-cells = <3>; + + /* + * Declare the interrupt-parent even though the mti,gic + * binding doesn't require it, such that the kernel can + * figure out that cpu_intc is the root interrupt + * controller & should be probed first. + */ + interrupt-parent = <&cpu_intc>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clocks = <&core0_clk>; + }; + }; + }; +}; From 263909a753d9fe070868a9b0890cb03fb402eaa1 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:20 +0100 Subject: [PATCH 383/814] MIPS: mobileye: Add EPM5 device tree Add a device tree for the Mobileye EPM5 evaluation board. Reviewed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/mobileye/Makefile | 4 ++++ arch/mips/boot/dts/mobileye/eyeq5-epm5.dts | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 arch/mips/boot/dts/mobileye/Makefile create mode 100644 arch/mips/boot/dts/mobileye/eyeq5-epm5.dts diff --git a/arch/mips/boot/dts/mobileye/Makefile b/arch/mips/boot/dts/mobileye/Makefile new file mode 100644 index 000000000000..01c01c3aad81 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright 2023 Mobileye Vision Technologies Ltd. + +dtb-$(CONFIG_MACH_EYEQ5) += eyeq5-epm5.dtb diff --git a/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts new file mode 100644 index 000000000000..6898b2d8267d --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2023 Mobileye Vision Technologies Ltd. + */ + +/dts-v1/; + +#include "eyeq5.dtsi" + +/ { + compatible = "mobileye,eyeq5-epm5", "mobileye,eyeq5"; + model = "Mobile EyeQ5 MP5 Evaluation board"; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x02000000>, + <0x8 0x02000000 0x0 0x7E000000>; + }; +}; From 80f2e4cd2573c7d5c8ecc287fb09b15f8dcafae0 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:21 +0100 Subject: [PATCH 384/814] MIPS: Share generic kernel code with other architecture Some architectures might seek to utilize a significant portion of the generic kernel code while maintaining independence from the generic kernel due to specific peculiarities. This patch allows for the reuse of core code, preventing unnecessary duplication. Suggested-by: Thomas Bogendoerfer Reviewed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kbuild | 1 + arch/mips/Kconfig | 6 ++++++ arch/mips/generic/Makefile | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild index e2d623621a00..e901bf554483 100644 --- a/arch/mips/Kbuild +++ b/arch/mips/Kbuild @@ -11,6 +11,7 @@ obj- := $(platform-y) # mips object files # The object files are linked as core-y files would be linked +obj-y += generic/ obj-y += kernel/ obj-y += mm/ obj-y += net/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 797ae590ebdb..04765463980a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -109,6 +109,9 @@ config MIPS_FIXUP_BIGPHYS_ADDR config MIPS_GENERIC bool +config MACH_GENERIC_CORE + bool + config MACH_INGENIC bool select SYS_SUPPORTS_32BIT_KERNEL @@ -145,6 +148,7 @@ config MIPS_GENERIC_KERNEL select DMA_NONCOHERENT select HAVE_PCI select IRQ_MIPS_CPU + select MACH_GENERIC_CORE select MIPS_AUTO_PFN_OFFSET select MIPS_CPU_SCACHE select MIPS_GIC @@ -413,6 +417,7 @@ config MACH_INGENIC_SOC bool "Ingenic SoC based machines" select MIPS_GENERIC select MACH_INGENIC + select MACH_GENERIC_CORE select SYS_SUPPORTS_ZBOOT_UART16550 select CPU_SUPPORTS_CPUFREQ select MIPS_EXTERNAL_TIMER @@ -599,6 +604,7 @@ config RALINK config MACH_REALTEK_RTL bool "Realtek RTL838x/RTL839x based machines" select MIPS_GENERIC + select MACH_GENERIC_CORE select DMA_NONCOHERENT select IRQ_MIPS_CPU select CSRC_R4K diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index e37a59bae0a6..56011d738441 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -4,9 +4,9 @@ # Author: Paul Burton # -obj-y += init.o -obj-y += irq.o -obj-y += proc.o +obj-$(CONFIG_MACH_GENERIC_CORE) += init.o +obj-$(CONFIG_MACH_GENERIC_CORE) += irq.o +obj-$(CONFIG_MACH_GENERIC_CORE) += proc.o obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o From 101bd58fde10681aea9d9677424275bb88a8845f Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:22 +0100 Subject: [PATCH 385/814] MIPS: Add support for Mobileye EyeQ5 Introduce support for the MIPS based Mobileye EyeQ5 SoCs. Reviewed-by: Jiaxun Yang Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kbuild.platforms | 1 + arch/mips/Kconfig | 53 ++++++++++++++ arch/mips/configs/eyeq5_defconfig | 108 ++++++++++++++++++++++++++++ arch/mips/mobileye/Makefile | 1 + arch/mips/mobileye/Platform | 15 ++++ arch/mips/mobileye/board-epm5.its.S | 24 +++++++ arch/mips/mobileye/vmlinux.its.S | 32 +++++++++ 7 files changed, 234 insertions(+) create mode 100644 arch/mips/configs/eyeq5_defconfig create mode 100644 arch/mips/mobileye/Makefile create mode 100644 arch/mips/mobileye/Platform create mode 100644 arch/mips/mobileye/board-epm5.its.S create mode 100644 arch/mips/mobileye/vmlinux.its.S diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index a2311c4bce6a..5c145b67d3bf 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -17,6 +17,7 @@ platform-$(CONFIG_MACH_LOONGSON2EF) += loongson2ef/ platform-$(CONFIG_MACH_LOONGSON32) += loongson32/ platform-$(CONFIG_MACH_LOONGSON64) += loongson64/ platform-$(CONFIG_MIPS_MALTA) += mti-malta/ +platform-$(CONFIG_MACH_EYEQ5) += mobileye/ platform-$(CONFIG_MACH_NINTENDO64) += n64/ platform-$(CONFIG_PIC32MZDA) += pic32/ platform-$(CONFIG_RALINK) += ralink/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 04765463980a..aa9b0ac649f6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -571,6 +571,59 @@ config MACH_PIC32 Microchip PIC32 is a family of general-purpose 32 bit MIPS core microcontrollers. +config MACH_EYEQ5 + bool "Mobileye EyeQ5 SoC" + select MACH_GENERIC_CORE + select ARM_AMBA + select PHYSICAL_START_BOOL + select ARCH_SPARSEMEM_DEFAULT if 64BIT + select BOOT_RAW + select BUILTIN_DTB + select CEVT_R4K + select CLKSRC_MIPS_GIC + select COMMON_CLK + select CPU_MIPSR2_IRQ_EI + select CPU_MIPSR2_IRQ_VI + select CSRC_R4K + select DMA_NONCOHERENT + select HAVE_PCI + select IRQ_MIPS_CPU + select MIPS_AUTO_PFN_OFFSET + select MIPS_CPU_SCACHE + select MIPS_GIC + select MIPS_L1_CACHE_SHIFT_7 + select PCI_DRIVERS_GENERIC + select SMP_UP if SMP + select SWAP_IO_SPACE + select SYS_HAS_CPU_MIPS64_R6 + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_HIGHMEM + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_RELOCATABLE + select SYS_SUPPORTS_ZBOOT + select UHI_BOOT + select USB_EHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN + select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN + select USE_OF + help + Select this to build a kernel supporting EyeQ5 SoC from Mobileye. + + bool + +config FIT_IMAGE_FDT_EPM5 + bool "Include FDT for Mobileye EyeQ5 development platforms" + depends on MACH_EYEQ5 + default n + help + Enable this to include the FDT for the EyeQ5 development platforms + from Mobileye in the FIT kernel image. + This requires u-boot on the platform. + config MACH_NINTENDO64 bool "Nintendo 64 console" select CEVT_R4K diff --git a/arch/mips/configs/eyeq5_defconfig b/arch/mips/configs/eyeq5_defconfig new file mode 100644 index 000000000000..c35c29a4d479 --- /dev/null +++ b/arch/mips/configs/eyeq5_defconfig @@ -0,0 +1,108 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_TASKSTATS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_MACH_EYEQ5=y +CONFIG_FIT_IMAGE_FDT_EPM5=y +CONFIG_PAGE_SIZE_16KB=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_NR_CPUS=16 +CONFIG_MIPS_RAW_APPENDED_DTB=y +CONFIG_JUMP_LABEL=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_TRIM_UNUSED_KSYMS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_USERFAULTFD=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETFILTER=y +CONFIG_CAN=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_ENDPOINT=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_SCSI=y +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=y +CONFIG_IPVLAN=y +CONFIG_MACB=y +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_CAN_M_CAN=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_HW_RANDOM=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_PINCTRL=y +CONFIG_MFD_SYSCON=y +CONFIG_HID_A4TECH=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_ITE=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_REDRAGON=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_NVMEM is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_CRYPTO_CRC32_MIPS=y +CONFIG_FRAME_WARN=1024 +CONFIG_DEBUG_FS=y +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" diff --git a/arch/mips/mobileye/Makefile b/arch/mips/mobileye/Makefile new file mode 100644 index 000000000000..315c06b689cf --- /dev/null +++ b/arch/mips/mobileye/Makefile @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-or-later diff --git a/arch/mips/mobileye/Platform b/arch/mips/mobileye/Platform new file mode 100644 index 000000000000..c69f811dd13a --- /dev/null +++ b/arch/mips/mobileye/Platform @@ -0,0 +1,15 @@ +# +# Copyright (C) 2016 Imagination Technologies +# Author: Paul Burton +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# + +load-$(CONFIG_MACH_EYEQ5) = 0xa800000808000000 +all-$(CONFIG_MACH_EYEQ5) += vmlinux.gz.itb + +its-y := vmlinux.its.S +its-$(CONFIG_FIT_IMAGE_FDT_EPM5) += board-epm5.its.S diff --git a/arch/mips/mobileye/board-epm5.its.S b/arch/mips/mobileye/board-epm5.its.S new file mode 100644 index 000000000000..08e8c4f183d6 --- /dev/null +++ b/arch/mips/mobileye/board-epm5.its.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/ { + images { + fdt-mobileye-epm5 { + description = "Mobileeye MP5 Device Tree"; + data = /incbin/("boot/dts/mobileye/eyeq5-epm5.dtb"); + type = "flat_dt"; + arch = "mips"; + compression = "none"; + hash { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "Mobileye EPM5 Linux kernel"; + kernel = "kernel"; + fdt = "fdt-mobileye-epm5"; + }; + }; +}; diff --git a/arch/mips/mobileye/vmlinux.its.S b/arch/mips/mobileye/vmlinux.its.S new file mode 100644 index 000000000000..3e254676540f --- /dev/null +++ b/arch/mips/mobileye/vmlinux.its.S @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/dts-v1/; + +/ { + description = KERNEL_NAME; + #address-cells = ; + + images { + kernel { + description = KERNEL_NAME; + data = /incbin/(VMLINUX_BINARY); + type = "kernel"; + arch = "mips"; + os = "linux"; + compression = VMLINUX_COMPRESSION; + load = /bits/ ADDR_BITS ; + entry = /bits/ ADDR_BITS ; + hash { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf-default"; + + conf-default { + description = "Generic Linux kernel"; + kernel = "kernel"; + }; + }; +}; From f34158edd24995203412cc950d1882a626c5ad65 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 16 Feb 2024 18:42:23 +0100 Subject: [PATCH 386/814] MAINTAINERS: Add entry for Mobileye MIPS SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Vlad, Théo and myself as co-maintainers for the Mobileye MIPS SoCs. Signed-off-by: Vladimir Kondratiev Signed-off-by: Théo Lebrun Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9ed4d3868539..d2cc66b92f5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14787,6 +14787,18 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/dvb-frontends/mn88473* +MOBILEYE MIPS SOCS +M: Vladimir Kondratiev +M: Gregory CLEMENT +M: Théo Lebrun +L: linux-mips@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/mips/mobileye.yaml +F: arch/mips/boot/dts/mobileye/ +F: arch/mips/configs/eyeq5_defconfig +F: arch/mips/mobileye/board-epm5.its.S +F: include/dt-bindings/soc/mobileye,eyeq5.h + MODULE SUPPORT M: Luis Chamberlain L: linux-modules@vger.kernel.org From e34813c2dac8cece48e4f8781f38479847e4e951 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 22 Nov 2023 20:04:52 +0300 Subject: [PATCH 387/814] MAINTAINERS: Add maintainer for MIPS Baikal-T1 platform code Add myself as a maintainer of the MIPS Baikal-T1 platform-specific drivers. The arch-code hasn't been submitted yet, but will be soon enough. Until then it's better to have the already available drivers marked as maintained. Signed-off-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d2cc66b92f5f..1c45074b4dce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14667,6 +14667,17 @@ F: arch/mips/ F: drivers/platform/mips/ F: include/dt-bindings/mips/ +MIPS BAIKAL-T1 PLATFORM +M: Serge Semin +L: linux-mips@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/bus/baikal,bt1-*.yaml +F: Documentation/devicetree/bindings/clock/baikal,bt1-*.yaml +F: drivers/bus/bt1-*.c +F: drivers/clk/baikal-t1/ +F: drivers/memory/bt1-l2-ctl.c +F: drivers/mtd/maps/physmap-bt1-rom.[ch] + MIPS BOSTON DEVELOPMENT BOARD M: Paul Burton L: linux-mips@vger.kernel.org From 5b7236c198a30d736a7664e26b09b5e3e8a914f4 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sat, 20 Jan 2024 14:34:43 +0100 Subject: [PATCH 388/814] MIPS: Alchemy: Use kcalloc() instead of kzalloc() As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the purpose specific kcalloc() function instead of the argument size * count in the kzalloc() function. Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/162 Signed-off-by: Erick Archer Reviewed-by: Gustavo A. R. Silva Signed-off-by: Thomas Bogendoerfer --- arch/mips/alchemy/common/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index c01be8c45271..6c8996e20a7d 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -771,7 +771,7 @@ static int __init alchemy_clk_init_fgens(int ctype) } id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; - a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL); + a = kcalloc(6, sizeof(*a), GFP_KERNEL); if (!a) return -ENOMEM; From 5033ad566016bb9c3ea45d62c0a2244a6eb8d610 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 28 Jan 2024 01:23:09 +0900 Subject: [PATCH 389/814] MIPS: move unselectable entries out of the "CPU type" choice Move the following entries out of the "CPU type" choice: - LOONGSON3_ENHANCEMENT - CPU_LOONGSON3_WORKAROUNDS - CPU_LOONGSON3_CPUCFG_EMULATION These entries cannot be selected from the choice because they depend on CPU_LOONGSON64, which is also located in the same choice. In fact, Kconfig does not consider them as choice values because they become children of CPU_LOOONGSON64 due to the automatic submenu creation in menu_finalize(). However, it is hard to understand this behavior unless you are familiar with the Kconfig internals. "choice" should contain only selectable entries. Signed-off-by: Masahiro Yamada Reviewed-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 76 +++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index aa9b0ac649f6..492d7b900929 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1328,44 +1328,6 @@ config CPU_LOONGSON64 3B1000, 3B1500, 3A2000, 3A3000 and 3A4000) processors. However, old Loongson-2E/2F is not covered here and will be removed in future. -config LOONGSON3_ENHANCEMENT - bool "New Loongson-3 CPU Enhancements" - default n - depends on CPU_LOONGSON64 - help - New Loongson-3 cores (since Loongson-3A R2, as opposed to Loongson-3A - R1, Loongson-3B R1 and Loongson-3B R2) has many enhancements, such as - FTLB, L1-VCache, EI/DI/Wait/Prefetch instruction, DSP/DSPr2 ASE, User - Local register, Read-Inhibit/Execute-Inhibit, SFB (Store Fill Buffer), - Fast TLB refill support, etc. - - This option enable those enhancements which are not probed at run - time. If you want a generic kernel to run on all Loongson 3 machines, - please say 'N' here. If you want a high-performance kernel to run on - new Loongson-3 machines only, please say 'Y' here. - -config CPU_LOONGSON3_WORKAROUNDS - bool "Loongson-3 LLSC Workarounds" - default y if SMP - depends on CPU_LOONGSON64 - help - Loongson-3 processors have the llsc issues which require workarounds. - Without workarounds the system may hang unexpectedly. - - Say Y, unless you know what you are doing. - -config CPU_LOONGSON3_CPUCFG_EMULATION - bool "Emulate the CPUCFG instruction on older Loongson cores" - default y - depends on CPU_LOONGSON64 - help - Loongson-3A R4 and newer have the CPUCFG instruction available for - userland to query CPU capabilities, much like CPUID on x86. This - option provides emulation of the instruction on older Loongson - cores, back to Loongson-3A1000. - - If unsure, please say Y. - config CPU_LOONGSON2E bool "Loongson 2E" depends on SYS_HAS_CPU_LOONGSON2E @@ -1703,6 +1665,44 @@ config CPU_BMIPS endchoice +config LOONGSON3_ENHANCEMENT + bool "New Loongson-3 CPU Enhancements" + default n + depends on CPU_LOONGSON64 + help + New Loongson-3 cores (since Loongson-3A R2, as opposed to Loongson-3A + R1, Loongson-3B R1 and Loongson-3B R2) has many enhancements, such as + FTLB, L1-VCache, EI/DI/Wait/Prefetch instruction, DSP/DSPr2 ASE, User + Local register, Read-Inhibit/Execute-Inhibit, SFB (Store Fill Buffer), + Fast TLB refill support, etc. + + This option enable those enhancements which are not probed at run + time. If you want a generic kernel to run on all Loongson 3 machines, + please say 'N' here. If you want a high-performance kernel to run on + new Loongson-3 machines only, please say 'Y' here. + +config CPU_LOONGSON3_WORKAROUNDS + bool "Loongson-3 LLSC Workarounds" + default y if SMP + depends on CPU_LOONGSON64 + help + Loongson-3 processors have the llsc issues which require workarounds. + Without workarounds the system may hang unexpectedly. + + Say Y, unless you know what you are doing. + +config CPU_LOONGSON3_CPUCFG_EMULATION + bool "Emulate the CPUCFG instruction on older Loongson cores" + default y + depends on CPU_LOONGSON64 + help + Loongson-3A R4 and newer have the CPUCFG instruction available for + userland to query CPU capabilities, much like CPUID on x86. This + option provides emulation of the instruction on older Loongson + cores, back to Loongson-3A1000. + + If unsure, please say Y. + config CPU_MIPS32_3_5_FEATURES bool "MIPS32 Release 3.5 Features" depends on SYS_HAS_CPU_MIPS32_R3_5 From fa494c0190170644f26ece25826d32e821450081 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 12:06:57 -0300 Subject: [PATCH 390/814] mips: sgi-ip22: make gio_bus_type const Now that the driver core can properly handle constant struct bus_type, move the gio_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Signed-off-by: Thomas Bogendoerfer --- arch/mips/sgi-ip22/ip22-gio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c index 81c9f0a8880b..a3cdcb289941 100644 --- a/arch/mips/sgi-ip22/ip22-gio.c +++ b/arch/mips/sgi-ip22/ip22-gio.c @@ -12,7 +12,7 @@ #include #include -static struct bus_type gio_bus_type; +static const struct bus_type gio_bus_type; static struct { const char *name; @@ -378,7 +378,7 @@ static void ip22_check_gio(int slotno, unsigned long addr, int irq) printk(KERN_INFO "GIO: slot %d : Empty\n", slotno); } -static struct bus_type gio_bus_type = { +static const struct bus_type gio_bus_type = { .name = "gio", .dev_groups = gio_dev_groups, .match = gio_bus_match, From 1003a1adf493074bf7ba2d8075d87aa0ae73f69b Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 12:06:58 -0300 Subject: [PATCH 391/814] mips: txx9: make txx9_sramc_subsys const Now that the driver core can properly handle constant struct bus_type, move the txx9_sramc_subsys variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Signed-off-by: Thomas Bogendoerfer --- arch/mips/txx9/generic/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index b098a3c76ae9..1e67fecd466e 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -762,7 +762,7 @@ void __init txx9_aclc_init(unsigned long baseaddr, int irq, { } -static struct bus_type txx9_sramc_subsys = { +static const struct bus_type txx9_sramc_subsys = { .name = "txx9_sram", .dev_name = "txx9_sram", }; From aaf2230036b709f979caccfbaa7a8bf671c22124 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:45:25 -0300 Subject: [PATCH 392/814] tc: make tc_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the tc_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Acked-by: Maciej W. Rozycki Reviewed-by: Greg Kroah-Hartman Signed-off-by: Thomas Bogendoerfer --- drivers/tc/tc-driver.c | 2 +- include/linux/tc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c index d45f2c1ff341..1c9d983a5a1f 100644 --- a/drivers/tc/tc-driver.c +++ b/drivers/tc/tc-driver.c @@ -95,7 +95,7 @@ static int tc_bus_match(struct device *dev, struct device_driver *drv) return 0; } -struct bus_type tc_bus_type = { +const struct bus_type tc_bus_type = { .name = "tc", .match = tc_bus_match, }; diff --git a/include/linux/tc.h b/include/linux/tc.h index a60639f37963..1638660abf5e 100644 --- a/include/linux/tc.h +++ b/include/linux/tc.h @@ -120,7 +120,7 @@ static inline unsigned long tc_get_speed(struct tc_bus *tbus) #ifdef CONFIG_TC -extern struct bus_type tc_bus_type; +extern const struct bus_type tc_bus_type; extern int tc_register_driver(struct tc_driver *tdrv); extern void tc_unregister_driver(struct tc_driver *tdrv); From eac95d5ae4f872201f6da274af1cd372970af521 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:49:24 -0300 Subject: [PATCH 393/814] mips: bus: make mips_cdmm_bustype const Now that the driver core can properly handle constant struct bus_type, move the mips_cdmm_bustype variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Tested-by: Serge Semin Acked-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cdmm.h | 2 +- drivers/bus/mips_cdmm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/cdmm.h b/arch/mips/include/asm/cdmm.h index c06dbf8ba937..81fa99084178 100644 --- a/arch/mips/include/asm/cdmm.h +++ b/arch/mips/include/asm/cdmm.h @@ -63,7 +63,7 @@ struct mips_cdmm_driver { */ phys_addr_t mips_cdmm_phys_base(void); -extern struct bus_type mips_cdmm_bustype; +extern const struct bus_type mips_cdmm_bustype; void __iomem *mips_cdmm_early_probe(unsigned int dev_type); #define to_mips_cdmm_device(d) container_of(d, struct mips_cdmm_device, dev) diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index 554e1992edd4..8baf14bd5eff 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -118,7 +118,7 @@ static struct attribute *mips_cdmm_dev_attrs[] = { }; ATTRIBUTE_GROUPS(mips_cdmm_dev); -struct bus_type mips_cdmm_bustype = { +const struct bus_type mips_cdmm_bustype = { .name = "cdmm", .dev_groups = mips_cdmm_dev_groups, .match = mips_cdmm_match, From 075dd2eef02523067bf93f598e9e6e0aa3227dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 8 Feb 2024 14:09:56 +0200 Subject: [PATCH 394/814] MIPS: lantiq: Remove unused function pointer variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since introduction in the commit e47d488935ed ("MIPS: Lantiq: Add PCI controller support.") ltqpci_plat_dev_init has been unused. In 57c8cb8f2429 ("MIPS: pci: convert lantiq driver to OF") also ltq_pci_plat_arch_init was introduced. With those commit being more than 10 years ago, it seem neither is going to get used anytime soon. Thus, remove both unused function pointer variables. Signed-off-by: Ilpo Järvinen Reviewed-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/fixup-lantiq.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c index 13009666204f..8bcc136976dc 100644 --- a/arch/mips/pci/fixup-lantiq.c +++ b/arch/mips/pci/fixup-lantiq.c @@ -7,17 +7,8 @@ #include #include -int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL; -int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL; - int pcibios_plat_dev_init(struct pci_dev *dev) { - if (ltq_pci_plat_arch_init) - return ltq_pci_plat_arch_init(dev); - - if (ltq_pci_plat_dev_init) - return ltq_pci_plat_dev_init(dev); - return 0; } From 10e51ebcef8276e22ab04d6d1653caba43916fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 8 Feb 2024 14:09:57 +0200 Subject: [PATCH 395/814] MIPS: ath79: Don't return PCIBIOS_* code from pcibios_enable_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcibios_plat_dev_init() is called from pcibios_enable_device() that should return normal errnos, not PCIBIOS return codes. In this case the impact is only cosmetic because PCIBIOS_SUCCESSFUL equals 0 that is success code with errnos as well. Nonetheless, remove the inconsistency by replacing the PCIBIOS_SUCCESSFUL with 0. Signed-off-by: Ilpo Järvinen Reviewed-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/fixup-ath79.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/pci/fixup-ath79.c b/arch/mips/pci/fixup-ath79.c index 09a4ce53424f..6a6c4f58f7f4 100644 --- a/arch/mips/pci/fixup-ath79.c +++ b/arch/mips/pci/fixup-ath79.c @@ -9,7 +9,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) { - return PCIBIOS_SUCCESSFUL; + return 0; } int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) From 923cfd0813377e809b91694f3f05a8c04c55517c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 8 Feb 2024 14:09:58 +0200 Subject: [PATCH 396/814] MIPS: PCI: Return PCIBIOS_* from tx4927_pci_config_read/write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_ops .read/.write must return PCIBIOS_* codes but tx4927_pci_config_read/write() return -1 when mkaddr() cannot find devfn from the root bus. Return PCIBIOS_DEVICE_NOT_FOUND instead and pass that onward in the call chain instead of overwriting the return value. Also converts 0 -> PCIBIOS_SUCCESSFUL which has only cosmetic impact. Signed-off-by: Ilpo Järvinen Reviewed-by: Sergio Paracuellos Reviewed-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/ops-tx4927.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index f7802f100401..670efbc5c585 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c @@ -60,7 +60,7 @@ static int mkaddr(struct pci_bus *bus, unsigned int devfn, int where, { if (bus->parent == NULL && devfn >= PCI_DEVFN(TX4927_PCIC_MAX_DEVNU, 0)) - return -1; + return PCIBIOS_DEVICE_NOT_FOUND; __raw_writel(((bus->number & 0xff) << 0x10) | ((devfn & 0xff) << 0x08) | (where & 0xfc) | (bus->parent ? 1 : 0), @@ -69,7 +69,7 @@ static int mkaddr(struct pci_bus *bus, unsigned int devfn, int where, __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT << 16), &pcicptr->pcistatus); - return 0; + return PCIBIOS_SUCCESSFUL; } static int check_abort(struct tx4927_pcic_reg __iomem *pcicptr) @@ -140,10 +140,12 @@ static int tx4927_pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus); + int ret; - if (mkaddr(bus, devfn, where, pcicptr)) { + ret = mkaddr(bus, devfn, where, pcicptr); + if (ret != PCIBIOS_SUCCESSFUL) { *val = 0xffffffff; - return -1; + return ret; } switch (size) { case 1: @@ -162,9 +164,11 @@ static int tx4927_pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus); + int ret; - if (mkaddr(bus, devfn, where, pcicptr)) - return -1; + ret = mkaddr(bus, devfn, where, pcicptr); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; switch (size) { case 1: icd_writeb(val, where & 3, pcicptr); From 3c35da51f77e45f345b229df4b3adebad82ce4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 8 Feb 2024 14:09:59 +0200 Subject: [PATCH 397/814] MIPS: TXx9: Use PCI_SET_ERROR_RESPONSE() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of literal, PCI error value should be set with PCI_SET_ERROR_RESPONSE(). Use it in tx4927_pci_config_read(). Signed-off-by: Ilpo Järvinen Reviewed-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/ops-tx4927.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index 670efbc5c585..37087f4137ee 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c @@ -144,7 +144,7 @@ static int tx4927_pci_config_read(struct pci_bus *bus, unsigned int devfn, ret = mkaddr(bus, devfn, where, pcicptr); if (ret != PCIBIOS_SUCCESSFUL) { - *val = 0xffffffff; + PCI_SET_ERROR_RESPONSE(val); return ret; } switch (size) { From f39b80e3ff12ced77dddcacd28b4af878cac1433 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:28:56 +0000 Subject: [PATCH 398/814] KVM: pfncache: Add a map helper function There is a pfncache unmap helper but mapping is open-coded. Arguably this is fine because mapping is done in only one place, hva_to_pfn_retry(), but adding the helper does make that function more readable. No functional change intended. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-2-paul@xen.org Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 49 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 2d6aba677830..10842f1eeeae 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -96,17 +96,32 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) } EXPORT_SYMBOL_GPL(kvm_gpc_check); -static void gpc_unmap_khva(kvm_pfn_t pfn, void *khva) +static void *gpc_map(kvm_pfn_t pfn) +{ + if (pfn_valid(pfn)) + return kmap(pfn_to_page(pfn)); + +#ifdef CONFIG_HAS_IOMEM + return memremap(pfn_to_hpa(pfn), PAGE_SIZE, MEMREMAP_WB); +#else + return NULL; +#endif +} + +static void gpc_unmap(kvm_pfn_t pfn, void *khva) { /* Unmap the old pfn/page if it was mapped before. */ - if (!is_error_noslot_pfn(pfn) && khva) { - if (pfn_valid(pfn)) - kunmap(pfn_to_page(pfn)); -#ifdef CONFIG_HAS_IOMEM - else - memunmap(khva); -#endif + if (is_error_noslot_pfn(pfn) || !khva) + return; + + if (pfn_valid(pfn)) { + kunmap(pfn_to_page(pfn)); + return; } + +#ifdef CONFIG_HAS_IOMEM + memunmap(khva); +#endif } static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_seq) @@ -175,7 +190,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) * the existing mapping and didn't create a new one. */ if (new_khva != old_khva) - gpc_unmap_khva(new_pfn, new_khva); + gpc_unmap(new_pfn, new_khva); kvm_release_pfn_clean(new_pfn); @@ -193,15 +208,11 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) * too must be done outside of gpc->lock! */ if (gpc->usage & KVM_HOST_USES_PFN) { - if (new_pfn == gpc->pfn) { + if (new_pfn == gpc->pfn) new_khva = old_khva; - } else if (pfn_valid(new_pfn)) { - new_khva = kmap(pfn_to_page(new_pfn)); -#ifdef CONFIG_HAS_IOMEM - } else { - new_khva = memremap(pfn_to_hpa(new_pfn), PAGE_SIZE, MEMREMAP_WB); -#endif - } + else + new_khva = gpc_map(new_pfn); + if (!new_khva) { kvm_release_pfn_clean(new_pfn); goto out_error; @@ -326,7 +337,7 @@ out_unlock: mutex_unlock(&gpc->refresh_lock); if (unmap_old) - gpc_unmap_khva(old_pfn, old_khva); + gpc_unmap(old_pfn, old_khva); return ret; } @@ -412,7 +423,7 @@ void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) list_del(&gpc->list); spin_unlock(&kvm->gpc_lock); - gpc_unmap_khva(old_pfn, old_khva); + gpc_unmap(old_pfn, old_khva); } } EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); From 41496fffc0e1276e1c41344ef38513d5353da3ca Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:28:57 +0000 Subject: [PATCH 399/814] KVM: pfncache: remove unnecessary exports There is no need for the existing kvm_gpc_XXX() functions to be exported. Clean up now before additional functions are added in subsequent patches. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-3-paul@xen.org Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 10842f1eeeae..f3571f44d9af 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -94,7 +94,6 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) return true; } -EXPORT_SYMBOL_GPL(kvm_gpc_check); static void *gpc_map(kvm_pfn_t pfn) { @@ -346,7 +345,6 @@ int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, unsigned long len) { return __kvm_gpc_refresh(gpc, gpc->gpa, len); } -EXPORT_SYMBOL_GPL(kvm_gpc_refresh); void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, struct kvm_vcpu *vcpu, enum pfn_cache_usage usage) @@ -363,7 +361,6 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, gpc->pfn = KVM_PFN_ERR_FAULT; gpc->uhva = KVM_HVA_ERR_BAD; } -EXPORT_SYMBOL_GPL(kvm_gpc_init); int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) { @@ -388,7 +385,6 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) } return __kvm_gpc_refresh(gpc, gpa, len); } -EXPORT_SYMBOL_GPL(kvm_gpc_activate); void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) { @@ -426,4 +422,3 @@ void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) gpc_unmap(old_pfn, old_khva); } } -EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); From 4438355ec6e165f73357203e0792079dec9e3059 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:28:58 +0000 Subject: [PATCH 400/814] KVM: x86/xen: mark guest pages dirty with the pfncache lock held Sampling gpa and memslot from an unlocked pfncache may yield inconsistent values so, since there is no problem with calling mark_page_dirty_in_slot() with the pfncache lock held, relocate the calls in kvm_xen_update_runstate_guest() and kvm_xen_inject_pending_events() accordingly. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-4-paul@xen.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 4b4e738c6f1b..f3327508ae41 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -452,14 +452,13 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic) smp_wmb(); } - if (user_len2) + if (user_len2) { + mark_page_dirty_in_slot(v->kvm, gpc2->memslot, gpc2->gpa >> PAGE_SHIFT); read_unlock(&gpc2->lock); - - read_unlock_irqrestore(&gpc1->lock, flags); + } mark_page_dirty_in_slot(v->kvm, gpc1->memslot, gpc1->gpa >> PAGE_SHIFT); - if (user_len2) - mark_page_dirty_in_slot(v->kvm, gpc2->memslot, gpc2->gpa >> PAGE_SHIFT); + read_unlock_irqrestore(&gpc1->lock, flags); } void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) @@ -565,13 +564,13 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) : "0" (evtchn_pending_sel32)); WRITE_ONCE(vi->evtchn_upcall_pending, 1); } + + mark_page_dirty_in_slot(v->kvm, gpc->memslot, gpc->gpa >> PAGE_SHIFT); read_unlock_irqrestore(&gpc->lock, flags); /* For the per-vCPU lapic vector, deliver it as MSI. */ if (v->arch.xen.upcall_vector) kvm_xen_inject_vcpu_vector(v); - - mark_page_dirty_in_slot(v->kvm, gpc->memslot, gpc->gpa >> PAGE_SHIFT); } int __kvm_xen_has_interrupt(struct kvm_vcpu *v) From 78b74638eb6dffd9b24bc3b121556a9039292df6 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:28:59 +0000 Subject: [PATCH 401/814] KVM: pfncache: add a mark-dirty helper At the moment pages are marked dirty by open-coded calls to mark_page_dirty_in_slot(), directly deferefencing the gpa and memslot from the cache. After a subsequent patch these may not always be set so add a helper now so that caller will protected from the need to know about this detail. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-5-paul@xen.org [sean: decrease indentation, use gpa_to_gfn()] Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 2 +- arch/x86/kvm/xen.c | 6 +++--- include/linux/kvm_host.h | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bf10a9073a09..f0f37c769a3a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3160,7 +3160,7 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu *v, guest_hv_clock->version = ++vcpu->hv_clock.version; - mark_page_dirty_in_slot(v->kvm, gpc->memslot, gpc->gpa >> PAGE_SHIFT); + kvm_gpc_mark_dirty_in_slot(gpc); read_unlock_irqrestore(&gpc->lock, flags); trace_kvm_pvclock_update(v->vcpu_id, &vcpu->hv_clock); diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index f3327508ae41..2d001a9c6378 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -453,11 +453,11 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic) } if (user_len2) { - mark_page_dirty_in_slot(v->kvm, gpc2->memslot, gpc2->gpa >> PAGE_SHIFT); + kvm_gpc_mark_dirty_in_slot(gpc2); read_unlock(&gpc2->lock); } - mark_page_dirty_in_slot(v->kvm, gpc1->memslot, gpc1->gpa >> PAGE_SHIFT); + kvm_gpc_mark_dirty_in_slot(gpc1); read_unlock_irqrestore(&gpc1->lock, flags); } @@ -565,7 +565,7 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) WRITE_ONCE(vi->evtchn_upcall_pending, 1); } - mark_page_dirty_in_slot(v->kvm, gpc->memslot, gpc->gpa >> PAGE_SHIFT); + kvm_gpc_mark_dirty_in_slot(gpc); read_unlock_irqrestore(&gpc->lock, flags); /* For the per-vCPU lapic vector, deliver it as MSI. */ diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7e7fd25b09b3..604ae285d9a9 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1795,6 +1795,16 @@ static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa) return kvm_is_error_hva(hva); } +static inline void kvm_gpc_mark_dirty_in_slot(struct gfn_to_pfn_cache *gpc) +{ + lockdep_assert_held(&gpc->lock); + + if (!gpc->memslot) + return; + + mark_page_dirty_in_slot(gpc->kvm, gpc->memslot, gpa_to_gfn(gpc->gpa)); +} + enum kvm_stat_kind { KVM_STAT_VM, KVM_STAT_VCPU, From a4bff3df51472f555ab8dea05a3d2faf4abbf199 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:00 +0000 Subject: [PATCH 402/814] KVM: pfncache: remove KVM_GUEST_USES_PFN usage As noted in [1] the KVM_GUEST_USES_PFN usage flag is never set by any callers of kvm_gpc_init(), and for good reason: the implementation is incomplete/broken. And it's not clear that there will ever be a user of KVM_GUEST_USES_PFN, as coordinating vCPUs with mmu_notifier events is non-trivial. Remove KVM_GUEST_USES_PFN and all related code, e.g. dropping KVM_GUEST_USES_PFN also makes the 'vcpu' argument redundant, to avoid having to reason about broken code as __kvm_gpc_refresh() evolves. Moreover, all existing callers specify KVM_HOST_USES_PFN so the usage check in hva_to_pfn_retry() and hence the 'usage' argument to kvm_gpc_init() are also redundant. [1] https://lore.kernel.org/all/ZQiR8IpqOZrOpzHC@google.com Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-6-paul@xen.org [sean: explicitly call out that guest usage is incomplete] Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 2 +- arch/x86/kvm/xen.c | 14 ++++------ include/linux/kvm_host.h | 11 +------- include/linux/kvm_types.h | 8 ------ virt/kvm/pfncache.c | 59 ++++++--------------------------------- 5 files changed, 15 insertions(+), 79 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f0f37c769a3a..415723a28dce 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12056,7 +12056,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.regs_avail = ~0; vcpu->arch.regs_dirty = ~0; - kvm_gpc_init(&vcpu->arch.pv_time, vcpu->kvm, vcpu, KVM_HOST_USES_PFN); + kvm_gpc_init(&vcpu->arch.pv_time, vcpu->kvm); if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu)) vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 2d001a9c6378..e90464225467 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -2108,14 +2108,10 @@ void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu) timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0); - kvm_gpc_init(&vcpu->arch.xen.runstate_cache, vcpu->kvm, NULL, - KVM_HOST_USES_PFN); - kvm_gpc_init(&vcpu->arch.xen.runstate2_cache, vcpu->kvm, NULL, - KVM_HOST_USES_PFN); - kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache, vcpu->kvm, NULL, - KVM_HOST_USES_PFN); - kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache, vcpu->kvm, NULL, - KVM_HOST_USES_PFN); + kvm_gpc_init(&vcpu->arch.xen.runstate_cache, vcpu->kvm); + kvm_gpc_init(&vcpu->arch.xen.runstate2_cache, vcpu->kvm); + kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache, vcpu->kvm); + kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache, vcpu->kvm); } void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) @@ -2158,7 +2154,7 @@ void kvm_xen_init_vm(struct kvm *kvm) { mutex_init(&kvm->arch.xen.xen_lock); idr_init(&kvm->arch.xen.evtchn_ports); - kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm, NULL, KVM_HOST_USES_PFN); + kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm); } void kvm_xen_destroy_vm(struct kvm *kvm) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 604ae285d9a9..3e1c04608c67 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1319,21 +1319,12 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn); * * @gpc: struct gfn_to_pfn_cache object. * @kvm: pointer to kvm instance. - * @vcpu: vCPU to be used for marking pages dirty and to be woken on - * invalidation. - * @usage: indicates if the resulting host physical PFN is used while - * the @vcpu is IN_GUEST_MODE (in which case invalidation of - * the cache from MMU notifiers---but not for KVM memslot - * changes!---will also force @vcpu to exit the guest and - * refresh the cache); and/or if the PFN used directly - * by KVM (and thus needs a kernel virtual mapping). * * This sets up a gfn_to_pfn_cache by initializing locks and assigning the * immutable attributes. Note, the cache must be zero-allocated (or zeroed by * the caller before init). */ -void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage); +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm); /** * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given guest diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index 9d1f7835d8c1..d93f6522b2c3 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -49,12 +49,6 @@ typedef u64 hfn_t; typedef hfn_t kvm_pfn_t; -enum pfn_cache_usage { - KVM_GUEST_USES_PFN = BIT(0), - KVM_HOST_USES_PFN = BIT(1), - KVM_GUEST_AND_HOST_USE_PFN = KVM_GUEST_USES_PFN | KVM_HOST_USES_PFN, -}; - struct gfn_to_hva_cache { u64 generation; gpa_t gpa; @@ -69,13 +63,11 @@ struct gfn_to_pfn_cache { unsigned long uhva; struct kvm_memory_slot *memslot; struct kvm *kvm; - struct kvm_vcpu *vcpu; struct list_head list; rwlock_t lock; struct mutex refresh_lock; void *khva; kvm_pfn_t pfn; - enum pfn_cache_usage usage; bool active; bool valid; }; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index f3571f44d9af..6f4b537eb25b 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -25,9 +25,7 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start, unsigned long end, bool may_block) { - DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS); struct gfn_to_pfn_cache *gpc; - bool evict_vcpus = false; spin_lock(&kvm->gpc_lock); list_for_each_entry(gpc, &kvm->gpc_list, list) { @@ -37,43 +35,10 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start, if (gpc->valid && !is_error_noslot_pfn(gpc->pfn) && gpc->uhva >= start && gpc->uhva < end) { gpc->valid = false; - - /* - * If a guest vCPU could be using the physical address, - * it needs to be forced out of guest mode. - */ - if (gpc->usage & KVM_GUEST_USES_PFN) { - if (!evict_vcpus) { - evict_vcpus = true; - bitmap_zero(vcpu_bitmap, KVM_MAX_VCPUS); - } - __set_bit(gpc->vcpu->vcpu_idx, vcpu_bitmap); - } } write_unlock_irq(&gpc->lock); } spin_unlock(&kvm->gpc_lock); - - if (evict_vcpus) { - /* - * KVM needs to ensure the vCPU is fully out of guest context - * before allowing the invalidation to continue. - */ - unsigned int req = KVM_REQ_OUTSIDE_GUEST_MODE; - bool called; - - /* - * If the OOM reaper is active, then all vCPUs should have - * been stopped already, so perform the request without - * KVM_REQUEST_WAIT and be sad if any needed to be IPI'd. - */ - if (!may_block) - req &= ~KVM_REQUEST_WAIT; - - called = kvm_make_vcpus_request_mask(kvm, req, vcpu_bitmap); - - WARN_ON_ONCE(called && !may_block); - } } bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) @@ -206,16 +171,14 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) * pfn. Note, kmap() and memremap() can both sleep, so this * too must be done outside of gpc->lock! */ - if (gpc->usage & KVM_HOST_USES_PFN) { - if (new_pfn == gpc->pfn) - new_khva = old_khva; - else - new_khva = gpc_map(new_pfn); + if (new_pfn == gpc->pfn) + new_khva = old_khva; + else + new_khva = gpc_map(new_pfn); - if (!new_khva) { - kvm_release_pfn_clean(new_pfn); - goto out_error; - } + if (!new_khva) { + kvm_release_pfn_clean(new_pfn); + goto out_error; } write_lock_irq(&gpc->lock); @@ -346,18 +309,12 @@ int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, unsigned long len) return __kvm_gpc_refresh(gpc, gpc->gpa, len); } -void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage) +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm) { - WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) != usage); - WARN_ON_ONCE((usage & KVM_GUEST_USES_PFN) && !vcpu); - rwlock_init(&gpc->lock); mutex_init(&gpc->refresh_lock); gpc->kvm = kvm; - gpc->vcpu = vcpu; - gpc->usage = usage; gpc->pfn = KVM_PFN_ERR_FAULT; gpc->uhva = KVM_HVA_ERR_BAD; } From 53e63e953e14a66b7d0d7e9c616cd602f3da9291 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:01 +0000 Subject: [PATCH 403/814] KVM: pfncache: stop open-coding offset_in_page() Some code in pfncache uses offset_in_page() but in other places it is open- coded. Use offset_in_page() consistently everywhere. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-7-paul@xen.org Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 6f4b537eb25b..0eeb034d0674 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -48,7 +48,7 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) if (!gpc->active) return false; - if ((gpc->gpa & ~PAGE_MASK) + len > PAGE_SIZE) + if (offset_in_page(gpc->gpa) + len > PAGE_SIZE) return false; if (gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) @@ -192,7 +192,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) gpc->valid = true; gpc->pfn = new_pfn; - gpc->khva = new_khva + (gpc->gpa & ~PAGE_MASK); + gpc->khva = new_khva + offset_in_page(gpc->gpa); /* * Put the reference to the _new_ pfn. The pfn is now tracked by the @@ -213,7 +213,7 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) { struct kvm_memslots *slots = kvm_memslots(gpc->kvm); - unsigned long page_offset = gpa & ~PAGE_MASK; + unsigned long page_offset = offset_in_page(gpa); bool unmap_old = false; unsigned long old_uhva; kvm_pfn_t old_pfn; From 406c10962a4cbb1e04aa7993ea466db1a4533ae4 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:02 +0000 Subject: [PATCH 404/814] KVM: pfncache: include page offset in uhva and use it consistently Currently the pfncache page offset is sometimes determined using the gpa and sometimes the khva, whilst the uhva is always page-aligned. After a subsequent patch is applied the gpa will not always be valid so adjust the code to include the page offset in the uhva and use it consistently as the source of truth. Also, where a page-aligned address is required, use PAGE_ALIGN_DOWN() for clarity. No functional change intended. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-8-paul@xen.org Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 0eeb034d0674..97eec8ee3449 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -48,10 +48,10 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) if (!gpc->active) return false; - if (offset_in_page(gpc->gpa) + len > PAGE_SIZE) + if (gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) return false; - if (gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) + if (offset_in_page(gpc->uhva) + len > PAGE_SIZE) return false; if (!gpc->valid) @@ -119,7 +119,7 @@ static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_s static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) { /* Note, the new page offset may be different than the old! */ - void *old_khva = gpc->khva - offset_in_page(gpc->khva); + void *old_khva = (void *)PAGE_ALIGN_DOWN((uintptr_t)gpc->khva); kvm_pfn_t new_pfn = KVM_PFN_ERR_FAULT; void *new_khva = NULL; unsigned long mmu_seq; @@ -192,7 +192,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) gpc->valid = true; gpc->pfn = new_pfn; - gpc->khva = new_khva + offset_in_page(gpc->gpa); + gpc->khva = new_khva + offset_in_page(gpc->uhva); /* * Put the reference to the _new_ pfn. The pfn is now tracked by the @@ -217,6 +217,7 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, bool unmap_old = false; unsigned long old_uhva; kvm_pfn_t old_pfn; + bool hva_change = false; void *old_khva; int ret; @@ -242,10 +243,10 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, } old_pfn = gpc->pfn; - old_khva = gpc->khva - offset_in_page(gpc->khva); - old_uhva = gpc->uhva; + old_khva = (void *)PAGE_ALIGN_DOWN((uintptr_t)gpc->khva); + old_uhva = PAGE_ALIGN_DOWN(gpc->uhva); - /* If the userspace HVA is invalid, refresh that first */ + /* Refresh the userspace HVA if necessary */ if (gpc->gpa != gpa || gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) { gfn_t gfn = gpa_to_gfn(gpa); @@ -259,13 +260,25 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, ret = -EFAULT; goto out; } + + /* + * Even if the GPA and/or the memslot generation changed, the + * HVA may still be the same. + */ + if (gpc->uhva != old_uhva) + hva_change = true; + } else { + gpc->uhva = old_uhva; } + /* Note: the offset must be correct before calling hva_to_pfn_retry() */ + gpc->uhva += page_offset; + /* * If the userspace HVA changed or the PFN was already invalid, * drop the lock and do the HVA to PFN lookup again. */ - if (!gpc->valid || old_uhva != gpc->uhva) { + if (!gpc->valid || hva_change) { ret = hva_to_pfn_retry(gpc); } else { /* From 9e7325acb3dc8df8a6370ebc18aef107aae17ef0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 15 Feb 2024 15:29:03 +0000 Subject: [PATCH 405/814] KVM: s390: Refactor kvm_is_error_gpa() into kvm_is_gpa_in_memslot() Rename kvm_is_error_gpa() to kvm_is_gpa_in_memslot() and invert the polarity accordingly in order to (a) free up kvm_is_error_gpa() to match with kvm_is_error_{hva,page}(), and (b) to make it more obvious that the helper is doing a memslot lookup, i.e. not simply checking for INVALID_GPA. No functional change intended. Link: https://lore.kernel.org/r/20240215152916.1158-9-paul@xen.org Signed-off-by: Sean Christopherson --- arch/s390/kvm/diag.c | 2 +- arch/s390/kvm/gaccess.c | 14 +++++++------- arch/s390/kvm/kvm-s390.c | 4 ++-- arch/s390/kvm/priv.c | 4 ++-- arch/s390/kvm/sigp.c | 2 +- include/linux/kvm_host.h | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 3c65b8258ae6..2a32438e09ce 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -102,7 +102,7 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu) parm.token_addr & 7 || parm.zarch != 0x8000000000000000ULL) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (kvm_is_error_gpa(vcpu->kvm, parm.token_addr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, parm.token_addr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); vcpu->arch.pfault_token = parm.token_addr; diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index 5bfcc50c1a68..415c99649e43 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -664,7 +664,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, case ASCE_TYPE_REGION1: { union region1_table_entry rfte; - if (kvm_is_error_gpa(vcpu->kvm, ptr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, ptr)) return PGM_ADDRESSING; if (deref_table(vcpu->kvm, ptr, &rfte.val)) return -EFAULT; @@ -682,7 +682,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, case ASCE_TYPE_REGION2: { union region2_table_entry rste; - if (kvm_is_error_gpa(vcpu->kvm, ptr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, ptr)) return PGM_ADDRESSING; if (deref_table(vcpu->kvm, ptr, &rste.val)) return -EFAULT; @@ -700,7 +700,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, case ASCE_TYPE_REGION3: { union region3_table_entry rtte; - if (kvm_is_error_gpa(vcpu->kvm, ptr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, ptr)) return PGM_ADDRESSING; if (deref_table(vcpu->kvm, ptr, &rtte.val)) return -EFAULT; @@ -728,7 +728,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, case ASCE_TYPE_SEGMENT: { union segment_table_entry ste; - if (kvm_is_error_gpa(vcpu->kvm, ptr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, ptr)) return PGM_ADDRESSING; if (deref_table(vcpu->kvm, ptr, &ste.val)) return -EFAULT; @@ -748,7 +748,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, ptr = ste.fc0.pto * (PAGE_SIZE / 2) + vaddr.px * 8; } } - if (kvm_is_error_gpa(vcpu->kvm, ptr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, ptr)) return PGM_ADDRESSING; if (deref_table(vcpu->kvm, ptr, &pte.val)) return -EFAULT; @@ -770,7 +770,7 @@ absolute_address: *prot = PROT_TYPE_IEP; return PGM_PROTECTION; } - if (kvm_is_error_gpa(vcpu->kvm, raddr.addr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, raddr.addr)) return PGM_ADDRESSING; *gpa = raddr.addr; return 0; @@ -957,7 +957,7 @@ static int guest_range_to_gpas(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, return rc; } else { gpa = kvm_s390_real_to_abs(vcpu, ga); - if (kvm_is_error_gpa(vcpu->kvm, gpa)) { + if (!kvm_is_gpa_in_memslot(vcpu->kvm, gpa)) { rc = PGM_ADDRESSING; prot = PROT_NONE; } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ea63ac769889..3e5a1d7aa81a 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2878,7 +2878,7 @@ static int kvm_s390_vm_mem_op_abs(struct kvm *kvm, struct kvm_s390_mem_op *mop) srcu_idx = srcu_read_lock(&kvm->srcu); - if (kvm_is_error_gpa(kvm, mop->gaddr)) { + if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) { r = PGM_ADDRESSING; goto out_unlock; } @@ -2940,7 +2940,7 @@ static int kvm_s390_vm_mem_op_cmpxchg(struct kvm *kvm, struct kvm_s390_mem_op *m srcu_idx = srcu_read_lock(&kvm->srcu); - if (kvm_is_error_gpa(kvm, mop->gaddr)) { + if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) { r = PGM_ADDRESSING; goto out_unlock; } diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index f875a404a0a0..1be19cc9d73c 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -149,7 +149,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu) * first page, since address is 8k aligned and memory pieces are always * at least 1MB aligned and have at least a size of 1MB. */ - if (kvm_is_error_gpa(vcpu->kvm, address)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, address)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); kvm_s390_set_prefix(vcpu, address); @@ -464,7 +464,7 @@ static int handle_test_block(struct kvm_vcpu *vcpu) return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); addr = kvm_s390_real_to_abs(vcpu, addr); - if (kvm_is_error_gpa(vcpu->kvm, addr)) + if (!kvm_is_gpa_in_memslot(vcpu->kvm, addr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); /* * We don't expect errors on modern systems, and do not care diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index d9696b530064..55c34cb35428 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -172,7 +172,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu, * first page, since address is 8k aligned and memory pieces are always * at least 1MB aligned and have at least a size of 1MB. */ - if (kvm_is_error_gpa(vcpu->kvm, irq.u.prefix.address)) { + if (!kvm_is_gpa_in_memslot(vcpu->kvm, irq.u.prefix.address)) { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_INVALID_PARAMETER; return SIGP_CC_STATUS_STORED; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3e1c04608c67..81a9d1cf91a2 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1779,11 +1779,11 @@ static inline hpa_t pfn_to_hpa(kvm_pfn_t pfn) return (hpa_t)pfn << PAGE_SHIFT; } -static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa) +static inline bool kvm_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa) { unsigned long hva = gfn_to_hva(kvm, gpa_to_gfn(gpa)); - return kvm_is_error_hva(hva); + return !kvm_is_error_hva(hva); } static inline void kvm_gpc_mark_dirty_in_slot(struct gfn_to_pfn_cache *gpc) From 721f5b0dda784829b833039fbb42f420b9f86575 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:04 +0000 Subject: [PATCH 406/814] KVM: pfncache: allow a cache to be activated with a fixed (userspace) HVA Some pfncache pages may actually be overlays on guest memory that have a fixed HVA within the VMM. It's pointless to invalidate such cached mappings if the overlay is moved so allow a cache to be activated directly with the HVA to cater for such cases. A subsequent patch will make use of this facility. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-10-paul@xen.org Signed-off-by: Sean Christopherson --- include/linux/kvm_host.h | 31 +++++++++++++ virt/kvm/pfncache.c | 98 ++++++++++++++++++++++++++++------------ 2 files changed, 101 insertions(+), 28 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 81a9d1cf91a2..fa070c36f98a 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -148,6 +148,11 @@ static inline bool kvm_is_error_hva(unsigned long addr) #endif +static inline bool kvm_is_error_gpa(gpa_t gpa) +{ + return gpa == INVALID_GPA; +} + #define KVM_ERR_PTR_BAD_PAGE (ERR_PTR(-ENOENT)) static inline bool is_error_page(struct page *page) @@ -1344,6 +1349,22 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm); */ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len); +/** + * kvm_gpc_activate_hva - prepare a cached kernel mapping and HPA for a given HVA. + * + * @gpc: struct gfn_to_pfn_cache object. + * @hva: userspace virtual address to map. + * @len: sanity check; the range being access must fit a single page. + * + * @return: 0 for success. + * -EINVAL for a mapping which would cross a page boundary. + * -EFAULT for an untranslatable guest physical address. + * + * The semantics of this function are the same as those of kvm_gpc_activate(). It + * merely bypasses a layer of address translation. + */ +int kvm_gpc_activate_hva(struct gfn_to_pfn_cache *gpc, unsigned long hva, unsigned long len); + /** * kvm_gpc_check - check validity of a gfn_to_pfn_cache. * @@ -1390,6 +1411,16 @@ int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, unsigned long len); */ void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc); +static inline bool kvm_gpc_is_gpa_active(struct gfn_to_pfn_cache *gpc) +{ + return gpc->active && !kvm_is_error_gpa(gpc->gpa); +} + +static inline bool kvm_gpc_is_hva_active(struct gfn_to_pfn_cache *gpc) +{ + return gpc->active && kvm_is_error_gpa(gpc->gpa); +} + void kvm_sigset_activate(struct kvm_vcpu *vcpu); void kvm_sigset_deactivate(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 97eec8ee3449..a47ca6fd75c2 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -48,7 +48,14 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) if (!gpc->active) return false; - if (gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) + /* + * If the page was cached from a memslot, make sure the memslots have + * not been re-configured. + */ + if (!kvm_is_error_gpa(gpc->gpa) && gpc->generation != slots->generation) + return false; + + if (kvm_is_error_hva(gpc->uhva)) return false; if (offset_in_page(gpc->uhva) + len > PAGE_SIZE) @@ -209,11 +216,10 @@ out_error: return -EFAULT; } -static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, +static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long uhva, unsigned long len) { - struct kvm_memslots *slots = kvm_memslots(gpc->kvm); - unsigned long page_offset = offset_in_page(gpa); + unsigned long page_offset; bool unmap_old = false; unsigned long old_uhva; kvm_pfn_t old_pfn; @@ -221,10 +227,16 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, void *old_khva; int ret; + /* Either gpa or uhva must be valid, but not both */ + if (WARN_ON_ONCE(kvm_is_error_gpa(gpa) == kvm_is_error_hva(uhva))) + return -EINVAL; + /* - * If must fit within a single page. The 'len' argument is - * only to enforce that. + * The cached acces must fit within a single page. The 'len' argument + * exists only to enforce that. */ + page_offset = kvm_is_error_gpa(gpa) ? offset_in_page(uhva) : + offset_in_page(gpa); if (page_offset + len > PAGE_SIZE) return -EINVAL; @@ -246,29 +258,39 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, old_khva = (void *)PAGE_ALIGN_DOWN((uintptr_t)gpc->khva); old_uhva = PAGE_ALIGN_DOWN(gpc->uhva); - /* Refresh the userspace HVA if necessary */ - if (gpc->gpa != gpa || gpc->generation != slots->generation || - kvm_is_error_hva(gpc->uhva)) { - gfn_t gfn = gpa_to_gfn(gpa); + if (kvm_is_error_gpa(gpa)) { + gpc->gpa = INVALID_GPA; + gpc->memslot = NULL; + gpc->uhva = PAGE_ALIGN_DOWN(uhva); - gpc->gpa = gpa; - gpc->generation = slots->generation; - gpc->memslot = __gfn_to_memslot(slots, gfn); - gpc->uhva = gfn_to_hva_memslot(gpc->memslot, gfn); - - if (kvm_is_error_hva(gpc->uhva)) { - ret = -EFAULT; - goto out; - } - - /* - * Even if the GPA and/or the memslot generation changed, the - * HVA may still be the same. - */ if (gpc->uhva != old_uhva) hva_change = true; } else { - gpc->uhva = old_uhva; + struct kvm_memslots *slots = kvm_memslots(gpc->kvm); + + if (gpc->gpa != gpa || gpc->generation != slots->generation || + kvm_is_error_hva(gpc->uhva)) { + gfn_t gfn = gpa_to_gfn(gpa); + + gpc->gpa = gpa; + gpc->generation = slots->generation; + gpc->memslot = __gfn_to_memslot(slots, gfn); + gpc->uhva = gfn_to_hva_memslot(gpc->memslot, gfn); + + if (kvm_is_error_hva(gpc->uhva)) { + ret = -EFAULT; + goto out; + } + + /* + * Even if the GPA and/or the memslot generation changed, the + * HVA may still be the same. + */ + if (gpc->uhva != old_uhva) + hva_change = true; + } else { + gpc->uhva = old_uhva; + } } /* Note: the offset must be correct before calling hva_to_pfn_retry() */ @@ -319,7 +341,15 @@ out_unlock: int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, unsigned long len) { - return __kvm_gpc_refresh(gpc, gpc->gpa, len); + /* + * If the GPA is valid then ignore the HVA, as a cache can be GPA-based + * or HVA-based, not both. For GPA-based caches, the HVA will be + * recomputed during refresh if necessary. + */ + unsigned long uhva = kvm_is_error_gpa(gpc->gpa) ? gpc->uhva : + KVM_HVA_ERR_BAD; + + return __kvm_gpc_refresh(gpc, gpc->gpa, uhva, len); } void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm) @@ -329,10 +359,12 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm) gpc->kvm = kvm; gpc->pfn = KVM_PFN_ERR_FAULT; + gpc->gpa = INVALID_GPA; gpc->uhva = KVM_HVA_ERR_BAD; } -int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) +static int __kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long uhva, + unsigned long len) { struct kvm *kvm = gpc->kvm; @@ -353,7 +385,17 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) gpc->active = true; write_unlock_irq(&gpc->lock); } - return __kvm_gpc_refresh(gpc, gpa, len); + return __kvm_gpc_refresh(gpc, gpa, uhva, len); +} + +int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) +{ + return __kvm_gpc_activate(gpc, gpa, KVM_HVA_ERR_BAD, len); +} + +int kvm_gpc_activate_hva(struct gfn_to_pfn_cache *gpc, unsigned long uhva, unsigned long len) +{ + return __kvm_gpc_activate(gpc, INVALID_GPA, uhva, len); } void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) From c01c55a34f284d27719638c4398282442c13ca34 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:05 +0000 Subject: [PATCH 407/814] KVM: x86/xen: separate initialization of shared_info cache and content A subsequent patch will allow shared_info to be initialized using either a GPA or a user-space (i.e. VMM) HVA. To make that patch cleaner, separate the initialization of the shared_info content from the activation of the pfncache. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-11-paul@xen.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 55 +++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index e90464225467..031e98d88ba2 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -34,41 +34,32 @@ static bool kvm_xen_hcall_evtchn_send(struct kvm_vcpu *vcpu, u64 param, u64 *r); DEFINE_STATIC_KEY_DEFERRED_FALSE(kvm_xen_enabled, HZ); -static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn) +static int kvm_xen_shared_info_init(struct kvm *kvm) { struct gfn_to_pfn_cache *gpc = &kvm->arch.xen.shinfo_cache; struct pvclock_wall_clock *wc; - gpa_t gpa = gfn_to_gpa(gfn); u32 *wc_sec_hi; u32 wc_version; u64 wall_nsec; int ret = 0; int idx = srcu_read_lock(&kvm->srcu); - if (gfn == KVM_XEN_INVALID_GFN) { - kvm_gpc_deactivate(gpc); - goto out; - } + read_lock_irq(&gpc->lock); + while (!kvm_gpc_check(gpc, PAGE_SIZE)) { + read_unlock_irq(&gpc->lock); - do { - ret = kvm_gpc_activate(gpc, gpa, PAGE_SIZE); + ret = kvm_gpc_refresh(gpc, PAGE_SIZE); if (ret) goto out; - /* - * This code mirrors kvm_write_wall_clock() except that it writes - * directly through the pfn cache and doesn't mark the page dirty. - */ - wall_nsec = kvm_get_wall_clock_epoch(kvm); - - /* It could be invalid again already, so we need to check */ read_lock_irq(&gpc->lock); + } - if (gpc->valid) - break; - - read_unlock_irq(&gpc->lock); - } while (1); + /* + * This code mirrors kvm_write_wall_clock() except that it writes + * directly through the pfn cache and doesn't mark the page dirty. + */ + wall_nsec = kvm_get_wall_clock_epoch(kvm); /* Paranoia checks on the 32-bit struct layout */ BUILD_BUG_ON(offsetof(struct compat_shared_info, wc) != 0x900); @@ -639,12 +630,30 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data) } break; - case KVM_XEN_ATTR_TYPE_SHARED_INFO: + case KVM_XEN_ATTR_TYPE_SHARED_INFO: { + int idx; + mutex_lock(&kvm->arch.xen.xen_lock); - r = kvm_xen_shared_info_init(kvm, data->u.shared_info.gfn); + + idx = srcu_read_lock(&kvm->srcu); + + if (data->u.shared_info.gfn == KVM_XEN_INVALID_GFN) { + kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); + r = 0; + } else { + r = kvm_gpc_activate(&kvm->arch.xen.shinfo_cache, + gfn_to_gpa(data->u.shared_info.gfn), + PAGE_SIZE); + } + + srcu_read_unlock(&kvm->srcu, idx); + + if (!r && kvm->arch.xen.shinfo_cache.active) + r = kvm_xen_shared_info_init(kvm); + mutex_unlock(&kvm->arch.xen.xen_lock); break; - + } case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR: if (data->u.vector && data->u.vector < 0x10) r = -EINVAL; From 18b99e4d6db65fface45f1e9bcd1041d93c1ac66 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:06 +0000 Subject: [PATCH 408/814] KVM: x86/xen: re-initialize shared_info if guest (32/64-bit) mode is set If the shared_info PFN cache has already been initialized then the content of the shared_info page needs to be re-initialized whenever the guest mode is (re)set. Setting the guest mode is either done explicitly by the VMM via the KVM_XEN_ATTR_TYPE_LONG_MODE attribute, or implicitly when the guest writes the MSR to set up the hypercall page. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-12-paul@xen.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 031e98d88ba2..52edf676c471 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -625,8 +625,16 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data) } else { mutex_lock(&kvm->arch.xen.xen_lock); kvm->arch.xen.long_mode = !!data->u.long_mode; + + /* + * Re-initialize shared_info to put the wallclock in the + * correct place. Whilst it's not necessary to do this + * unless the mode is actually changed, it does no harm + * to make the call anyway. + */ + r = kvm->arch.xen.shinfo_cache.active ? + kvm_xen_shared_info_init(kvm) : 0; mutex_unlock(&kvm->arch.xen.xen_lock); - r = 0; } break; @@ -1101,9 +1109,24 @@ int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data) u32 page_num = data & ~PAGE_MASK; u64 page_addr = data & PAGE_MASK; bool lm = is_long_mode(vcpu); + int r = 0; - /* Latch long_mode for shared_info pages etc. */ - vcpu->kvm->arch.xen.long_mode = lm; + mutex_lock(&kvm->arch.xen.xen_lock); + if (kvm->arch.xen.long_mode != lm) { + kvm->arch.xen.long_mode = lm; + + /* + * Re-initialize shared_info to put the wallclock in the + * correct place. + */ + if (kvm->arch.xen.shinfo_cache.active && + kvm_xen_shared_info_init(kvm)) + r = 1; + } + mutex_unlock(&kvm->arch.xen.xen_lock); + + if (r) + return r; /* * If Xen hypercall intercept is enabled, fill the hypercall From 8c328de8fd5046eb3ec5a7ff7b682a8175e986c3 Mon Sep 17 00:00:00 2001 From: Shrikanth Hegde Date: Fri, 16 Feb 2024 11:00:16 +0530 Subject: [PATCH 409/814] powerpc: Remove duplicate/unnecessary ifdefs When an ifdef is used in the below manner, second one could be considered as duplicate. ifdef DEFINE_A ...code block... ifdef DEFINE_A <-- This is a duplicate. ...code block... endif else ifndef DEFINE_A <-- This is also duplicate. ...code block... endif endif More details about the script and methods used to find these code patterns are in cover letter of [1]. Few places in arch/powerpc where this pattern was seen: paca.h: Hunk1: Code is under check of CONFIG_PPC64 from line 13, hence the second CONFIG_PPC64 at line 166 is a duplicate. Hunk2: CONFIG_PPC_BOOK3S_64 was defined back to back. Merged the two ifdefs. asm-offsets.c: Code is under check of CONFIG_PPC64 from line 176 hence second CONFIG_PPC64 at line 249 is a duplicate. powermac/feature.c: #ifndef CONFIG_PPC64 is used at line 2066. And then in #else again #ifdef CONFIG_PPC64 is used. Which is a duplicate since in #else means CONFIG_PPC64 is defined. xmon.c: Code is under the check of CONFIG_SMP from line 521 hence the same check of CONFIG_SMP at line 646 is a duplicate. No functional change is intended here. It only aims to improve code readability. [1] https://lore.kernel.org/all/20240118080326.13137-1-sshegde@linux.ibm.com/ Signed-off-by: Shrikanth Hegde Signed-off-by: Michael Ellerman Link: https://msgid.link/20240216053016.528906-1-sshegde@linux.ibm.com --- arch/powerpc/include/asm/paca.h | 4 ---- arch/powerpc/kernel/asm-offsets.c | 2 -- arch/powerpc/platforms/powermac/feature.c | 2 -- arch/powerpc/xmon/xmon.c | 2 -- 4 files changed, 10 deletions(-) diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index e667d455ecb4..1d58da946739 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -163,9 +163,7 @@ struct paca_struct { u64 kstack; /* Saved Kernel stack addr */ u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */ u64 saved_msr; /* MSR saved here by enter_rtas */ -#ifdef CONFIG_PPC64 u64 exit_save_r1; /* Syscall/interrupt R1 save */ -#endif #ifdef CONFIG_PPC_BOOK3E_64 u16 trap_save; /* Used when bad stack is encountered */ #endif @@ -214,8 +212,6 @@ struct paca_struct { /* Non-maskable exceptions that are not performance critical */ u64 exnmi[EX_SIZE]; /* used for system reset (nmi) */ u64 exmc[EX_SIZE]; /* used for machine checks */ -#endif -#ifdef CONFIG_PPC_BOOK3S_64 /* Exclusive stacks for system reset and machine check exception. */ void *nmi_emergency_sp; void *mc_emergency_sp; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9f14d95b8b32..f029755f9e69 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -246,9 +246,7 @@ int main(void) OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id); OFFSET(PACAKEXECSTATE, paca_struct, kexec_state); OFFSET(PACA_DSCR_DEFAULT, paca_struct, dscr_default); -#ifdef CONFIG_PPC64 OFFSET(PACA_EXIT_SAVE_R1, paca_struct, exit_save_r1); -#endif #ifdef CONFIG_PPC_BOOK3E_64 OFFSET(PACA_TRAP_SAVE, paca_struct, trap_save); #endif diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 81c9fbae88b1..2cc257f75c50 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2333,7 +2333,6 @@ static struct pmac_mb_def pmac_mb_defs[] = { PMAC_TYPE_POWERMAC_G5, g5_features, 0, }, -#ifdef CONFIG_PPC64 { "PowerMac7,3", "PowerMac G5", PMAC_TYPE_POWERMAC_G5, g5_features, 0, @@ -2359,7 +2358,6 @@ static struct pmac_mb_def pmac_mb_defs[] = { 0, }, #endif /* CONFIG_PPC64 */ -#endif /* CONFIG_PPC64 */ }; /* diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index b3b94cd37713..f413c220165c 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -643,10 +643,8 @@ static int xmon_core(struct pt_regs *regs, volatile int fromipi) touch_nmi_watchdog(); } else { cmd = 1; -#ifdef CONFIG_SMP if (xmon_batch) cmd = batch_cmds(regs); -#endif if (!locked_down && cmd) cmd = cmds(regs); if (locked_down || cmd != 0) { From c2ed087ed35ca569d8179924ba560be248c758e5 Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Wed, 21 Feb 2024 15:46:22 +1100 Subject: [PATCH 410/814] powerpc: Add Power11 architected and raw mode Add CPU table entries for raw and architected mode. Most fields are copied from the Power10 table entries. CPU, MMU and user (ELF_HWCAP) features are unchanged vs P10. However userspace can detect P11 because the AT_PLATFORM value changes to "power11". The logical PVR value of 0x0F000007, passed to firmware via the ibm_arch_vec, indicates the kernel can support a P11 compatible CPU, which means at least ISA v3.1 compliant. Signed-off-by: Madhavan Srinivasan Signed-off-by: Michael Ellerman Link: https://msgid.link/20240221044623.1598642-1-mpe@ellerman.id.au --- arch/powerpc/include/asm/cputable.h | 3 ++ arch/powerpc/include/asm/mmu.h | 1 + arch/powerpc/include/asm/reg.h | 2 ++ arch/powerpc/kernel/cpu_specs_book3s_64.h | 34 +++++++++++++++++++++++ arch/powerpc/kernel/dt_cpu_ftrs.c | 10 +++++++ arch/powerpc/kernel/prom_init.c | 10 ++++++- arch/powerpc/kvm/book3s_hv.c | 1 + 7 files changed, 60 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 8765d5158324..3bd6e6e0224c 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -454,6 +454,9 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTR_ARCH_300 | CPU_FTR_ARCH_31 | \ CPU_FTR_DAWR | CPU_FTR_DAWR1 | \ CPU_FTR_DEXCR_NPHIE) + +#define CPU_FTRS_POWER11 CPU_FTRS_POWER10 + #define CPU_FTRS_CELL (CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index d8b7e246a32f..61ebe5eff2c9 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -133,6 +133,7 @@ #define MMU_FTRS_POWER8 MMU_FTRS_POWER6 #define MMU_FTRS_POWER9 MMU_FTRS_POWER6 #define MMU_FTRS_POWER10 MMU_FTRS_POWER6 +#define MMU_FTRS_POWER11 MMU_FTRS_POWER6 #define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ MMU_FTR_CI_LARGE_PAGE #define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7fd09f25452d..58d6348e4ea0 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1364,6 +1364,7 @@ #define PVR_HX_C2000 0x0066 #define PVR_POWER9 0x004E #define PVR_POWER10 0x0080 +#define PVR_POWER11 0x0082 #define PVR_BE 0x0070 #define PVR_PA6T 0x0090 @@ -1375,6 +1376,7 @@ #define PVR_ARCH_207 0x0f000004 #define PVR_ARCH_300 0x0f000005 #define PVR_ARCH_31 0x0f000006 +#define PVR_ARCH_31_P11 0x0f000007 /* Macros for setting and retrieving special purpose registers */ #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/kernel/cpu_specs_book3s_64.h b/arch/powerpc/kernel/cpu_specs_book3s_64.h index 3ff9757df4c0..98d4274a1b6b 100644 --- a/arch/powerpc/kernel/cpu_specs_book3s_64.h +++ b/arch/powerpc/kernel/cpu_specs_book3s_64.h @@ -60,6 +60,9 @@ PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | \ PPC_FEATURE2_VEC_CRYPTO) +#define COMMON_USER_POWER11 COMMON_USER_POWER10 +#define COMMON_USER2_POWER11 COMMON_USER2_POWER10 + static struct cpu_spec cpu_specs[] __initdata = { { /* PPC970 */ .pvr_mask = 0xffff0000, @@ -281,6 +284,20 @@ static struct cpu_spec cpu_specs[] __initdata = { .cpu_restore = __restore_cpu_power10, .platform = "power10", }, + { /* 3.1-compliant processor, i.e. Power11 "architected" mode */ + .pvr_mask = 0xffffffff, + .pvr_value = 0x0f000007, + .cpu_name = "Power11 (architected)", + .cpu_features = CPU_FTRS_POWER11, + .cpu_user_features = COMMON_USER_POWER11, + .cpu_user_features2 = COMMON_USER2_POWER11, + .mmu_features = MMU_FTRS_POWER11, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power10, + .cpu_restore = __restore_cpu_power10, + .platform = "power11", + }, { /* Power7 */ .pvr_mask = 0xffff0000, .pvr_value = 0x003f0000, @@ -451,6 +468,23 @@ static struct cpu_spec cpu_specs[] __initdata = { .machine_check_early = __machine_check_early_realmode_p10, .platform = "power10", }, + { /* Power11 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00820000, + .cpu_name = "Power11 (raw)", + .cpu_features = CPU_FTRS_POWER11, + .cpu_user_features = COMMON_USER_POWER11, + .cpu_user_features2 = COMMON_USER2_POWER11, + .mmu_features = MMU_FTRS_POWER11, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, + .cpu_setup = __setup_cpu_power10, + .cpu_restore = __restore_cpu_power10, + .machine_check_early = __machine_check_early_realmode_p10, + .platform = "power11", + }, { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index c3fb9fdf5bd7..af4263594eb2 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -458,6 +458,14 @@ static int __init feat_enable_mce_power10(struct dt_cpu_feature *f) return 1; } +static int __init feat_enable_mce_power11(struct dt_cpu_feature *f) +{ + cur_cpu_spec->platform = "power11"; + cur_cpu_spec->machine_check_early = __machine_check_early_realmode_p10; + + return 1; +} + static int __init feat_enable_tm(struct dt_cpu_feature *f) { #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -648,8 +656,10 @@ static struct dt_cpu_feature_match __initdata {"pc-relative-addressing", feat_enable, 0}, {"machine-check-power9", feat_enable_mce_power9, 0}, {"machine-check-power10", feat_enable_mce_power10, 0}, + {"machine-check-power11", feat_enable_mce_power11, 0}, {"performance-monitor-power9", feat_enable_pmu_power9, 0}, {"performance-monitor-power10", feat_enable_pmu_power10, 0}, + {"performance-monitor-power11", feat_enable_pmu_power10, 0}, {"event-based-branch-v3", feat_enable, 0}, {"random-number-generator", feat_enable, 0}, {"system-call-vectored", feat_disable, 0}, diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e67effdba85c..0ef358285337 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -947,7 +947,7 @@ struct option_vector7 { } __packed; struct ibm_arch_vec { - struct { __be32 mask, val; } pvrs[14]; + struct { __be32 mask, val; } pvrs[16]; u8 num_vectors; @@ -1007,6 +1007,14 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .mask = cpu_to_be32(0xffff0000), /* POWER10 */ .val = cpu_to_be32(0x00800000), }, + { + .mask = cpu_to_be32(0xffff0000), /* POWER11 */ + .val = cpu_to_be32(0x00820000), + }, + { + .mask = cpu_to_be32(0xffffffff), /* P11 compliant */ + .val = cpu_to_be32(0x0f000007), + }, { .mask = cpu_to_be32(0xffffffff), /* all 3.1-compliant */ .val = cpu_to_be32(0x0f000006), diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 52427fc2a33f..0ee7395caa21 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -427,6 +427,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) cap = H_GUEST_CAP_POWER9; break; case PVR_ARCH_31: + case PVR_ARCH_31_P11: guest_pcr_bit = PCR_ARCH_31; cap = H_GUEST_CAP_POWER10; break; From b22ea627225b53ec7ce25c19d6df9fa8217d1643 Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Wed, 21 Feb 2024 15:46:23 +1100 Subject: [PATCH 411/814] powerpc/perf: Power11 Performance Monitoring support Base enablement patch to register performance monitoring hardware support for Power11. Most of fields are copied from power10_pmu struct for power11_pmu struct. Signed-off-by: Madhavan Srinivasan Signed-off-by: Michael Ellerman Link: https://msgid.link/20240221044623.1598642-2-mpe@ellerman.id.au --- arch/powerpc/perf/core-book3s.c | 2 ++ arch/powerpc/perf/internal.h | 1 + arch/powerpc/perf/power10-pmu.c | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index b7ff680cde96..6f0d46c53027 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -2593,6 +2593,8 @@ static int __init init_ppc64_pmu(void) return 0; else if (!init_power10_pmu()) return 0; + else if (!init_power11_pmu()) + return 0; else if (!init_ppc970_pmu()) return 0; else diff --git a/arch/powerpc/perf/internal.h b/arch/powerpc/perf/internal.h index 4c18b5504326..a70ac471a5a5 100644 --- a/arch/powerpc/perf/internal.h +++ b/arch/powerpc/perf/internal.h @@ -10,4 +10,5 @@ int __init init_power7_pmu(void); int __init init_power8_pmu(void); int __init init_power9_pmu(void); int __init init_power10_pmu(void); +int __init init_power11_pmu(void); int __init init_generic_compat_pmu(void); diff --git a/arch/powerpc/perf/power10-pmu.c b/arch/powerpc/perf/power10-pmu.c index 9b5133e361a7..62a68b6b2d4b 100644 --- a/arch/powerpc/perf/power10-pmu.c +++ b/arch/powerpc/perf/power10-pmu.c @@ -634,3 +634,30 @@ int __init init_power10_pmu(void) return 0; } + +static struct power_pmu power11_pmu; + +int __init init_power11_pmu(void) +{ + unsigned int pvr; + int rc; + + pvr = mfspr(SPRN_PVR); + if (PVR_VER(pvr) != PVR_POWER11) + return -ENODEV; + + /* Set the PERF_REG_EXTENDED_MASK here */ + PERF_REG_EXTENDED_MASK = PERF_REG_PMU_MASK_31; + + power11_pmu = power10_pmu; + power11_pmu.name = "Power11"; + + rc = register_power_pmu(&power11_pmu); + if (rc) + return rc; + + /* Tell userspace that EBB is supported */ + cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB; + + return 0; +} From 8b338061065b1871fc9ec53bd772321c15363123 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 7 Feb 2024 13:52:18 +1000 Subject: [PATCH 412/814] powerpc/pseries: Add a clear modifier to ibm,pa/pi-features parser When a new ibm,pa/pi-features bit is introduced that is intended to apply to existing systems and features, it may have an "inverted" meaning (i.e., bit clear => feature available; bit set => unavailable). Depending on the nature of the feature, this may give the best backward compatibility result where old firmware will continue to have that bit clear and therefore the feature available. The 'invert' modifier presumably was introduced for this type of feature bit. However it invert will set the feature if the bit is clear, which prevents it being used in the situation where an old CPU lacks a feature that a new CPU has, then a new firmware comes out to disable that feature on the new CPU if the bit is set. Adding an 'invert' entry for that feature would incorrectly enable it for the old CPU. So add a 'clear' modifier that clears the feature if the bit is set, but it does not set the feature if the bit is clear. The feature is expected to be set in the cpu table. This replaces the 'invert' modifier, which is unused since commit 7d4703455168 ("powerpc/feature: Remove CPU_FTR_NODSISRALIGN"). Signed-off-by: Nicholas Piggin Tested-by: Vaibhav Jain Signed-off-by: Michael Ellerman Link: https://msgid.link/20240207035220.339726-1-npiggin@gmail.com --- arch/powerpc/kernel/prom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f2c2f79ea477..25c414be92db 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -151,6 +151,9 @@ static void __init move_device_tree(void) * pa-features property is missing, or a 1/0 to indicate if the feature * is supported/not supported. Note that the bit numbers are * big-endian to match the definition in PAPR. + * Note: the 'clear' flag clears the feature if the bit is set in the + * ibm,pa/pi-features property, it does not set the feature if the + * bit is clear. */ struct ibm_feature { unsigned long cpu_features; /* CPU_FTR_xxx bit */ @@ -159,7 +162,7 @@ struct ibm_feature { unsigned int cpu_user_ftrs2; /* PPC_FEATURE2_xxx bit */ unsigned char pabyte; /* byte number in ibm,pa/pi-features */ unsigned char pabit; /* bit number (big-endian) */ - unsigned char invert; /* if 1, pa bit set => clear feature */ + unsigned char clear; /* if 1, pa bit set => clear feature */ }; static struct ibm_feature ibm_pa_features[] __initdata = { @@ -220,12 +223,12 @@ static void __init scan_features(unsigned long node, const unsigned char *ftrs, if (fp->pabyte >= ftrs[0]) continue; bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; - if (bit ^ fp->invert) { + if (bit && !fp->clear) { cur_cpu_spec->cpu_features |= fp->cpu_features; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; cur_cpu_spec->cpu_user_features2 |= fp->cpu_user_ftrs2; cur_cpu_spec->mmu_features |= fp->mmu_features; - } else { + } else if (bit == fp->clear) { cur_cpu_spec->cpu_features &= ~fp->cpu_features; cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; cur_cpu_spec->cpu_user_features2 &= ~fp->cpu_user_ftrs2; From 6e9de2054eb417d6e05561b19c825c29b424b475 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 7 Feb 2024 13:52:19 +1000 Subject: [PATCH 413/814] powerpc/pseries: Set CPU_FTR_DBELL according to ibm,pi-features PAPR will define a new ibm,pi-features bit which says that doorbells should not be used even on architectures where they exist. This could be because they are emulated and slower than using the interrupt controller directly for IPIs. Wire this bit into the pi-features parser to clear CPU_FTR_DBELL, and ensure CPU_FTR_DBELL is not in CPU_FTRS_ALWAYS. Signed-off-by: Nicholas Piggin Tested-by: Vaibhav Jain Signed-off-by: Michael Ellerman Link: https://msgid.link/20240207035220.339726-2-npiggin@gmail.com --- arch/powerpc/include/asm/cputable.h | 11 ++++++----- arch/powerpc/kernel/prom.c | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 3bd6e6e0224c..07a204d21034 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -545,19 +545,20 @@ enum { #define CPU_FTRS_DT_CPU_BASE (~0ul) #endif +/* pseries may disable DBELL with ibm,pi-features */ #ifdef CONFIG_CPU_LITTLE_ENDIAN #define CPU_FTRS_ALWAYS \ - (CPU_FTRS_POSSIBLE & ~CPU_FTR_HVMODE & CPU_FTRS_POWER7 & \ - CPU_FTRS_POWER8E & CPU_FTRS_POWER8 & CPU_FTRS_POWER9 & \ - CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ + (CPU_FTRS_POSSIBLE & ~CPU_FTR_HVMODE & ~CPU_FTR_DBELL & \ + CPU_FTRS_POWER7 & CPU_FTRS_POWER8E & CPU_FTRS_POWER8 & \ + CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ CPU_FTRS_POWER10 & CPU_FTRS_DT_CPU_BASE) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & \ CPU_FTRS_POWER6 & CPU_FTRS_POWER7 & CPU_FTRS_CELL & \ CPU_FTRS_PA6T & CPU_FTRS_POWER8 & CPU_FTRS_POWER8E & \ - ~CPU_FTR_HVMODE & CPU_FTRS_POSSIBLE & CPU_FTRS_POWER9 & \ - CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ + ~CPU_FTR_HVMODE & ~CPU_FTR_DBELL & CPU_FTRS_POSSIBLE & \ + CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ CPU_FTRS_POWER10 & CPU_FTRS_DT_CPU_BASE) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 25c414be92db..1dc32a058156 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -196,6 +196,7 @@ static struct ibm_feature ibm_pa_features[] __initdata = { */ static struct ibm_feature ibm_pi_features[] __initdata = { { .pabyte = 0, .pabit = 3, .mmu_features = MMU_FTR_NX_DSI }, + { .pabyte = 0, .pabit = 4, .cpu_features = CPU_FTR_DBELL, .clear = 1 }, }; static void __init scan_features(unsigned long node, const unsigned char *ftrs, From 6735fef14c1f089ae43fd6d43add818b7ff682a8 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 27 Dec 2023 17:24:03 +1000 Subject: [PATCH 414/814] powerpc/ps3: Fix lv1 hcall assembly for ELFv2 calling convention Stack-passed parameters begin at a different offset in the caller's stack in the ELFv2 ABI. Reported-by: Geoff Levand Fixes: 8c5fa3b5c4df ("powerpc/64: Make ELFv2 the default for big-endian builds") Signed-off-by: Nicholas Piggin Tested-by: Geoff Levand Signed-off-by: Michael Ellerman Link: https://msgid.link/20231227072405.63751-2-npiggin@gmail.com --- arch/powerpc/include/asm/ppc_asm.h | 6 ++++-- arch/powerpc/platforms/ps3/hvcall.S | 18 +++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index e7792aa13510..041ee2595520 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -201,11 +201,13 @@ #ifdef CONFIG_PPC64_ELF_ABI_V2 #define STK_GOT 24 -#define __STK_PARAM(i) (32 + ((i)-3)*8) +#define STK_PARAM_AREA 32 #else #define STK_GOT 40 -#define __STK_PARAM(i) (48 + ((i)-3)*8) +#define STK_PARAM_AREA 48 #endif + +#define __STK_PARAM(i) (STK_PARAM_AREA + ((i)-3)*8) #define STK_PARAM(i) __STK_PARAM(__REG_##i) #ifdef CONFIG_PPC64_ELF_ABI_V2 diff --git a/arch/powerpc/platforms/ps3/hvcall.S b/arch/powerpc/platforms/ps3/hvcall.S index 509e30ad01bb..59ea569debf4 100644 --- a/arch/powerpc/platforms/ps3/hvcall.S +++ b/arch/powerpc/platforms/ps3/hvcall.S @@ -714,7 +714,7 @@ _GLOBAL(_##API_NAME) \ std r4, 0(r11); \ ld r11, -16(r1); \ std r5, 0(r11); \ - ld r11, 48+8*8(r1); \ + ld r11, STK_PARAM_AREA+8*8(r1); \ std r6, 0(r11); \ \ ld r0, 16(r1); \ @@ -746,22 +746,22 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, 16(r1); \ \ - std r10, 48+8*7(r1); \ + std r10, STK_PARAM_AREA+8*7(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - ld r11, 48+8*7(r1); \ + ld r11, STK_PARAM_AREA+8*7(r1); \ std r4, 0(r11); \ - ld r11, 48+8*8(r1); \ + ld r11, STK_PARAM_AREA+8*8(r1); \ std r5, 0(r11); \ - ld r11, 48+8*9(r1); \ + ld r11, STK_PARAM_AREA+8*9(r1); \ std r6, 0(r11); \ - ld r11, 48+8*10(r1); \ + ld r11, STK_PARAM_AREA+8*10(r1); \ std r7, 0(r11); \ - ld r11, 48+8*11(r1); \ + ld r11, STK_PARAM_AREA+8*11(r1); \ std r8, 0(r11); \ - ld r11, 48+8*12(r1); \ + ld r11, STK_PARAM_AREA+8*12(r1); \ std r9, 0(r11); \ \ ld r0, 16(r1); \ @@ -777,7 +777,7 @@ _GLOBAL(_##API_NAME) \ li r11, API_NUMBER; \ lv1call; \ \ - ld r11, 48+8*8(r1); \ + ld r11, STK_PARAM_AREA+8*8(r1); \ std r4, 0(r11); \ \ ld r0, 16(r1); \ From d901473c4dd0198d2d60553ea483d632175af4ea Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 27 Dec 2023 17:24:04 +1000 Subject: [PATCH 415/814] powerpc/ps3: lv1 hcall code use symbolic constant for LR save offset The LRSAVE constant is required for assembly compiled for both 32-bit and 64-bit, because the value differs there. PS3 is 64-bit only so this is a noop, but it is nice to abstract stack frame offsets. Signed-off-by: Nicholas Piggin Tested-by: Geoff Levand Signed-off-by: Michael Ellerman Link: https://msgid.link/20231227072405.63751-3-npiggin@gmail.com --- arch/powerpc/platforms/ps3/hvcall.S | 128 ++++++++++++++-------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/arch/powerpc/platforms/ps3/hvcall.S b/arch/powerpc/platforms/ps3/hvcall.S index 59ea569debf4..b854675f6113 100644 --- a/arch/powerpc/platforms/ps3/hvcall.S +++ b/arch/powerpc/platforms/ps3/hvcall.S @@ -16,12 +16,12 @@ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -38,7 +38,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r3, -8(r1); \ \ @@ -49,7 +49,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -57,7 +57,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r3, -8(r1); \ stdu r4, -16(r1); \ @@ -71,7 +71,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -79,7 +79,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r3, -8(r1); \ std r4, -16(r1); \ @@ -96,7 +96,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -104,7 +104,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r3, -8(r1); \ std r4, -16(r1); \ @@ -133,7 +133,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -56(r1); \ std r10, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -141,7 +141,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r4, -8(r1); \ \ @@ -152,7 +152,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -160,7 +160,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ stdu r5, -16(r1); \ @@ -174,7 +174,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -182,7 +182,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ std r5, -16(r1); \ @@ -199,7 +199,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -207,7 +207,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ std r5, -16(r1); \ @@ -227,7 +227,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -32(r1); \ std r7, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -235,7 +235,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ std r5, -16(r1); \ @@ -258,7 +258,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -40(r1); \ std r8, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -266,7 +266,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ std r5, -16(r1); \ @@ -292,7 +292,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -48(r1); \ std r9, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -300,7 +300,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ std r5, -16(r1); \ @@ -329,7 +329,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -56(r1); \ std r10, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -337,7 +337,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r5, -8(r1); \ \ @@ -348,7 +348,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -356,7 +356,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r5, -8(r1); \ stdu r6, -16(r1); \ @@ -370,7 +370,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -378,7 +378,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r5, -8(r1); \ std r6, -16(r1); \ @@ -395,7 +395,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -403,7 +403,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r5, -8(r1); \ std r6, -16(r1); \ @@ -423,7 +423,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -32(r1); \ std r7, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -431,7 +431,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r5, -8(r1); \ std r6, -16(r1); \ @@ -454,7 +454,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -40(r1); \ std r8, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -462,7 +462,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r6, -8(r1); \ \ @@ -473,7 +473,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -481,7 +481,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r6, -8(r1); \ stdu r7, -16(r1); \ @@ -495,7 +495,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -503,7 +503,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r6, -8(r1); \ std r7, -16(r1); \ @@ -520,7 +520,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -528,7 +528,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r7, -8(r1); \ \ @@ -539,7 +539,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -547,7 +547,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r7, -8(r1); \ stdu r8, -16(r1); \ @@ -561,7 +561,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -569,7 +569,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r7, -8(r1); \ std r8, -16(r1); \ @@ -586,7 +586,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -594,7 +594,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r8, -8(r1); \ \ @@ -605,7 +605,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -613,7 +613,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r8, -8(r1); \ stdu r9, -16(r1); \ @@ -627,7 +627,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -635,7 +635,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r8, -8(r1); \ std r9, -16(r1); \ @@ -652,7 +652,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -24(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -660,7 +660,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r9, -8(r1); \ \ @@ -671,7 +671,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -679,7 +679,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r9, -8(r1); \ stdu r10, -16(r1); \ @@ -693,7 +693,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -16(r1); \ std r5, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -701,7 +701,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r9, -8(r1); \ stdu r10, -16(r1); \ @@ -717,7 +717,7 @@ _GLOBAL(_##API_NAME) \ ld r11, STK_PARAM_AREA+8*8(r1); \ std r6, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -725,7 +725,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ stdu r10, -8(r1); \ \ @@ -736,7 +736,7 @@ _GLOBAL(_##API_NAME) \ ld r11, -8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -744,7 +744,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ std r10, STK_PARAM_AREA+8*7(r1); \ \ @@ -764,7 +764,7 @@ _GLOBAL(_##API_NAME) \ ld r11, STK_PARAM_AREA+8*12(r1); \ std r9, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr @@ -772,7 +772,7 @@ _GLOBAL(_##API_NAME) \ _GLOBAL(_##API_NAME) \ \ mflr r0; \ - std r0, 16(r1); \ + std r0, LRSAVE(r1); \ \ li r11, API_NUMBER; \ lv1call; \ @@ -780,7 +780,7 @@ _GLOBAL(_##API_NAME) \ ld r11, STK_PARAM_AREA+8*8(r1); \ std r4, 0(r11); \ \ - ld r0, 16(r1); \ + ld r0, LRSAVE(r1); \ mtlr r0; \ blr From 28b2ed86750cf5be86d19dd6ff236b23e98b255d Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 27 Dec 2023 17:24:05 +1000 Subject: [PATCH 416/814] powerpc/ps3: Make real stack frames for LV1 hcalls The PS3 hcall assembly code makes ad-hoc stack frames that don't have a back-chain pointer or meet other requirements like minimum frame size. This probably confuses stack unwinders. Give all hcalls a real stack frame. Signed-off-by: Nicholas Piggin Tested-by: Geoff Levand [mpe: Add missing \ in LV1_2_IN_4_OUT] Signed-off-by: Michael Ellerman Link: https://msgid.link/20231227072405.63751-4-npiggin@gmail.com --- arch/powerpc/platforms/ps3/hvcall.S | 152 +++++++++++++++++----------- 1 file changed, 94 insertions(+), 58 deletions(-) diff --git a/arch/powerpc/platforms/ps3/hvcall.S b/arch/powerpc/platforms/ps3/hvcall.S index b854675f6113..e8ab3d6b03bd 100644 --- a/arch/powerpc/platforms/ps3/hvcall.S +++ b/arch/powerpc/platforms/ps3/hvcall.S @@ -9,6 +9,7 @@ #include #include +#include #define lv1call .long 0x44000022; extsw r3, r3 @@ -18,8 +19,10 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ + stdu r1, -STACK_FRAME_MIN_SIZE(r1); \ li r11, API_NUMBER; \ lv1call; \ + addi r1, r1, STACK_FRAME_MIN_SIZE; \ \ ld r0, LRSAVE(r1); \ mtlr r0; \ @@ -40,12 +43,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r3, -8(r1); \ + std r3, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -60,12 +64,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r3, -8(r1); \ - stdu r4, -16(r1); \ + std r4, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -83,12 +88,13 @@ _GLOBAL(_##API_NAME) \ \ std r3, -8(r1); \ std r4, -16(r1); \ - stdu r5, -24(r1); \ + std r5, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -112,12 +118,13 @@ _GLOBAL(_##API_NAME) \ std r6, -32(r1); \ std r7, -40(r1); \ std r8, -48(r1); \ - stdu r9, -56(r1); \ + std r9, -56(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-56(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 56; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+56; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -143,12 +150,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r4, -8(r1); \ + std r4, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -163,12 +171,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r4, -8(r1); \ - stdu r5, -16(r1); \ + std r5, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -186,12 +195,13 @@ _GLOBAL(_##API_NAME) \ \ std r4, -8(r1); \ std r5, -16(r1); \ - stdu r6, -24(r1); \ + std r6, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -212,12 +222,13 @@ _GLOBAL(_##API_NAME) \ std r4, -8(r1); \ std r5, -16(r1); \ std r6, -24(r1); \ - stdu r7, -32(r1); \ + std r7, -32(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-32(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 32; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+32; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -241,12 +252,13 @@ _GLOBAL(_##API_NAME) \ std r5, -16(r1); \ std r6, -24(r1); \ std r7, -32(r1); \ - stdu r8, -40(r1); \ + std r8, -40(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-40(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 40; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+40; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -273,12 +285,13 @@ _GLOBAL(_##API_NAME) \ std r6, -24(r1); \ std r7, -32(r1); \ std r8, -40(r1); \ - stdu r9, -48(r1); \ + std r9, -48(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-48(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 48; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+48; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -308,12 +321,13 @@ _GLOBAL(_##API_NAME) \ std r7, -32(r1); \ std r8, -40(r1); \ std r9, -48(r1); \ - stdu r10, -56(r1); \ + std r10, -56(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-56(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 56; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+56; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -339,12 +353,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r5, -8(r1); \ + std r5, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -359,12 +374,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r5, -8(r1); \ - stdu r6, -16(r1); \ + std r6, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -382,12 +398,13 @@ _GLOBAL(_##API_NAME) \ \ std r5, -8(r1); \ std r6, -16(r1); \ - stdu r7, -24(r1); \ + std r7, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -408,12 +425,13 @@ _GLOBAL(_##API_NAME) \ std r5, -8(r1); \ std r6, -16(r1); \ std r7, -24(r1); \ - stdu r8, -32(r1); \ + std r8, -32(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-32(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 32; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+32;\ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -437,12 +455,13 @@ _GLOBAL(_##API_NAME) \ std r6, -16(r1); \ std r7, -24(r1); \ std r8, -32(r1); \ - stdu r9, -40(r1); \ + std r9, -40(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-40(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 40; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+40; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -464,12 +483,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r6, -8(r1); \ + std r6, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -484,12 +504,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r6, -8(r1); \ - stdu r7, -16(r1); \ + std r7, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -507,12 +528,13 @@ _GLOBAL(_##API_NAME) \ \ std r6, -8(r1); \ std r7, -16(r1); \ - stdu r8, -24(r1); \ + std r8, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -530,12 +552,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r7, -8(r1); \ + std r7, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -550,12 +573,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r7, -8(r1); \ - stdu r8, -16(r1); \ + std r8, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -573,12 +597,13 @@ _GLOBAL(_##API_NAME) \ \ std r7, -8(r1); \ std r8, -16(r1); \ - stdu r9, -24(r1); \ + std r9, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -596,12 +621,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r8, -8(r1); \ + std r8, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -616,12 +642,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r8, -8(r1); \ - stdu r9, -16(r1); \ + std r9, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -639,12 +666,13 @@ _GLOBAL(_##API_NAME) \ \ std r8, -8(r1); \ std r9, -16(r1); \ - stdu r10, -24(r1); \ + std r10, -24(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-24(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 24; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+24; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -662,12 +690,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r9, -8(r1); \ + std r9, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -682,12 +711,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r9, -8(r1); \ - stdu r10, -16(r1); \ + std r10, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -704,12 +734,13 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r9, -8(r1); \ - stdu r10, -16(r1); \ + std r10, -16(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-16(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 16; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+16; \ ld r11, -8(r1); \ std r4, 0(r11); \ ld r11, -16(r1); \ @@ -727,12 +758,13 @@ _GLOBAL(_##API_NAME) \ mflr r0; \ std r0, LRSAVE(r1); \ \ - stdu r10, -8(r1); \ + std r10, -8(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE-8(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ - addi r1, r1, 8; \ + addi r1, r1, STACK_FRAME_MIN_SIZE+8; \ ld r11, -8(r1); \ std r4, 0(r11); \ \ @@ -747,10 +779,12 @@ _GLOBAL(_##API_NAME) \ std r0, LRSAVE(r1); \ \ std r10, STK_PARAM_AREA+8*7(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ + addi r1, r1, STACK_FRAME_MIN_SIZE; \ ld r11, STK_PARAM_AREA+8*7(r1); \ std r4, 0(r11); \ ld r11, STK_PARAM_AREA+8*8(r1); \ @@ -773,10 +807,12 @@ _GLOBAL(_##API_NAME) \ \ mflr r0; \ std r0, LRSAVE(r1); \ + stdu r1, -STACK_FRAME_MIN_SIZE(r1); \ \ li r11, API_NUMBER; \ lv1call; \ \ + addi r1, r1, STACK_FRAME_MIN_SIZE; \ ld r11, STK_PARAM_AREA+8*8(r1); \ std r4, 0(r11); \ \ From 914d081ead115f7ba685ab57f977716bdd09c894 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Fri, 19 Jan 2024 10:27:53 +0000 Subject: [PATCH 417/814] Revert "powerpc/ps3_defconfig: Disable PPC64_BIG_ENDIAN_ELF_ABI_V2" This reverts commit 482b718a84f08b6fc84879c3e90cc57dba11c115. The preceding commits by Nicholas Piggin enable PS3 support for ELFv2, so there's no need to disable it for PS3 anymore. Signed-off-by: Geoff Levand Signed-off-by: Michael Ellerman Link: https://msgid.link/983836405df1b6001a2262972fb32d1aee97d6f5.1705654669.git.geoff@infradead.org --- arch/powerpc/configs/ps3_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index aa8bb0208bcc..2b175ddf82f0 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -24,7 +24,6 @@ CONFIG_PS3_VRAM=m CONFIG_PS3_LPM=m # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set CONFIG_KEXEC=y -# CONFIG_PPC64_BIG_ENDIAN_ELF_ABI_V2 is not set CONFIG_PPC_4K_PAGES=y CONFIG_SCHED_SMT=y CONFIG_PM=y From 4a447b135e45b49101417d54079df25b520299d9 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Sun, 18 Feb 2024 12:30:03 +0800 Subject: [PATCH 418/814] KVM: selftests: Test top-down slots event in x86's pmu_counters_test Although the fixed counter 3 and its exclusive pseudo slots event are not supported by KVM yet, the architectural slots event is supported by KVM and can be programmed on any GP counter. Thus add validation for this architectural slots event. Top-down slots event "counts the total number of available slots for an unhalted logical processor, and increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method." As for the slot, it's an abstract concept which indicates how many uops (decoded from instructions) can be processed simultaneously (per cycle) on HW. In Top-down Microarchitecture Analysis (TMA) method, the processor is divided into two parts, frond-end and back-end. Assume there is a processor with classic 5-stage pipeline, fetch, decode, execute, memory access and register writeback. The former 2 stages (fetch/decode) are classified to frond-end and the latter 3 stages are classified to back-end. In modern Intel processors, a complicated instruction would be decoded into several uops (micro-operations) and so these uops can be processed simultaneously and then improve the performance. Thus, assume a processor can decode and dispatch 4 uops in front-end and execute 4 uops in back-end simultaneously (per-cycle), so the machine-width of this processor is 4 and this processor has 4 topdown slots per-cycle. If a slot is spare and can be used to process a new upcoming uop, then the slot is available, but if a uop occupies a slot for several cycles and can't be retired (maybe blocked by memory access), then this slot is stall and unavailable. Considering the testing instruction sequence can't be macro-fused on x86 platforms, the measured slots count should not be less than NUM_INSNS_RETIRED. Thus assert the slots count against NUM_INSNS_RETIRED. pmu_counters_test passed with this patch on Intel Sapphire Rapids. About the more information about TMA method, please refer the below link. https://www.intel.com/content/www/us/en/docs/vtune-profiler/cookbook/2023-0/top-down-microarchitecture-analysis-method.html Signed-off-by: Dapeng Mi Link: https://lore.kernel.org/r/20240218043003.2424683-1-dapeng1.mi@linux.intel.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/pmu_counters_test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index ae5f6042f1e8..29609b52f8fa 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -119,6 +119,9 @@ static void guest_assert_event_count(uint8_t idx, case INTEL_ARCH_REFERENCE_CYCLES_INDEX: GUEST_ASSERT_NE(count, 0); break; + case INTEL_ARCH_TOPDOWN_SLOTS_INDEX: + GUEST_ASSERT(count >= NUM_INSNS_RETIRED); + break; default: break; } From 85a19b3054274e09bcd9043d7d3203c3836688d0 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Mon, 5 Feb 2024 22:43:00 +0100 Subject: [PATCH 419/814] KVM: s390: only deliver the set service event bits The SCLP driver code masks off the last two bits of the parameter [1] to determine if a read is required, but doesn't care about the contents of those bits. Meanwhile, the KVM code that delivers event interrupts masks off those two bits but sends both to the guest, even if only one was specified by userspace [2]. This works for the driver code, but it means any nuances of those bits gets lost. Use the event pending mask as an actual mask, and only send the bit(s) that were specified in the pending interrupt. [1] Linux: sclp_interrupt_handler() (drivers/s390/char/sclp.c:658) [2] QEMU: service_interrupt() (hw/s390x/sclp.c:360..363) Fixes: 0890ddea1a90 ("KVM: s390: protvirt: Add SCLP interrupt handling") Signed-off-by: Eric Farman Reviewed-by: Christian Borntraeger Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20240205214300.1018522-1-farman@linux.ibm.com Signed-off-by: Janosch Frank Message-Id: <20240205214300.1018522-1-farman@linux.ibm.com> --- arch/s390/kvm/interrupt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index fc4007cc067a..20e080e9150b 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -1031,7 +1031,7 @@ static int __must_check __deliver_service_ev(struct kvm_vcpu *vcpu) return 0; } ext = fi->srv_signal; - /* only clear the event bit */ + /* only clear the event bits */ fi->srv_signal.ext_params &= ~SCCB_EVENT_PENDING; clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); spin_unlock(&fi->lock); @@ -1041,7 +1041,7 @@ static int __must_check __deliver_service_ev(struct kvm_vcpu *vcpu) trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE, ext.ext_params, 0); - return write_sclp(vcpu, SCCB_EVENT_PENDING); + return write_sclp(vcpu, ext.ext_params & SCCB_EVENT_PENDING); } static int __must_check __deliver_pfault_done(struct kvm_vcpu *vcpu) From 9d16a8591a52d614507ed76f0b105c7de7b8dbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:15 +0100 Subject: [PATCH 420/814] powerpc: sgy_cts1000: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/1e8396078942d9e46e56d70ed2f749a76391c381.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/platforms/85xx/sgy_cts1000.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c index 751395cbf022..34ce21f42623 100644 --- a/arch/powerpc/platforms/85xx/sgy_cts1000.c +++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c @@ -114,7 +114,7 @@ static int gpio_halt_probe(struct platform_device *pdev) return ret; } -static int gpio_halt_remove(struct platform_device *pdev) +static void gpio_halt_remove(struct platform_device *pdev) { free_irq(halt_irq, pdev); cancel_work_sync(&gpio_halt_wq); @@ -124,8 +124,6 @@ static int gpio_halt_remove(struct platform_device *pdev) gpiod_put(halt_gpio); halt_gpio = NULL; - - return 0; } static const struct of_device_id gpio_halt_match[] = { @@ -145,7 +143,7 @@ static struct platform_driver gpio_halt_driver = { .of_match_table = gpio_halt_match, }, .probe = gpio_halt_probe, - .remove = gpio_halt_remove, + .remove_new = gpio_halt_remove, }; module_platform_driver(gpio_halt_driver); From b1cd248f427607e595c2799044f8166dac1e953b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:16 +0100 Subject: [PATCH 421/814] powerpc: gpio_mdio: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/8a5ac8044578694879e919322dbd46f140b64950.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index fd130fe7a65a..4e983af32949 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -260,7 +260,7 @@ out: } -static int gpio_mdio_remove(struct platform_device *dev) +static void gpio_mdio_remove(struct platform_device *dev) { struct mii_bus *bus = dev_get_drvdata(&dev->dev); @@ -271,8 +271,6 @@ static int gpio_mdio_remove(struct platform_device *dev) kfree(bus->priv); bus->priv = NULL; mdiobus_free(bus); - - return 0; } static const struct of_device_id gpio_mdio_match[] = @@ -287,7 +285,7 @@ MODULE_DEVICE_TABLE(of, gpio_mdio_match); static struct platform_driver gpio_mdio_driver = { .probe = gpio_mdio_probe, - .remove = gpio_mdio_remove, + .remove_new = gpio_mdio_remove, .driver = { .name = "gpio-mdio-bitbang", .of_match_table = gpio_mdio_match, From ca899c1221b6beee80ac91977309c08b78c74ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:17 +0100 Subject: [PATCH 422/814] powerpc: opal-prd: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/28dd12b7cbde4b278b8b1d0ae4382dbd8ce9c9c5.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/platforms/powernv/opal-prd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c index b66b06efcef1..24f04f20d3e8 100644 --- a/arch/powerpc/platforms/powernv/opal-prd.c +++ b/arch/powerpc/platforms/powernv/opal-prd.c @@ -425,12 +425,11 @@ static int opal_prd_probe(struct platform_device *pdev) return 0; } -static int opal_prd_remove(struct platform_device *pdev) +static void opal_prd_remove(struct platform_device *pdev) { misc_deregister(&opal_prd_dev); opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb); opal_message_notifier_unregister(OPAL_MSG_PRD2, &opal_prd_event_nb2); - return 0; } static const struct of_device_id opal_prd_match[] = { @@ -444,7 +443,7 @@ static struct platform_driver opal_prd_driver = { .of_match_table = opal_prd_match, }, .probe = opal_prd_probe, - .remove = opal_prd_remove, + .remove_new = opal_prd_remove, }; module_platform_driver(opal_prd_driver); From 18a4a2612ba1e54526bbc11980f1fbb31b7aa440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:18 +0100 Subject: [PATCH 423/814] powerpc: papr_scm: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/34847d756453af2e85e5944a8cc2e2c21aacc905.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/platforms/pseries/papr_scm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 1a53e048ceb7..c233f9db039b 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -1521,7 +1521,7 @@ err: kfree(p); return rc; } -static int papr_scm_remove(struct platform_device *pdev) +static void papr_scm_remove(struct platform_device *pdev) { struct papr_scm_priv *p = platform_get_drvdata(pdev); @@ -1538,8 +1538,6 @@ static int papr_scm_remove(struct platform_device *pdev) pdev->archdata.priv = NULL; kfree(p->bus_desc.provider_name); kfree(p); - - return 0; } static const struct of_device_id papr_scm_match[] = { @@ -1550,7 +1548,7 @@ static const struct of_device_id papr_scm_match[] = { static struct platform_driver papr_scm_driver = { .probe = papr_scm_probe, - .remove = papr_scm_remove, + .remove_new = papr_scm_remove, .driver = { .name = "papr_scm", .of_match_table = papr_scm_match, From e2064de2f3c89976a4a03f265edb5bc3795fc8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:19 +0100 Subject: [PATCH 424/814] powerpc: fsl_msi: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/42d8e3721053dce21ea373a24cb37fb0f59eed26.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/sysdev/fsl_msi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 558ec68d768e..8e6c84df4ca1 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -320,7 +320,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data) return ret; } -static int fsl_of_msi_remove(struct platform_device *ofdev) +static void fsl_of_msi_remove(struct platform_device *ofdev) { struct fsl_msi *msi = platform_get_drvdata(ofdev); int virq, i; @@ -343,8 +343,6 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) if ((msi->feature & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC) iounmap(msi->msi_regs); kfree(msi); - - return 0; } static struct lock_class_key fsl_msi_irq_class; @@ -603,7 +601,7 @@ static struct platform_driver fsl_of_msi_driver = { .of_match_table = fsl_of_msi_ids, }, .probe = fsl_of_msi_probe, - .remove = fsl_of_msi_remove, + .remove_new = fsl_of_msi_remove, }; static __init int fsl_of_msi_init(void) From a3e1820186b5ed3703e690eb064ad7c6c7477cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 21 Feb 2024 16:40:20 +0100 Subject: [PATCH 425/814] powerpc: pmi: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/3201daed6d19c01ee0ee72e0f9302a38ecef3577.1708529736.git.u.kleine-koenig@pengutronix.de --- arch/powerpc/sysdev/pmi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index fcf8d1516210..737f97fd67d7 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c @@ -173,7 +173,7 @@ out: return rc; } -static int pmi_of_remove(struct platform_device *dev) +static void pmi_of_remove(struct platform_device *dev) { struct pmi_handler *handler, *tmp; @@ -189,13 +189,11 @@ static int pmi_of_remove(struct platform_device *dev) kfree(data); data = NULL; - - return 0; } static struct platform_driver pmi_of_platform_driver = { .probe = pmi_of_probe, - .remove = pmi_of_remove, + .remove_new = pmi_of_remove, .driver = { .name = "pmi", .of_match_table = pmi_match, From 9e00743aba832f3f30ecb017d3345baf1f372140 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 10:46:43 +0100 Subject: [PATCH 426/814] powerpc/trace: Restrict hash_fault trace event to HASH MMU 'perf list' on powerpc 8xx shows an event named "1:hash_fault". This event is pointless because trace_hash_fault() is called only from mm/book3s64/hash_utils.c Only define it when CONFIG_PPC_64S_HASH_MMU is selected. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/85a86e51b4ab26ce4b592984cc0a0851a3cc9479.1708076780.git.christophe.leroy@csgroup.eu --- arch/powerpc/include/asm/trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/trace.h b/arch/powerpc/include/asm/trace.h index 82cc2c6704e6..d9ac3a4f46e1 100644 --- a/arch/powerpc/include/asm/trace.h +++ b/arch/powerpc/include/asm/trace.h @@ -267,6 +267,7 @@ TRACE_EVENT_FN(opal_exit, ); #endif +#ifdef CONFIG_PPC_64S_HASH_MMU TRACE_EVENT(hash_fault, TP_PROTO(unsigned long addr, unsigned long access, unsigned long trap), @@ -286,7 +287,7 @@ TRACE_EVENT(hash_fault, TP_printk("hash fault with addr 0x%lx and access = 0x%lx trap = 0x%lx", __entry->addr, __entry->access, __entry->trap) ); - +#endif TRACE_EVENT(tlbie, From d5835fb60bad641dbae64fe30c02f10857bf4647 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 11:10:36 +0100 Subject: [PATCH 427/814] powerpc: Use user_mode() macro when possible There is a nice macro to check user mode. Use it instead of open coding anding with MSR_PR to increase readability and avoid having to comment what that anding is for. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/fbf74887dcf1f1ba9e1680fc3247cbb581b00662.1708078228.git.christophe.leroy@csgroup.eu --- arch/powerpc/include/asm/interrupt.h | 2 +- arch/powerpc/kernel/syscall.c | 2 +- arch/powerpc/kernel/traps.c | 4 ++-- arch/powerpc/lib/sstep.c | 23 +++++++++++------------ arch/powerpc/perf/core-book3s.c | 2 +- arch/powerpc/xmon/xmon.c | 4 ++-- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index a4196ab1d016..7b610864b364 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -97,7 +97,7 @@ DECLARE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); static inline bool is_implicit_soft_masked(struct pt_regs *regs) { - if (regs->msr & MSR_PR) + if (user_mode(regs)) return false; if (regs->nip >= (unsigned long)__end_soft_masked) diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c index 77fedb190c93..f6f868e817e6 100644 --- a/arch/powerpc/kernel/syscall.c +++ b/arch/powerpc/kernel/syscall.c @@ -31,7 +31,7 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0) user_exit_irqoff(); BUG_ON(regs_is_unrecoverable(regs)); - BUG_ON(!(regs->msr & MSR_PR)); + BUG_ON(!user_mode(regs)); BUG_ON(arch_irq_disabled_regs(regs)); #ifdef CONFIG_PPC_PKEY diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 11e062b47d3f..f23430adb68a 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -404,7 +404,7 @@ noinstr void hv_nmi_check_nonrecoverable(struct pt_regs *regs) return; if (!(regs->msr & MSR_HV)) return; - if (regs->msr & MSR_PR) + if (user_mode(regs)) return; /* @@ -1510,7 +1510,7 @@ static void do_program_check(struct pt_regs *regs) if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR)) bugaddr += PAGE_OFFSET; - if (!(regs->msr & MSR_PR) && /* not user-mode */ + if (!user_mode(regs) && report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) { regs_add_return_ip(regs, 4); return; diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 5766180f5380..e65f3fb68d06 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -1429,7 +1429,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, return 1; case 18: /* rfid, scary */ - if (regs->msr & MSR_PR) + if (user_mode(regs)) goto priv; op->type = RFI; return 0; @@ -1742,13 +1742,13 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, return 1; #endif case 83: /* mfmsr */ - if (regs->msr & MSR_PR) + if (user_mode(regs)) goto priv; op->type = MFMSR; op->reg = rd; return 0; case 146: /* mtmsr */ - if (regs->msr & MSR_PR) + if (user_mode(regs)) goto priv; op->type = MTMSR; op->reg = rd; @@ -1756,7 +1756,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, return 0; #ifdef CONFIG_PPC64 case 178: /* mtmsrd */ - if (regs->msr & MSR_PR) + if (user_mode(regs)) goto priv; op->type = MTMSR; op->reg = rd; @@ -3437,14 +3437,14 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) * stored in the thread_struct. If the instruction is in * the kernel, we must not touch the state in the thread_struct. */ - if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) + if (!user_mode(regs) && !(regs->msr & MSR_FP)) return 0; err = do_fp_load(op, ea, regs, cross_endian); break; #endif #ifdef CONFIG_ALTIVEC case LOAD_VMX: - if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) + if (!user_mode(regs) && !(regs->msr & MSR_VEC)) return 0; err = do_vec_load(op->reg, ea, size, regs, cross_endian); break; @@ -3459,7 +3459,7 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) */ if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) msrbit = MSR_VEC; - if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) + if (!user_mode(regs) && !(regs->msr & msrbit)) return 0; err = do_vsx_load(op, ea, regs, cross_endian); break; @@ -3495,8 +3495,7 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) } #endif if ((op->type & UPDATE) && size == sizeof(long) && - op->reg == 1 && op->update_reg == 1 && - !(regs->msr & MSR_PR) && + op->reg == 1 && op->update_reg == 1 && !user_mode(regs) && ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) { err = handle_stack_update(ea, regs); break; @@ -3508,14 +3507,14 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) #ifdef CONFIG_PPC_FPU case STORE_FP: - if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) + if (!user_mode(regs) && !(regs->msr & MSR_FP)) return 0; err = do_fp_store(op, ea, regs, cross_endian); break; #endif #ifdef CONFIG_ALTIVEC case STORE_VMX: - if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) + if (!user_mode(regs) && !(regs->msr & MSR_VEC)) return 0; err = do_vec_store(op->reg, ea, size, regs, cross_endian); break; @@ -3530,7 +3529,7 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) */ if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) msrbit = MSR_VEC; - if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) + if (!user_mode(regs) && !(regs->msr & msrbit)) return 0; err = do_vsx_store(op, ea, regs, cross_endian); break; diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 6f0d46c53027..6b5f8a94e7d8 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -256,7 +256,7 @@ static bool regs_sipr(struct pt_regs *regs) static inline u32 perf_flags_from_msr(struct pt_regs *regs) { - if (regs->msr & MSR_PR) + if (user_mode(regs)) return PERF_RECORD_MISC_USER; if ((regs->msr & MSR_HV) && freeze_events_kernel != MMCR0_FCHV) return PERF_RECORD_MISC_HYPERVISOR; diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index f413c220165c..c85fa3f0dd3b 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1818,8 +1818,8 @@ static void print_bug_trap(struct pt_regs *regs) const struct bug_entry *bug; unsigned long addr; - if (regs->msr & MSR_PR) - return; /* not in kernel */ + if (user_mode(regs)) + return; addr = regs->nip; /* address of trap instruction */ if (!is_kernel_addr(addr)) return; From 09ca1b11716f96461a4675eb0418d5cb97687389 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 11:12:05 +0100 Subject: [PATCH 428/814] powerpc: Implement set_memory_rox() Same as x86 and s390, add set_memory_rox() to avoid doing one pass with set_memory_ro() and a second pass with set_memory_x(). See commit 60463628c9e0 ("x86/mm: Implement native set_memory_rox()") and commit 22e99fa56443 ("s390/mm: implement set_memory_rox()") for more information. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/dc9a794f82ab62572d7d0be5cb4b8b27920a4f78.1708078316.git.christophe.leroy@csgroup.eu --- arch/powerpc/include/asm/set_memory.h | 7 +++++++ arch/powerpc/mm/pageattr.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h index 7ebc807aa8cc..9a025b776a4b 100644 --- a/arch/powerpc/include/asm/set_memory.h +++ b/arch/powerpc/include/asm/set_memory.h @@ -8,6 +8,7 @@ #define SET_MEMORY_X 3 #define SET_MEMORY_NP 4 /* Set memory non present */ #define SET_MEMORY_P 5 /* Set memory present */ +#define SET_MEMORY_ROX 6 int change_memory_attr(unsigned long addr, int numpages, long action); @@ -41,4 +42,10 @@ static inline int set_memory_p(unsigned long addr, int numpages) return change_memory_attr(addr, numpages, SET_MEMORY_P); } +static inline int set_memory_rox(unsigned long addr, int numpages) +{ + return change_memory_attr(addr, numpages, SET_MEMORY_ROX); +} +#define set_memory_rox set_memory_rox + #endif diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c index 6163e484bc6d..421db7c4f2a4 100644 --- a/arch/powerpc/mm/pageattr.c +++ b/arch/powerpc/mm/pageattr.c @@ -38,6 +38,10 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data) /* Don't clear DIRTY bit */ pte_update_delta(ptep, addr, _PAGE_KERNEL_RW & ~_PAGE_DIRTY, _PAGE_KERNEL_RO); break; + case SET_MEMORY_ROX: + /* Don't clear DIRTY bit */ + pte_update_delta(ptep, addr, _PAGE_KERNEL_RW & ~_PAGE_DIRTY, _PAGE_KERNEL_ROX); + break; case SET_MEMORY_RW: pte_update_delta(ptep, addr, _PAGE_KERNEL_RO, _PAGE_KERNEL_RW); break; From f7f18e30b468458b2611ca65d745b50edcda9f43 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 11:13:28 +0100 Subject: [PATCH 429/814] powerpc/kprobes: Handle error returned by set_memory_rox() set_memory_rox() can fail. In case it fails, free allocated memory and return NULL. Link: https://github.com/KSPP/linux/issues/7 Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/b4907cf4339bd086abc40430d91311436cb0c18e.1708078401.git.christophe.leroy@csgroup.eu --- arch/powerpc/kernel/kprobes.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index b20ee72e873a..bbca90a5e2ec 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -134,10 +134,16 @@ void *alloc_insn_page(void) if (!page) return NULL; - if (strict_module_rwx_enabled()) - set_memory_rox((unsigned long)page, 1); + if (strict_module_rwx_enabled()) { + int err = set_memory_rox((unsigned long)page, 1); + if (err) + goto error; + } return page; +error: + module_memfree(page); + return NULL; } int arch_prepare_kprobe(struct kprobe *p) From b9220d32799a62c634f7b0b3618da52772626952 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:07 +0000 Subject: [PATCH 430/814] KVM: x86/xen: allow shared_info to be mapped by fixed HVA The shared_info page is not guest memory as such. It is a dedicated page allocated by the VMM and overlaid onto guest memory in a GFN chosen by the guest and specified in the XENMEM_add_to_physmap hypercall. The guest may even request that shared_info be moved from one GFN to another by re-issuing that hypercall, but the HVA is never going to change. Because the shared_info page is an overlay the memory slots need to be updated in response to the hypercall. However, memory slot adjustment is not atomic and, whilst all vCPUs are paused, there is still the possibility that events may be delivered (which requires the shared_info page to be updated) whilst the shared_info GPA is absent. The HVA is never absent though, so it makes much more sense to use that as the basis for the kernel's mapping. Hence add a new KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA attribute type for this purpose and a KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA flag to advertize its availability. Don't actually advertize it yet though. That will be done in a subsequent patch, which will also add tests for the new attribute type. Also update the KVM API documentation with the new attribute and also fix it up to consistently refer to 'shared_info' (with the underscore). Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-13-paul@xen.org [sean: store "hva" as a user pointer, use kvm_gpc_is_{gpa,hva}_active()] Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 25 ++++++++++++++++----- arch/x86/include/uapi/asm/kvm.h | 6 ++++- arch/x86/kvm/xen.c | 40 ++++++++++++++++++++++++++------- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 3ec0b7a455a0..3372be85b335 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -372,7 +372,7 @@ The bits in the dirty bitmap are cleared before the ioctl returns, unless KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled. For more information, see the description of the capability. -Note that the Xen shared info page, if configured, shall always be assumed +Note that the Xen shared_info page, if configured, shall always be assumed to be dirty. KVM will not explicitly mark it such. @@ -5487,8 +5487,9 @@ KVM_PV_ASYNC_CLEANUP_PERFORM __u8 long_mode; __u8 vector; __u8 runstate_update_flag; - struct { + union { __u64 gfn; + __u64 hva; } shared_info; struct { __u32 send_port; @@ -5516,10 +5517,10 @@ type values: KVM_XEN_ATTR_TYPE_LONG_MODE Sets the ABI mode of the VM to 32-bit or 64-bit (long mode). This - determines the layout of the shared info pages exposed to the VM. + determines the layout of the shared_info page exposed to the VM. KVM_XEN_ATTR_TYPE_SHARED_INFO - Sets the guest physical frame number at which the Xen "shared info" + Sets the guest physical frame number at which the Xen shared_info page resides. Note that although Xen places vcpu_info for the first 32 vCPUs in the shared_info page, KVM does not automatically do so and instead requires that KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO be used @@ -5528,7 +5529,7 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO not be aware of the Xen CPU id which is used as the index into the vcpu_info[] array, so may know the correct default location. - Note that the shared info page may be constantly written to by KVM; + Note that the shared_info page may be constantly written to by KVM; it contains the event channel bitmap used to deliver interrupts to a Xen guest, amongst other things. It is exempt from dirty tracking mechanisms — KVM will not explicitly mark the page as dirty each @@ -5537,9 +5538,21 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO any vCPU has been running or any event channel interrupts can be routed to the guest. - Setting the gfn to KVM_XEN_INVALID_GFN will disable the shared info + Setting the gfn to KVM_XEN_INVALID_GFN will disable the shared_info page. +KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA + If the KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA flag is also set in the + Xen capabilities, then this attribute may be used to set the + userspace address at which the shared_info page resides, which + will always be fixed in the VMM regardless of where it is mapped + in guest physical address space. This attribute should be used in + preference to KVM_XEN_ATTR_TYPE_SHARED_INFO as it avoids + unnecessary invalidation of an internal cache when the page is + re-mapped in guest physcial address space. + + Setting the hva to zero will disable the shared_info page. + KVM_XEN_ATTR_TYPE_UPCALL_VECTOR Sets the exception vector used to deliver Xen event channel upcalls. This is the HVM-wide vector injected directly by the hypervisor diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 0ad6bda1fc39..9482f22333c8 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -549,6 +549,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) #define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) #define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7) +#define KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA (1 << 8) struct kvm_xen_hvm_config { __u32 flags; @@ -567,9 +568,10 @@ struct kvm_xen_hvm_attr { __u8 long_mode; __u8 vector; __u8 runstate_update_flag; - struct { + union { __u64 gfn; #define KVM_XEN_INVALID_GFN ((__u64)-1) + __u64 hva; } shared_info; struct { __u32 send_port; @@ -611,6 +613,8 @@ struct kvm_xen_hvm_attr { #define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 /* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */ #define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */ +#define KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA 0x6 struct kvm_xen_vcpu_attr { __u16 type; diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 52edf676c471..45a74307cc25 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -638,20 +638,36 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data) } break; - case KVM_XEN_ATTR_TYPE_SHARED_INFO: { + case KVM_XEN_ATTR_TYPE_SHARED_INFO: + case KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA: { int idx; mutex_lock(&kvm->arch.xen.xen_lock); idx = srcu_read_lock(&kvm->srcu); - if (data->u.shared_info.gfn == KVM_XEN_INVALID_GFN) { - kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); - r = 0; + if (data->type == KVM_XEN_ATTR_TYPE_SHARED_INFO) { + gfn_t gfn = data->u.shared_info.gfn; + + if (gfn == KVM_XEN_INVALID_GFN) { + kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); + r = 0; + } else { + r = kvm_gpc_activate(&kvm->arch.xen.shinfo_cache, + gfn_to_gpa(gfn), PAGE_SIZE); + } } else { - r = kvm_gpc_activate(&kvm->arch.xen.shinfo_cache, - gfn_to_gpa(data->u.shared_info.gfn), - PAGE_SIZE); + void __user * hva = u64_to_user_ptr(data->u.shared_info.hva); + + if (!PAGE_ALIGNED(hva) || !access_ok(hva, PAGE_SIZE)) { + r = -EINVAL; + } else if (!hva) { + kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); + r = 0; + } else { + r = kvm_gpc_activate_hva(&kvm->arch.xen.shinfo_cache, + (unsigned long)hva, PAGE_SIZE); + } } srcu_read_unlock(&kvm->srcu, idx); @@ -715,13 +731,21 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data) break; case KVM_XEN_ATTR_TYPE_SHARED_INFO: - if (kvm->arch.xen.shinfo_cache.active) + if (kvm_gpc_is_gpa_active(&kvm->arch.xen.shinfo_cache)) data->u.shared_info.gfn = gpa_to_gfn(kvm->arch.xen.shinfo_cache.gpa); else data->u.shared_info.gfn = KVM_XEN_INVALID_GFN; r = 0; break; + case KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA: + if (kvm_gpc_is_hva_active(&kvm->arch.xen.shinfo_cache)) + data->u.shared_info.hva = kvm->arch.xen.shinfo_cache.uhva; + else + data->u.shared_info.hva = 0; + r = 0; + break; + case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR: data->u.vector = kvm->arch.xen.upcall_vector; r = 0; From 3991f35805d0f1ad84c3259dc1435021ccf63f16 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:08 +0000 Subject: [PATCH 431/814] KVM: x86/xen: allow vcpu_info to be mapped by fixed HVA If the guest does not explicitly set the GPA of vcpu_info structure in memory then, for guests with 32 vCPUs or fewer, the vcpu_info embedded in the shared_info page may be used. As described in a previous commit, the shared_info page is an overlay at a fixed HVA within the VMM, so in this case it also more optimal to activate the vcpu_info cache with a fixed HVA to avoid unnecessary invalidation if the guest memory layout is modified. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-14-paul@xen.org [sean: use kvm_gpc_is_{gpa,hva}_active()] Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 26 +++++++++++++++++++----- arch/x86/include/uapi/asm/kvm.h | 3 +++ arch/x86/kvm/xen.c | 35 ++++++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 3372be85b335..bd93cafd3e4e 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5523,11 +5523,12 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO Sets the guest physical frame number at which the Xen shared_info page resides. Note that although Xen places vcpu_info for the first 32 vCPUs in the shared_info page, KVM does not automatically do so - and instead requires that KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO be used - explicitly even when the vcpu_info for a given vCPU resides at the - "default" location in the shared_info page. This is because KVM may - not be aware of the Xen CPU id which is used as the index into the - vcpu_info[] array, so may know the correct default location. + and instead requires that KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO or + KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA be used explicitly even when + the vcpu_info for a given vCPU resides at the "default" location + in the shared_info page. This is because KVM may not be aware of + the Xen CPU id which is used as the index into the vcpu_info[] + array, so may know the correct default location. Note that the shared_info page may be constantly written to by KVM; it contains the event channel bitmap used to deliver interrupts to @@ -5649,6 +5650,21 @@ KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO on dirty logging. Setting the gpa to KVM_XEN_INVALID_GPA will disable the vcpu_info. +KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA + If the KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA flag is also set in the + Xen capabilities, then this attribute may be used to set the + userspace address of the vcpu_info for a given vCPU. It should + only be used when the vcpu_info resides at the "default" location + in the shared_info page. In this case it is safe to assume the + userspace address will not change, because the shared_info page is + an overlay on guest memory and remains at a fixed host address + regardless of where it is mapped in guest physical address space + and hence unnecessary invalidation of an internal cache may be + avoided if the guest memory layout is modified. + If the vcpu_info does not reside at the "default" location then + it is not guaranteed to remain at the same host address and + hence the aforementioned cache invalidation is required. + KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO Sets the guest physical address of an additional pvclock structure for a given vCPU. This is typically used for guest vsyscall support. diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 9482f22333c8..ad29984d5e39 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -622,6 +622,7 @@ struct kvm_xen_vcpu_attr { union { __u64 gpa; #define KVM_XEN_INVALID_GPA ((__u64)-1) + __u64 hva; __u64 pad[8]; struct { __u64 state; @@ -652,6 +653,8 @@ struct kvm_xen_vcpu_attr { #define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6 #define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7 #define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */ +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA 0x9 /* Secure Encrypted Virtualization command */ enum sev_cmd_id { diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 45a74307cc25..cd05faa19308 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -782,20 +782,33 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) switch (data->type) { case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO: + case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA: /* No compat necessary here. */ BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info)); BUILD_BUG_ON(offsetof(struct vcpu_info, time) != offsetof(struct compat_vcpu_info, time)); - if (data->u.gpa == KVM_XEN_INVALID_GPA) { - kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache); - r = 0; - break; + if (data->type == KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO) { + if (data->u.gpa == KVM_XEN_INVALID_GPA) { + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache); + r = 0; + break; + } + + r = kvm_gpc_activate(&vcpu->arch.xen.vcpu_info_cache, + data->u.gpa, sizeof(struct vcpu_info)); + } else { + if (data->u.hva == 0) { + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache); + r = 0; + break; + } + + r = kvm_gpc_activate_hva(&vcpu->arch.xen.vcpu_info_cache, + data->u.hva, sizeof(struct vcpu_info)); } - r = kvm_gpc_activate(&vcpu->arch.xen.vcpu_info_cache, - data->u.gpa, sizeof(struct vcpu_info)); if (!r) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); @@ -1017,13 +1030,21 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) switch (data->type) { case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO: - if (vcpu->arch.xen.vcpu_info_cache.active) + if (kvm_gpc_is_gpa_active(&vcpu->arch.xen.vcpu_info_cache)) data->u.gpa = vcpu->arch.xen.vcpu_info_cache.gpa; else data->u.gpa = KVM_XEN_INVALID_GPA; r = 0; break; + case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA: + if (kvm_gpc_is_hva_active(&vcpu->arch.xen.vcpu_info_cache)) + data->u.hva = vcpu->arch.xen.vcpu_info_cache.uhva; + else + data->u.hva = 0; + r = 0; + break; + case KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: if (vcpu->arch.xen.vcpu_time_info_cache.active) data->u.gpa = vcpu->arch.xen.vcpu_time_info_cache.gpa; From 9397b5334af1f4af37cf35b5c647f84a948e3110 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:09 +0000 Subject: [PATCH 432/814] KVM: selftests: map Xen's shared_info page using HVA rather than GFN Using the HVA of the shared_info page is more efficient, so if the capability (KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA) is present use that method to do the mapping. NOTE: Have the juggle_shinfo_state() thread map and unmap using both GFN and HVA, to make sure the older mechanism is not broken. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-15-paul@xen.org Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/xen_shinfo_test.c | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index 9ec9ab60b63e..a61500ff0822 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -389,6 +389,7 @@ static int cmp_timespec(struct timespec *a, struct timespec *b) return 0; } +static struct shared_info *shinfo; static struct vcpu_info *vinfo; static struct kvm_vcpu *vcpu; @@ -404,20 +405,38 @@ static void *juggle_shinfo_state(void *arg) { struct kvm_vm *vm = (struct kvm_vm *)arg; - struct kvm_xen_hvm_attr cache_activate = { + struct kvm_xen_hvm_attr cache_activate_gfn = { .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, .u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE }; - struct kvm_xen_hvm_attr cache_deactivate = { + struct kvm_xen_hvm_attr cache_deactivate_gfn = { .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, .u.shared_info.gfn = KVM_XEN_INVALID_GFN }; + struct kvm_xen_hvm_attr cache_activate_hva = { + .type = KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA, + .u.shared_info.hva = (unsigned long)shinfo + }; + + struct kvm_xen_hvm_attr cache_deactivate_hva = { + .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, + .u.shared_info.hva = 0 + }; + + int xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM); + for (;;) { - __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_activate); - __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_deactivate); + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_activate_gfn); pthread_testcancel(); + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_deactivate_gfn); + + if (xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA) { + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_activate_hva); + pthread_testcancel(); + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_deactivate_hva); + } } return NULL; @@ -442,6 +461,7 @@ int main(int argc, char *argv[]) bool do_runstate_flag = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG); bool do_eventfd_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL); bool do_evtchn_tests = do_eventfd_tests && !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND); + bool has_shinfo_hva = !!(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA); clock_gettime(CLOCK_REALTIME, &min_ts); @@ -452,7 +472,7 @@ int main(int argc, char *argv[]) SHINFO_REGION_GPA, SHINFO_REGION_SLOT, 3, 0); virt_map(vm, SHINFO_REGION_GVA, SHINFO_REGION_GPA, 3); - struct shared_info *shinfo = addr_gpa2hva(vm, SHINFO_VADDR); + shinfo = addr_gpa2hva(vm, SHINFO_VADDR); int zero_fd = open("/dev/zero", O_RDONLY); TEST_ASSERT(zero_fd != -1, "Failed to open /dev/zero"); @@ -488,10 +508,16 @@ int main(int argc, char *argv[]) "Failed to read back RUNSTATE_UPDATE_FLAG attr"); } - struct kvm_xen_hvm_attr ha = { - .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, - .u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE, - }; + struct kvm_xen_hvm_attr ha = {}; + + if (has_shinfo_hva) { + ha.type = KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA; + ha.u.shared_info.hva = (unsigned long)shinfo; + } else { + ha.type = KVM_XEN_ATTR_TYPE_SHARED_INFO; + ha.u.shared_info.gfn = SHINFO_ADDR / PAGE_SIZE; + } + vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha); /* From b4dfbfdc95387eeb8c900cf80116088a7a663be5 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:10 +0000 Subject: [PATCH 433/814] KVM: selftests: re-map Xen's vcpu_info using HVA rather than GPA If the relevant capability (KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA) is present then re-map vcpu_info using the HVA part way through the tests to make sure then there is no functional change. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-16-paul@xen.org Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/xen_shinfo_test.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index a61500ff0822..d2ea0435f4f7 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -62,6 +62,7 @@ enum { TEST_POLL_TIMEOUT, TEST_POLL_MASKED, TEST_POLL_WAKE, + SET_VCPU_INFO, TEST_TIMER_PAST, TEST_LOCKING_SEND_RACE, TEST_LOCKING_POLL_RACE, @@ -321,6 +322,10 @@ static void guest_code(void) GUEST_SYNC(TEST_POLL_WAKE); + /* Set the vcpu_info to point at exactly the place it already is to + * make sure the attribute is functional. */ + GUEST_SYNC(SET_VCPU_INFO); + /* A timer wake an *unmasked* port which should wake us with an * actual interrupt, while we're polling on a different port. */ ports[0]++; @@ -888,6 +893,16 @@ int main(int argc, char *argv[]) alarm(1); break; + case SET_VCPU_INFO: + if (has_shinfo_hva) { + struct kvm_xen_vcpu_attr vih = { + .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA, + .u.hva = (unsigned long)vinfo + }; + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &vih); + } + break; + case TEST_TIMER_PAST: TEST_ASSERT(!evtchn_irq_expected, "Expected event channel IRQ but it didn't happen"); From 615451d8cb3f82265e0ed60414b606b4fa120f5e Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:11 +0000 Subject: [PATCH 434/814] KVM: x86/xen: advertize the KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA capability Now that all relevant kernel changes and selftests are in place, enable the new capability. Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-17-paul@xen.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 415723a28dce..2911e6383fef 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4682,7 +4682,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) KVM_XEN_HVM_CONFIG_SHARED_INFO | KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL | KVM_XEN_HVM_CONFIG_EVTCHN_SEND | - KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE; + KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE | + KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA; if (sched_info_on()) r |= KVM_XEN_HVM_CONFIG_RUNSTATE | KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG; From 9fa336e343b2c7f6bad6fd5fa2e1cf55e80d3ed1 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:14 +0000 Subject: [PATCH 435/814] KVM: pfncache: check the need for invalidation under read lock first When processing mmu_notifier invalidations for gpc caches, pre-check for overlap with the invalidation event while holding gpc->lock for read, and only take gpc->lock for write if the cache needs to be invalidated. Doing a pre-check without taking gpc->lock for write avoids unnecessarily contending the lock for unrelated invalidations, which is very beneficial for caches that are heavily used (but rarely subjected to mmu_notifier invalidations). Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-20-paul@xen.org Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index a47ca6fd75c2..9ac8c9da4eda 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -29,14 +29,30 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start, spin_lock(&kvm->gpc_lock); list_for_each_entry(gpc, &kvm->gpc_list, list) { - write_lock_irq(&gpc->lock); + read_lock_irq(&gpc->lock); /* Only a single page so no need to care about length */ if (gpc->valid && !is_error_noslot_pfn(gpc->pfn) && gpc->uhva >= start && gpc->uhva < end) { - gpc->valid = false; + read_unlock_irq(&gpc->lock); + + /* + * There is a small window here where the cache could + * be modified, and invalidation would no longer be + * necessary. Hence check again whether invalidation + * is still necessary once the write lock has been + * acquired. + */ + + write_lock_irq(&gpc->lock); + if (gpc->valid && !is_error_noslot_pfn(gpc->pfn) && + gpc->uhva >= start && gpc->uhva < end) + gpc->valid = false; + write_unlock_irq(&gpc->lock); + continue; } - write_unlock_irq(&gpc->lock); + + read_unlock_irq(&gpc->lock); } spin_unlock(&kvm->gpc_lock); } From 003d914220c97ef93cabfe3ec4e245e2383e19e9 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 15 Feb 2024 15:29:15 +0000 Subject: [PATCH 436/814] KVM: x86/xen: allow vcpu_info content to be 'safely' copied If the guest sets an explicit vcpu_info GPA then, for any of the first 32 vCPUs, the content of the default vcpu_info in the shared_info page must be copied into the new location. Because this copy may race with event delivery (which updates the 'evtchn_pending_sel' field in vcpu_info), event delivery needs to be deferred until the copy is complete. Happily there is already a shadow of 'evtchn_pending_sel' in kvm_vcpu_xen that is used in atomic context if the vcpu_info PFN cache has been invalidated so that the update of vcpu_info can be deferred until the cache can be refreshed (on vCPU thread's the way back into guest context). Use this shadow if the vcpu_info cache has been *deactivated*, so that the VMM can safely copy the vcpu_info content and then re-activate the cache with the new GPA. To do this, stop considering an inactive vcpu_info cache as a hard error in kvm_xen_set_evtchn_fast(), and let the existing kvm_gpc_check() fail and kick the vCPU (if necessary). Signed-off-by: Paul Durrant Reviewed-by: David Woodhouse Link: https://lore.kernel.org/r/20240215152916.1158-21-paul@xen.org [sean: add a bit of verbosity to the changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index cd05faa19308..8a04e0ae9245 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1697,9 +1697,6 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) WRITE_ONCE(xe->vcpu_idx, vcpu->vcpu_idx); } - if (!vcpu->arch.xen.vcpu_info_cache.active) - return -EINVAL; - if (xe->port >= max_evtchn_port(kvm)) return -EINVAL; From 392703b6a18bbecbb2ae652619a705454f0fa0d6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 13 Feb 2024 08:59:12 +0000 Subject: [PATCH 437/814] dt-bindings: interrupt-controller: renesas,rzg2l-irqc: Update interrupts All the RZ/G2L and alike SoC's (listed below) have ECCRAM0/1 interrupts supported by the IRQC block, reflect the same in DT binding doc. - R9A07G043U - RZ/G2UL - R9A07G044L/R9A07G044LC - RZ/{G2L,G2LC} - R9A07G054 - RZ/V2L - R9A08G045 - RZ/G3S For the RZ/G3S SoC ("R9A08G045") ECCRAM0/1 interrupts combined into single interrupt so we just use the below to represent them: - ec7tie1-0 - ec7tie2-0 - ec7tiovf-0 Previously, it was assumed that BUS-error and ECCRAM0/1 error interrupts were only supported by RZ/G2UL ("R9A07G043U") and RZ/G3S ("R9A08G045") SoCs. However, in reality, all RZ/G2L and similar SoCs (listed above) support these interrupts. Therefore, mark the 'interrupt-names' property as required for all the SoCs and update the example node in the binding document. Fixes: 96fed779d3d4 ("dt-bindings: interrupt-controller: Add Renesas RZ/G2L Interrupt Controller") Fixes: 1cf0697a24ef ("dt-bindings: interrupt-controller: renesas,rzg2l-irqc: Document RZ/G3S") Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240213085912.56600-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Rob Herring --- .../renesas,rzg2l-irqc.yaml | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml index d3b5aec0a3f7..daef4ee06f4e 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml @@ -44,7 +44,7 @@ properties: maxItems: 1 interrupts: - minItems: 41 + minItems: 45 items: - description: NMI interrupt - description: IRQ0 interrupt @@ -88,9 +88,15 @@ properties: - description: GPIO interrupt, TINT30 - description: GPIO interrupt, TINT31 - description: Bus error interrupt + - description: ECCRAM0 or combined ECCRAM0/1 1bit error interrupt + - description: ECCRAM0 or combined ECCRAM0/1 2bit error interrupt + - description: ECCRAM0 or combined ECCRAM0/1 error overflow interrupt + - description: ECCRAM1 1bit error interrupt + - description: ECCRAM1 2bit error interrupt + - description: ECCRAM1 error overflow interrupt interrupt-names: - minItems: 41 + minItems: 45 items: - const: nmi - const: irq0 @@ -134,6 +140,12 @@ properties: - const: tint30 - const: tint31 - const: bus-err + - const: ec7tie1-0 + - const: ec7tie2-0 + - const: ec7tiovf-0 + - const: ec7tie1-1 + - const: ec7tie2-1 + - const: ec7tiovf-1 clocks: maxItems: 2 @@ -156,6 +168,7 @@ required: - interrupt-controller - reg - interrupts + - interrupt-names - clocks - clock-names - power-domains @@ -169,16 +182,19 @@ allOf: compatible: contains: enum: - - renesas,r9a07g043u-irqc - renesas,r9a08g045-irqc then: properties: interrupts: - minItems: 42 + maxItems: 45 interrupt-names: - minItems: 42 - required: - - interrupt-names + maxItems: 45 + else: + properties: + interrupts: + minItems: 48 + interrupt-names: + minItems: 48 unevaluatedProperties: false @@ -233,7 +249,14 @@ examples: , , , - ; + , + , + , + , + , + , + , + ; interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3", "irq4", "irq5", "irq6", "irq7", @@ -244,7 +267,10 @@ examples: "tint16", "tint17", "tint18", "tint19", "tint20", "tint21", "tint22", "tint23", "tint24", "tint25", "tint26", "tint27", - "tint28", "tint29", "tint30", "tint31"; + "tint28", "tint29", "tint30", "tint31", + "bus-err", "ec7tie1-0", "ec7tie2-0", + "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", + "ec7tiovf-1"; clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>, <&cpg CPG_MOD R9A07G044_IA55_PCLK>; clock-names = "clk", "pclk"; From 99101dda29e3186b1356b0dc4dbb835c02c71ac9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 22 Feb 2024 14:12:09 +0000 Subject: [PATCH 438/814] KVM: arm64: Make build-time check of RES0/RES1 bits optional In order to ease the transition towards a state of absolute paranoia where all RES0/RES1 bits gets checked against what KVM know of them, make the checks optional and guarded by a config symbol (CONFIG_KVM_ARM64_RES_BITS_PARANOIA) default to n. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/kvm/87frxka7ud.wl-maz@kernel.org/ Signed-off-by: Oliver Upton --- arch/arm64/kvm/Kconfig | 11 +++++++++++ arch/arm64/kvm/check-res-bits.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 5c2a672c06a8..fa9389270cfe 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -67,4 +67,15 @@ config PROTECTED_NVHE_STACKTRACE If unsure, or not using protected nVHE (pKVM), say N. +config KVM_ARM64_RES_BITS_PARANOIA + bool "Build-time check of RES0/RES1 bits" + depends on KVM + default n + help + Say Y here to validate that KVM's knowledge of most system + registers' RES0/RES1 bits matches when the rest of the kernel + defines. Expect the build to fail badly if you enable this. + + Just say N. + endif # VIRTUALIZATION diff --git a/arch/arm64/kvm/check-res-bits.h b/arch/arm64/kvm/check-res-bits.h index 967b5d171d53..2d98e60efc3c 100644 --- a/arch/arm64/kvm/check-res-bits.h +++ b/arch/arm64/kvm/check-res-bits.h @@ -21,6 +21,8 @@ */ static inline void check_res_bits(void) { +#ifdef CONFIG_KVM_ARM64_RES_BITS_PARANOIA + BUILD_BUG_ON(OSDTRRX_EL1_RES0 != (GENMASK_ULL(63, 32))); BUILD_BUG_ON(MDCCINT_EL1_RES0 != (GENMASK_ULL(63, 31) | GENMASK_ULL(28, 0))); BUILD_BUG_ON(MDSCR_EL1_RES0 != (GENMASK_ULL(63, 36) | GENMASK_ULL(28, 28) | GENMASK_ULL(25, 24) | GENMASK_ULL(20, 20) | GENMASK_ULL(18, 16) | GENMASK_ULL(11, 7) | GENMASK_ULL(5, 1))); @@ -118,4 +120,6 @@ static inline void check_res_bits(void) BUILD_BUG_ON(TRBMAR_EL1_RES0 != (GENMASK_ULL(63, 12))); BUILD_BUG_ON(TRBTRG_EL1_RES0 != (GENMASK_ULL(63, 32))); BUILD_BUG_ON(TRBIDR_EL1_RES0 != (GENMASK_ULL(63, 12) | GENMASK_ULL(7, 6))); + +#endif } From 19032628bd7ce8a39cdf0521b6418bf88c25ec80 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Mon, 15 Jan 2024 14:34:34 +0800 Subject: [PATCH 439/814] vfio/pci: WARN_ON driver_override kasprintf failure kasprintf() returns a pointer to dynamically allocated memory which can be NULL upon failure. This is a blocking notifier callback, so errno isn't a proper return value. Use WARN_ON to small allocation failures. Signed-off-by: Kunwu Chan Link: https://lore.kernel.org/r/20240115063434.20278-1-chentao@kylinos.cn Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 1cbc990d42e0..61aa19666050 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -2047,6 +2047,7 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb, pci_name(pdev)); pdev->driver_override = kasprintf(GFP_KERNEL, "%s", vdev->vdev.ops->name); + WARN_ON(!pdev->driver_override); } else if (action == BUS_NOTIFY_BOUND_DRIVER && pdev->is_virtfn && physfn == vdev->pdev) { struct pci_driver *drv = pci_dev_driver(pdev); From 1cbcb564f5b67cee2fc2f78132b9733118a79c6d Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Mon, 5 Feb 2024 14:48:24 +0200 Subject: [PATCH 440/814] net/mlx5: Add the IFC related bits for query tracker Add the IFC related bits for query tracker. Signed-off-by: Yishai Hadas Reviewed-by: Kevin Tian Acked-by: Leon Romanovsky Link: https://lore.kernel.org/r/20240205124828.232701-2-yishaih@nvidia.com Signed-off-by: Alex Williamson --- include/linux/mlx5/mlx5_ifc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index c726f90ab752..0e513e372bf0 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -12672,6 +12672,11 @@ struct mlx5_ifc_modify_page_track_obj_in_bits { struct mlx5_ifc_page_track_bits obj_context; }; +struct mlx5_ifc_query_page_track_obj_out_bits { + struct mlx5_ifc_general_obj_out_cmd_hdr_bits general_obj_out_cmd_hdr; + struct mlx5_ifc_page_track_bits obj_context; +}; + struct mlx5_ifc_msecq_reg_bits { u8 reserved_at_0[0x20]; From f886473071d6c0c98857eb5d7871a5e5ac26e950 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Mon, 5 Feb 2024 14:48:25 +0200 Subject: [PATCH 441/814] vfio/mlx5: Add support for tracker object change event Add support for tracker object change event by referring to its MLX5_EVENT_TYPE_OBJECT_CHANGE event when occurs. This lets the driver recognize whether the firmware moved the tracker object to an error state. In that case, the driver will skip/block any usage of that object including an early exit in case the object was previously marked with an error. This functionality also covers the case when no CQE is delivered as of the error state. The driver was adapted to the device specification to handle the above. Signed-off-by: Yishai Hadas Reviewed-by: Kevin Tian Acked-by: Leon Romanovsky Link: https://lore.kernel.org/r/20240205124828.232701-3-yishaih@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/mlx5/cmd.c | 48 +++++++++++++++++++++++++++++++++++++ drivers/vfio/pci/mlx5/cmd.h | 1 + 2 files changed, 49 insertions(+) diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index efd1d252cdc9..8a39ff19da28 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -149,6 +149,12 @@ int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev, return 0; } +static void set_tracker_change_event(struct mlx5vf_pci_core_device *mvdev) +{ + mvdev->tracker.object_changed = true; + complete(&mvdev->tracker_comp); +} + static void set_tracker_error(struct mlx5vf_pci_core_device *mvdev) { /* Mark the tracker under an error and wake it up if it's running */ @@ -900,6 +906,29 @@ static int mlx5vf_cmd_modify_tracker(struct mlx5_core_dev *mdev, return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); } +static int mlx5vf_cmd_query_tracker(struct mlx5_core_dev *mdev, + struct mlx5_vhca_page_tracker *tracker) +{ + u32 out[MLX5_ST_SZ_DW(query_page_track_obj_out)] = {}; + u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; + void *obj_context; + void *cmd_hdr; + int err; + + cmd_hdr = MLX5_ADDR_OF(modify_page_track_obj_in, in, general_obj_in_cmd_hdr); + MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_PAGE_TRACK); + MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, tracker->id); + + err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (err) + return err; + + obj_context = MLX5_ADDR_OF(query_page_track_obj_out, out, obj_context); + tracker->status = MLX5_GET(page_track, obj_context, state); + return 0; +} + static int alloc_cq_frag_buf(struct mlx5_core_dev *mdev, struct mlx5_vhca_cq_buf *buf, int nent, int cqe_size) @@ -957,9 +986,11 @@ static int mlx5vf_event_notifier(struct notifier_block *nb, unsigned long type, mlx5_nb_cof(nb, struct mlx5_vhca_page_tracker, nb); struct mlx5vf_pci_core_device *mvdev = container_of( tracker, struct mlx5vf_pci_core_device, tracker); + struct mlx5_eqe_obj_change *object; struct mlx5_eqe *eqe = data; u8 event_type = (u8)type; u8 queue_type; + u32 obj_id; int qp_num; switch (event_type) { @@ -975,6 +1006,12 @@ static int mlx5vf_event_notifier(struct notifier_block *nb, unsigned long type, break; set_tracker_error(mvdev); break; + case MLX5_EVENT_TYPE_OBJECT_CHANGE: + object = &eqe->data.obj_change; + obj_id = be32_to_cpu(object->obj_id); + if (obj_id == tracker->id) + set_tracker_change_event(mvdev); + break; default: break; } @@ -1634,6 +1671,11 @@ int mlx5vf_tracker_read_and_clear(struct vfio_device *vdev, unsigned long iova, goto end; } + if (tracker->is_err) { + err = -EIO; + goto end; + } + mdev = mvdev->mdev; err = mlx5vf_cmd_modify_tracker(mdev, tracker->id, iova, length, MLX5_PAGE_TRACK_STATE_REPORTING); @@ -1652,6 +1694,12 @@ int mlx5vf_tracker_read_and_clear(struct vfio_device *vdev, unsigned long iova, dirty, &tracker->status); if (poll_err == CQ_EMPTY) { wait_for_completion(&mvdev->tracker_comp); + if (tracker->object_changed) { + tracker->object_changed = false; + err = mlx5vf_cmd_query_tracker(mdev, tracker); + if (err) + goto end; + } continue; } } diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h index f2c7227fa683..0d6a2db3d801 100644 --- a/drivers/vfio/pci/mlx5/cmd.h +++ b/drivers/vfio/pci/mlx5/cmd.h @@ -162,6 +162,7 @@ struct mlx5_vhca_page_tracker { u32 id; u32 pdn; u8 is_err:1; + u8 object_changed:1; struct mlx5_uars_page *uar; struct mlx5_vhca_cq cq; struct mlx5_vhca_qp *host_qp; From 793d4bfa3103a238c6e48eb13c38fa31acd18b94 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Mon, 5 Feb 2024 14:48:26 +0200 Subject: [PATCH 442/814] vfio/mlx5: Handle the EREMOTEIO error upon the SAVE command The SAVE command uses the async command interface over the PF. Upon a failure in the firmware -EREMOTEIO is returned. In that case call mlx5_cmd_out_err() to let it print the command failure details including the firmware syndrome. Note: The other commands in the driver use the sync command interface in a way that a firmware syndrome is printed upon an error inside mlx5_core. Signed-off-by: Yishai Hadas Reviewed-by: Kevin Tian Acked-by: Leon Romanovsky Link: https://lore.kernel.org/r/20240205124828.232701-4-yishaih@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/mlx5/cmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index 8a39ff19da28..6b45bd7d89ad 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -614,8 +614,13 @@ static void mlx5vf_save_callback(int status, struct mlx5_async_work *context) err: /* The error flow can't run from an interrupt context */ - if (status == -EREMOTEIO) + if (status == -EREMOTEIO) { status = MLX5_GET(save_vhca_state_out, async_data->out, status); + /* Failed in FW, print cmd out failure details */ + mlx5_cmd_out_err(migf->mvdev->mdev, MLX5_CMD_OP_SAVE_VHCA_STATE, 0, + async_data->out); + } + async_data->status = status; queue_work(migf->mvdev->cb_wq, &async_data->work); } From d8d577b5fa2a8832f5730ac26e905d8ac131882d Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Mon, 5 Feb 2024 14:48:27 +0200 Subject: [PATCH 443/814] vfio/mlx5: Block incremental query upon migf state error Block incremental query which is state-dependent once the migration file was previously marked with state error. This may prevent redundant calls to firmware upon PRE_COPY which will end-up with a failure and a syndrome printed in dmesg. Signed-off-by: Yishai Hadas Reviewed-by: Kevin Tian Acked-by: Leon Romanovsky Link: https://lore.kernel.org/r/20240205124828.232701-5-yishaih@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/mlx5/cmd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index 6b45bd7d89ad..6800e4ffe9ee 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -121,6 +121,11 @@ int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev, } query_flags &= ~MLX5VF_QUERY_INC; } + /* Block incremental query which is state-dependent */ + if (mvdev->saving_migf->state == MLX5_MIGF_STATE_ERROR) { + complete(&mvdev->saving_migf->save_comp); + return -ENODEV; + } } MLX5_SET(query_vhca_migration_state_in, in, opcode, From 6de042240b0f654940c196a491c90e81257e49b9 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Mon, 5 Feb 2024 14:48:28 +0200 Subject: [PATCH 444/814] vfio/mlx5: Let firmware knows upon leaving PRE_COPY back to RUNNING Let firmware knows upon leaving PRE_COPY back to RUNNING as of some error in the target/migration cancellation. This will let firmware cleaning its internal resources that were turned on upon PRE_COPY. The flow is based on the device specification in this area. Signed-off-by: Yishai Hadas Reviewed-by: Kevin Tian Acked-by: Leon Romanovsky Link: https://lore.kernel.org/r/20240205124828.232701-6-yishaih@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/mlx5/cmd.c | 14 +++++++++---- drivers/vfio/pci/mlx5/cmd.h | 4 +++- drivers/vfio/pci/mlx5/main.c | 39 +++++++++++++++++++++++++++++------- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index 6800e4ffe9ee..c54bcd5d0917 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -108,8 +108,9 @@ int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev, ret = wait_for_completion_interruptible(&mvdev->saving_migf->save_comp); if (ret) return ret; - if (mvdev->saving_migf->state == - MLX5_MIGF_STATE_PRE_COPY_ERROR) { + /* Upon cleanup, ignore previous pre_copy error state */ + if (mvdev->saving_migf->state == MLX5_MIGF_STATE_PRE_COPY_ERROR && + !(query_flags & MLX5VF_QUERY_CLEANUP)) { /* * In case we had a PRE_COPY error, only query full * image for final image @@ -200,7 +201,7 @@ void mlx5vf_cmd_close_migratable(struct mlx5vf_pci_core_device *mvdev) /* Must be done outside the lock to let it progress */ set_tracker_error(mvdev); mutex_lock(&mvdev->state_mutex); - mlx5vf_disable_fds(mvdev); + mlx5vf_disable_fds(mvdev, NULL); _mlx5vf_free_page_tracker_resources(mvdev); mlx5vf_state_mutex_unlock(mvdev); } @@ -639,6 +640,7 @@ int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev, u32 in[MLX5_ST_SZ_DW(save_vhca_state_in)] = {}; struct mlx5_vhca_data_buffer *header_buf = NULL; struct mlx5vf_async_data *async_data; + bool pre_copy_cleanup = false; int err; lockdep_assert_held(&mvdev->state_mutex); @@ -649,6 +651,10 @@ int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev, if (err) return err; + if ((migf->state == MLX5_MIGF_STATE_PRE_COPY || + migf->state == MLX5_MIGF_STATE_PRE_COPY_ERROR) && !track && !inc) + pre_copy_cleanup = true; + if (migf->state == MLX5_MIGF_STATE_PRE_COPY_ERROR) /* * In case we had a PRE_COPY error, SAVE is triggered only for @@ -667,7 +673,7 @@ int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev, async_data = &migf->async_data; async_data->buf = buf; - async_data->stop_copy_chunk = !track; + async_data->stop_copy_chunk = (!track && !pre_copy_cleanup); async_data->out = kvzalloc(out_size, GFP_KERNEL); if (!async_data->out) { err = -ENOMEM; diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h index 0d6a2db3d801..707393df36c4 100644 --- a/drivers/vfio/pci/mlx5/cmd.h +++ b/drivers/vfio/pci/mlx5/cmd.h @@ -197,6 +197,7 @@ struct mlx5vf_pci_core_device { enum { MLX5VF_QUERY_INC = (1UL << 0), MLX5VF_QUERY_FINAL = (1UL << 1), + MLX5VF_QUERY_CLEANUP = (1UL << 2), }; int mlx5vf_cmd_suspend_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod); @@ -232,7 +233,8 @@ int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, struct page *mlx5vf_get_migration_page(struct mlx5_vhca_data_buffer *buf, unsigned long offset); void mlx5vf_state_mutex_unlock(struct mlx5vf_pci_core_device *mvdev); -void mlx5vf_disable_fds(struct mlx5vf_pci_core_device *mvdev); +void mlx5vf_disable_fds(struct mlx5vf_pci_core_device *mvdev, + enum mlx5_vf_migf_state *last_save_state); void mlx5vf_mig_file_cleanup_cb(struct work_struct *_work); void mlx5vf_mig_file_set_save_work(struct mlx5_vf_migration_file *migf, u8 chunk_num, size_t next_required_umem_size); diff --git a/drivers/vfio/pci/mlx5/main.c b/drivers/vfio/pci/mlx5/main.c index fe09a8c8af95..3982fcf60cf2 100644 --- a/drivers/vfio/pci/mlx5/main.c +++ b/drivers/vfio/pci/mlx5/main.c @@ -1146,7 +1146,8 @@ end: return ERR_PTR(ret); } -void mlx5vf_disable_fds(struct mlx5vf_pci_core_device *mvdev) +void mlx5vf_disable_fds(struct mlx5vf_pci_core_device *mvdev, + enum mlx5_vf_migf_state *last_save_state) { if (mvdev->resuming_migf) { mlx5vf_disable_fd(mvdev->resuming_migf); @@ -1157,6 +1158,8 @@ void mlx5vf_disable_fds(struct mlx5vf_pci_core_device *mvdev) if (mvdev->saving_migf) { mlx5_cmd_cleanup_async_ctx(&mvdev->saving_migf->async_ctx); cancel_work_sync(&mvdev->saving_migf->async_data.work); + if (last_save_state) + *last_save_state = mvdev->saving_migf->state; mlx5vf_disable_fd(mvdev->saving_migf); wake_up_interruptible(&mvdev->saving_migf->poll_wait); mlx5fv_cmd_clean_migf_resources(mvdev->saving_migf); @@ -1217,12 +1220,34 @@ mlx5vf_pci_step_device_state_locked(struct mlx5vf_pci_core_device *mvdev, return migf->filp; } - if ((cur == VFIO_DEVICE_STATE_STOP_COPY && new == VFIO_DEVICE_STATE_STOP) || - (cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_RUNNING) || + if (cur == VFIO_DEVICE_STATE_STOP_COPY && new == VFIO_DEVICE_STATE_STOP) { + mlx5vf_disable_fds(mvdev, NULL); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_RUNNING) || (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_RUNNING_P2P)) { - mlx5vf_disable_fds(mvdev); - return NULL; + struct mlx5_vf_migration_file *migf = mvdev->saving_migf; + struct mlx5_vhca_data_buffer *buf; + enum mlx5_vf_migf_state state; + size_t size; + + ret = mlx5vf_cmd_query_vhca_migration_state(mvdev, &size, NULL, + MLX5VF_QUERY_INC | MLX5VF_QUERY_CLEANUP); + if (ret) + return ERR_PTR(ret); + buf = mlx5vf_get_data_buffer(migf, size, DMA_FROM_DEVICE); + if (IS_ERR(buf)) + return ERR_CAST(buf); + /* pre_copy cleanup */ + ret = mlx5vf_cmd_save_vhca_state(mvdev, migf, buf, false, false); + if (ret) { + mlx5vf_put_data_buffer(buf); + return ERR_PTR(ret); + } + mlx5vf_disable_fds(mvdev, &state); + return (state != MLX5_MIGF_STATE_ERROR) ? NULL : ERR_PTR(-EIO); } if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_RESUMING) { @@ -1244,7 +1269,7 @@ mlx5vf_pci_step_device_state_locked(struct mlx5vf_pci_core_device *mvdev, if (ret) return ERR_PTR(ret); } - mlx5vf_disable_fds(mvdev); + mlx5vf_disable_fds(mvdev, NULL); return NULL; } @@ -1289,7 +1314,7 @@ again: mvdev->deferred_reset = false; spin_unlock(&mvdev->reset_lock); mvdev->mig_state = VFIO_DEVICE_STATE_RUNNING; - mlx5vf_disable_fds(mvdev); + mlx5vf_disable_fds(mvdev, NULL); goto again; } mutex_unlock(&mvdev->state_mutex); From 05f3a0bd094c08dce69938306c31b0e39b5f465a Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 5 Feb 2024 16:54:18 -0700 Subject: [PATCH 445/814] MAINTAINERS: Re-alphabetize VFIO The vfio-pci virtio variant entry slipped in out of order. Link: https://lore.kernel.org/r/20240205235427.2103714-1-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- MAINTAINERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9ed4d3868539..9d0ca59f1ddc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23089,13 +23089,6 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/pci/mlx5/ -VFIO VIRTIO PCI DRIVER -M: Yishai Hadas -L: kvm@vger.kernel.org -L: virtualization@lists.linux-foundation.org -S: Maintained -F: drivers/vfio/pci/virtio - VFIO PCI DEVICE SPECIFIC DRIVERS R: Jason Gunthorpe R: Yishai Hadas @@ -23119,6 +23112,13 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ +VFIO VIRTIO PCI DRIVER +M: Yishai Hadas +L: kvm@vger.kernel.org +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/vfio/pci/virtio + VGA_SWITCHEROO R: Lukas Wunner S: Maintained From 77943f4d2de0c5fa284013b97967e6c271c04310 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Thu, 8 Feb 2024 17:02:04 -0300 Subject: [PATCH 446/814] vfio: mdev: make mdev_bus_type const Now that the driver core can properly handle constant struct bus_type, move the mdev_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Reviewed-by: Jason Gunthorpe Reviewed-by: Kirti Wankhede Link: https://lore.kernel.org/r/20240208-bus_cleanup-vfio-v1-1-ed5da3019949@marliere.net Signed-off-by: Alex Williamson --- drivers/vfio/mdev/mdev_driver.c | 2 +- drivers/vfio/mdev/mdev_private.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c index 7825d83a55f8..b98322966b3e 100644 --- a/drivers/vfio/mdev/mdev_driver.c +++ b/drivers/vfio/mdev/mdev_driver.c @@ -40,7 +40,7 @@ static int mdev_match(struct device *dev, struct device_driver *drv) return 0; } -struct bus_type mdev_bus_type = { +const struct bus_type mdev_bus_type = { .name = "mdev", .probe = mdev_probe, .remove = mdev_remove, diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index af457b27f607..63a1316b08b7 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -13,7 +13,7 @@ int mdev_bus_register(void); void mdev_bus_unregister(void); -extern struct bus_type mdev_bus_type; +extern const struct bus_type mdev_bus_type; extern const struct attribute_group *mdev_device_groups[]; #define to_mdev_type_attr(_attr) \ From 4de676d494cd8fb2b4c65e58c19ebbdb36673957 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Tue, 20 Feb 2024 17:20:53 +0530 Subject: [PATCH 447/814] vfio/pci: rename and export do_io_rw() do_io_rw() is used to read/write to the device MMIO. The grace hopper VFIO PCI variant driver require this functionality to read/write to its memory. Rename this as vfio_pci_core functions and export as GPL. Reviewed-by: Kevin Tian Reviewed-by: Yishai Hadas Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240220115055.23546-2-ankita@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_rdwr.c | 16 +++++++++------- include/linux/vfio_pci_core.h | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 07fea08ea8a2..03b8f7ada1ac 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -96,10 +96,10 @@ VFIO_IOREAD(32) * reads with -1. This is intended for handling MSI-X vector tables and * leftover space for ROM BARs. */ -static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, - void __iomem *io, char __user *buf, - loff_t off, size_t count, size_t x_start, - size_t x_end, bool iswrite) +ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, + void __iomem *io, char __user *buf, + loff_t off, size_t count, size_t x_start, + size_t x_end, bool iswrite) { ssize_t done = 0; int ret; @@ -201,6 +201,7 @@ static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, return done; } +EXPORT_SYMBOL_GPL(vfio_pci_core_do_io_rw); int vfio_pci_core_setup_barmap(struct vfio_pci_core_device *vdev, int bar) { @@ -279,8 +280,8 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, x_end = vdev->msix_offset + vdev->msix_size; } - done = do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, - count, x_start, x_end, iswrite); + done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, + count, x_start, x_end, iswrite); if (done >= 0) *ppos += done; @@ -348,7 +349,8 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, * probing, so we don't currently worry about access in relation * to the memory enable bit in the command register. */ - done = do_io_rw(vdev, false, iomem, buf, off, count, 0, 0, iswrite); + done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, + 0, 0, iswrite); vga_put(vdev->pdev, rsrc); diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 85e84b92751b..cf9480a31f3e 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -130,7 +130,10 @@ void vfio_pci_core_finish_enable(struct vfio_pci_core_device *vdev); int vfio_pci_core_setup_barmap(struct vfio_pci_core_device *vdev, int bar); pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev, pci_channel_state_t state); - +ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, + void __iomem *io, char __user *buf, + loff_t off, size_t count, size_t x_start, + size_t x_end, bool iswrite); #define VFIO_IOWRITE_DECLATION(size) \ int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \ bool test_mem, u##size val, void __iomem *io); From 30e920e1debb437e5aea7a4ccdab61634354297a Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Tue, 20 Feb 2024 17:20:54 +0530 Subject: [PATCH 448/814] vfio/pci: rename and export range_intersect_range range_intersect_range determines an overlap between two ranges. If an overlap, the helper function returns the overlapping offset and size. The VFIO PCI variant driver emulates the PCI config space BAR offset registers. These offset may be accessed for read/write with a variety of lengths including sub-word sizes from sub-word offsets. The driver makes use of this helper function to read/write the targeted part of the emulated register. Make this a vfio_pci_core function, rename and export as GPL. Also update references in virtio driver. Reviewed-by: Kevin Tian Reviewed-by: Yishai Hadas Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240220115055.23546-3-ankita@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_config.c | 42 +++++++++++++++++ drivers/vfio/pci/virtio/main.c | 72 +++++++++++------------------- include/linux/vfio_pci_core.h | 5 +++ 3 files changed, 73 insertions(+), 46 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 7e2e62ab0869..97422aafaa7b 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1966,3 +1966,45 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, return done; } + +/** + * vfio_pci_core_range_intersect_range() - Determine overlap between a buffer + * and register offset ranges. + * @buf_start: start offset of the buffer + * @buf_cnt: number of buffer bytes + * @reg_start: start register offset + * @reg_cnt: number of register bytes + * @buf_offset: start offset of overlap in the buffer + * @intersect_count: number of overlapping bytes + * @register_offset: start offset of overlap in register + * + * Returns: true if there is overlap, false if not. + * The overlap start and size is returned through function args. + */ +bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt, + loff_t reg_start, size_t reg_cnt, + loff_t *buf_offset, + size_t *intersect_count, + size_t *register_offset) +{ + if (buf_start <= reg_start && + buf_start + buf_cnt > reg_start) { + *buf_offset = reg_start - buf_start; + *intersect_count = min_t(size_t, reg_cnt, + buf_start + buf_cnt - reg_start); + *register_offset = 0; + return true; + } + + if (buf_start > reg_start && + buf_start < reg_start + reg_cnt) { + *buf_offset = 0; + *intersect_count = min_t(size_t, buf_cnt, + reg_start + reg_cnt - buf_start); + *register_offset = buf_start - reg_start; + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(vfio_pci_core_range_intersect_range); diff --git a/drivers/vfio/pci/virtio/main.c b/drivers/vfio/pci/virtio/main.c index d5af683837d3..b5d3a8c5bbc9 100644 --- a/drivers/vfio/pci/virtio/main.c +++ b/drivers/vfio/pci/virtio/main.c @@ -132,33 +132,6 @@ end: return ret ? ret : count; } -static bool range_intersect_range(loff_t range1_start, size_t count1, - loff_t range2_start, size_t count2, - loff_t *start_offset, - size_t *intersect_count, - size_t *register_offset) -{ - if (range1_start <= range2_start && - range1_start + count1 > range2_start) { - *start_offset = range2_start - range1_start; - *intersect_count = min_t(size_t, count2, - range1_start + count1 - range2_start); - *register_offset = 0; - return true; - } - - if (range1_start > range2_start && - range1_start < range2_start + count2) { - *start_offset = 0; - *intersect_count = min_t(size_t, count1, - range2_start + count2 - range1_start); - *register_offset = range1_start - range2_start; - return true; - } - - return false; -} - static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, char __user *buf, size_t count, loff_t *ppos) @@ -178,16 +151,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, if (ret < 0) return ret; - if (range_intersect_range(pos, count, PCI_DEVICE_ID, sizeof(val16), - ©_offset, ©_count, ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET); if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count)) return -EFAULT; } if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) && - range_intersect_range(pos, count, PCI_COMMAND, sizeof(val16), - ©_offset, ©_count, ®ister_offset)) { + vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset, copy_count)) return -EFAULT; @@ -197,16 +172,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, return -EFAULT; } - if (range_intersect_range(pos, count, PCI_REVISION_ID, sizeof(val8), - ©_offset, ©_count, ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID, + sizeof(val8), ©_offset, + ©_count, ®ister_offset)) { /* Transional needs to have revision 0 */ val8 = 0; if (copy_to_user(buf + copy_offset, &val8, copy_count)) return -EFAULT; } - if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, sizeof(val32), - ©_offset, ©_count, ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, + sizeof(val32), ©_offset, + ©_count, ®ister_offset)) { u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1); u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0); @@ -215,8 +192,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, return -EFAULT; } - if (range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, sizeof(val16), - ©_offset, ©_count, ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { /* * Transitional devices use the PCI subsystem device id as * virtio device id, same as legacy driver always did. @@ -227,8 +205,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, return -EFAULT; } - if (range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, sizeof(val16), - ©_offset, ©_count, ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET); if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count)) @@ -270,19 +249,20 @@ static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev, loff_t copy_offset; size_t copy_count; - if (range_intersect_range(pos, count, PCI_COMMAND, sizeof(virtvdev->pci_cmd), - ©_offset, ©_count, - ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, + sizeof(virtvdev->pci_cmd), + ©_offset, ©_count, + ®ister_offset)) { if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset, buf + copy_offset, copy_count)) return -EFAULT; } - if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, - sizeof(virtvdev->pci_base_addr_0), - ©_offset, ©_count, - ®ister_offset)) { + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, + sizeof(virtvdev->pci_base_addr_0), + ©_offset, ©_count, + ®ister_offset)) { if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset, buf + copy_offset, copy_count)) diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index cf9480a31f3e..a2c8b8bba711 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -134,6 +134,11 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, void __iomem *io, char __user *buf, loff_t off, size_t count, size_t x_start, size_t x_end, bool iswrite); +bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt, + loff_t reg_start, size_t reg_cnt, + loff_t *buf_offset, + size_t *intersect_count, + size_t *register_offset); #define VFIO_IOWRITE_DECLATION(size) \ int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \ bool test_mem, u##size val, void __iomem *io); From 701ab935859fcfd4a8c8a97f3ee4fb5294a9d481 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Tue, 20 Feb 2024 17:20:55 +0530 Subject: [PATCH 449/814] vfio/nvgrace-gpu: Add vfio pci variant module for grace hopper NVIDIA's upcoming Grace Hopper Superchip provides a PCI-like device for the on-chip GPU that is the logical OS representation of the internal proprietary chip-to-chip cache coherent interconnect. The device is peculiar compared to a real PCI device in that whilst there is a real 64b PCI BAR1 (comprising region 2 & region 3) on the device, it is not used to access device memory once the faster chip-to-chip interconnect is initialized (occurs at the time of host system boot). The device memory is accessed instead using the chip-to-chip interconnect that is exposed as a contiguous physically addressable region on the host. This device memory aperture can be obtained from host ACPI table using device_property_read_u64(), according to the FW specification. Since the device memory is cache coherent with the CPU, it can be mmap into the user VMA with a cacheable mapping using remap_pfn_range() and used like a regular RAM. The device memory is not added to the host kernel, but mapped directly as this reduces memory wastage due to struct pages. There is also a requirement of a minimum reserved 1G uncached region (termed as resmem) to support the Multi-Instance GPU (MIG) feature [1]. This is to work around a HW defect. Based on [2], the requisite properties (uncached, unaligned access) can be achieved through a VM mapping (S1) of NORMAL_NC and host (S2) mapping with MemAttr[2:0]=0b101. To provide a different non-cached property to the reserved 1G region, it needs to be carved out from the device memory and mapped as a separate region in Qemu VMA with pgprot_writecombine(). pgprot_writecombine() sets the Qemu VMA page properties (pgprot) as NORMAL_NC. Provide a VFIO PCI variant driver that adapts the unique device memory representation into a more standard PCI representation facing userspace. The variant driver exposes these two regions - the non-cached reserved (resmem) and the cached rest of the device memory (termed as usemem) as separate VFIO 64b BAR regions. This is divergent from the baremetal approach, where the device memory is exposed as a device memory region. The decision for a different approach was taken in view of the fact that it would necessiate additional code in Qemu to discover and insert those regions in the VM IPA, along with the additional VM ACPI DSDT changes to communicate the device memory region IPA to the VM workloads. Moreover, this behavior would have to be added to a variety of emulators (beyond top of tree Qemu) out there desiring grace hopper support. Since the device implements 64-bit BAR0, the VFIO PCI variant driver maps the uncached carved out region to the next available PCI BAR (i.e. comprising of region 2 and 3). The cached device memory aperture is assigned BAR region 4 and 5. Qemu will then naturally generate a PCI device in the VM with the uncached aperture reported as BAR2 region, the cacheable as BAR4. The variant driver provides emulation for these fake BARs' PCI config space offset registers. The hardware ensures that the system does not crash when the memory is accessed with the memory enable turned off. It synthesis ~0 reads and dropped writes on such access. So there is no need to support the disablement/enablement of BAR through PCI_COMMAND config space register. The memory layout on the host looks like the following: devmem (memlength) |--------------------------------------------------| |-------------cached------------------------|--NC--| | | usemem.memphys resmem.memphys PCI BARs need to be aligned to the power-of-2, but the actual memory on the device may not. A read or write access to the physical address from the last device PFN up to the next power-of-2 aligned physical address results in reading ~0 and dropped writes. Note that the GPU device driver [6] is capable of knowing the exact device memory size through separate means. The device memory size is primarily kept in the system ACPI tables for use by the VFIO PCI variant module. Note that the usemem memory is added by the VM Nvidia device driver [5] to the VM kernel as memblocks. Hence make the usable memory size memblock (MEMBLK_SIZE) aligned. This is a hardwired ABI value between the GPU FW and VFIO driver. The VM device driver make use of the same value for its calculation to determine USEMEM size. Currently there is no provision in KVM for a S2 mapping with MemAttr[2:0]=0b101, but there is an ongoing effort to provide the same [3]. As previously mentioned, resmem is mapped pgprot_writecombine(), that sets the Qemu VMA page properties (pgprot) as NORMAL_NC. Using the proposed changes in [3] and [4], KVM marks the region with MemAttr[2:0]=0b101 in S2. If the device memory properties are not present, the driver registers the vfio-pci-core function pointers. Since there are no ACPI memory properties generated for the VM, the variant driver inside the VM will only use the vfio-pci-core ops and hence try to map the BARs as non cached. This is not a problem as the CPUs have FWB enabled which blocks the VM mapping's ability to override the cacheability set by the host mapping. This goes along with a qemu series [6] to provides the necessary implementation of the Grace Hopper Superchip firmware specification so that the guest operating system can see the correct ACPI modeling for the coherent GPU device. Verified with the CUDA workload in the VM. [1] https://www.nvidia.com/en-in/technologies/multi-instance-gpu/ [2] section D8.5.5 of https://developer.arm.com/documentation/ddi0487/latest/ [3] https://lore.kernel.org/all/20240211174705.31992-1-ankita@nvidia.com/ [4] https://lore.kernel.org/all/20230907181459.18145-2-ankita@nvidia.com/ [5] https://github.com/NVIDIA/open-gpu-kernel-modules [6] https://lore.kernel.org/all/20231203060245.31593-1-ankita@nvidia.com/ Reviewed-by: Kevin Tian Reviewed-by: Yishai Hadas Reviewed-by: Zhi Wang Signed-off-by: Aniket Agashe Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240220115055.23546-4-ankita@nvidia.com Signed-off-by: Alex Williamson --- MAINTAINERS | 6 + drivers/vfio/pci/Kconfig | 2 + drivers/vfio/pci/Makefile | 2 + drivers/vfio/pci/nvgrace-gpu/Kconfig | 10 + drivers/vfio/pci/nvgrace-gpu/Makefile | 3 + drivers/vfio/pci/nvgrace-gpu/main.c | 879 ++++++++++++++++++++++++++ 6 files changed, 902 insertions(+) create mode 100644 drivers/vfio/pci/nvgrace-gpu/Kconfig create mode 100644 drivers/vfio/pci/nvgrace-gpu/Makefile create mode 100644 drivers/vfio/pci/nvgrace-gpu/main.c diff --git a/MAINTAINERS b/MAINTAINERS index 9d0ca59f1ddc..7625911ec2f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23089,6 +23089,12 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/pci/mlx5/ +VFIO NVIDIA GRACE GPU DRIVER +M: Ankit Agrawal +L: kvm@vger.kernel.org +S: Supported +F: drivers/vfio/pci/nvgrace-gpu/ + VFIO PCI DEVICE SPECIFIC DRIVERS R: Jason Gunthorpe R: Yishai Hadas diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 18c397df566d..15821a2d77d2 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig @@ -67,4 +67,6 @@ source "drivers/vfio/pci/pds/Kconfig" source "drivers/vfio/pci/virtio/Kconfig" +source "drivers/vfio/pci/nvgrace-gpu/Kconfig" + endmenu diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile index 046139a4eca5..ce7a61f1d912 100644 --- a/drivers/vfio/pci/Makefile +++ b/drivers/vfio/pci/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisilicon/ obj-$(CONFIG_PDS_VFIO_PCI) += pds/ obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio/ + +obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu/ diff --git a/drivers/vfio/pci/nvgrace-gpu/Kconfig b/drivers/vfio/pci/nvgrace-gpu/Kconfig new file mode 100644 index 000000000000..a7f624b37e41 --- /dev/null +++ b/drivers/vfio/pci/nvgrace-gpu/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +config NVGRACE_GPU_VFIO_PCI + tristate "VFIO support for the GPU in the NVIDIA Grace Hopper Superchip" + depends on ARM64 || (COMPILE_TEST && 64BIT) + select VFIO_PCI_CORE + help + VFIO support for the GPU in the NVIDIA Grace Hopper Superchip is + required to assign the GPU device to userspace using KVM/qemu/etc. + + If you don't know what to do here, say N. diff --git a/drivers/vfio/pci/nvgrace-gpu/Makefile b/drivers/vfio/pci/nvgrace-gpu/Makefile new file mode 100644 index 000000000000..3ca8c187897a --- /dev/null +++ b/drivers/vfio/pci/nvgrace-gpu/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu-vfio-pci.o +nvgrace-gpu-vfio-pci-y := main.o diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c new file mode 100644 index 000000000000..25814006352d --- /dev/null +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -0,0 +1,879 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved + */ + +#include +#include + +/* + * The device memory usable to the workloads running in the VM is cached + * and showcased as a 64b device BAR (comprising of BAR4 and BAR5 region) + * to the VM and is represented as usemem. + * Moreover, the VM GPU device driver needs a non-cacheable region to + * support the MIG feature. This region is also exposed as a 64b BAR + * (comprising of BAR2 and BAR3 region) and represented as resmem. + */ +#define RESMEM_REGION_INDEX VFIO_PCI_BAR2_REGION_INDEX +#define USEMEM_REGION_INDEX VFIO_PCI_BAR4_REGION_INDEX + +/* Memory size expected as non cached and reserved by the VM driver */ +#define RESMEM_SIZE SZ_1G + +/* A hardwired and constant ABI value between the GPU FW and VFIO driver. */ +#define MEMBLK_SIZE SZ_512M + +/* + * The state of the two device memory region - resmem and usemem - is + * saved as struct mem_region. + */ +struct mem_region { + phys_addr_t memphys; /* Base physical address of the region */ + size_t memlength; /* Region size */ + size_t bar_size; /* Reported region BAR size */ + __le64 bar_val; /* Emulated BAR offset registers */ + union { + void *memaddr; + void __iomem *ioaddr; + }; /* Base virtual address of the region */ +}; + +struct nvgrace_gpu_pci_core_device { + struct vfio_pci_core_device core_device; + /* Cached and usable memory for the VM. */ + struct mem_region usemem; + /* Non cached memory carved out from the end of device memory */ + struct mem_region resmem; + /* Lock to control device memory kernel mapping */ + struct mutex remap_lock; +}; + +static void nvgrace_gpu_init_fake_bar_emu_regs(struct vfio_device *core_vdev) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + + nvdev->resmem.bar_val = 0; + nvdev->usemem.bar_val = 0; +} + +/* Choose the structure corresponding to the fake BAR with a given index. */ +static struct mem_region * +nvgrace_gpu_memregion(int index, + struct nvgrace_gpu_pci_core_device *nvdev) +{ + if (index == USEMEM_REGION_INDEX) + return &nvdev->usemem; + + if (index == RESMEM_REGION_INDEX) + return &nvdev->resmem; + + return NULL; +} + +static int nvgrace_gpu_open_device(struct vfio_device *core_vdev) +{ + struct vfio_pci_core_device *vdev = + container_of(core_vdev, struct vfio_pci_core_device, vdev); + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + int ret; + + ret = vfio_pci_core_enable(vdev); + if (ret) + return ret; + + if (nvdev->usemem.memlength) { + nvgrace_gpu_init_fake_bar_emu_regs(core_vdev); + mutex_init(&nvdev->remap_lock); + } + + vfio_pci_core_finish_enable(vdev); + + return 0; +} + +static void nvgrace_gpu_close_device(struct vfio_device *core_vdev) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + + /* Unmap the mapping to the device memory cached region */ + if (nvdev->usemem.memaddr) { + memunmap(nvdev->usemem.memaddr); + nvdev->usemem.memaddr = NULL; + } + + /* Unmap the mapping to the device memory non-cached region */ + if (nvdev->resmem.ioaddr) { + iounmap(nvdev->resmem.ioaddr); + nvdev->resmem.ioaddr = NULL; + } + + mutex_destroy(&nvdev->remap_lock); + + vfio_pci_core_close_device(core_vdev); +} + +static int nvgrace_gpu_mmap(struct vfio_device *core_vdev, + struct vm_area_struct *vma) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + struct mem_region *memregion; + unsigned long start_pfn; + u64 req_len, pgoff, end; + unsigned int index; + int ret = 0; + + index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT); + + memregion = nvgrace_gpu_memregion(index, nvdev); + if (!memregion) + return vfio_pci_core_mmap(core_vdev, vma); + + /* + * Request to mmap the BAR. Map to the CPU accessible memory on the + * GPU using the memory information gathered from the system ACPI + * tables. + */ + pgoff = vma->vm_pgoff & + ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1); + + if (check_sub_overflow(vma->vm_end, vma->vm_start, &req_len) || + check_add_overflow(PHYS_PFN(memregion->memphys), pgoff, &start_pfn) || + check_add_overflow(PFN_PHYS(pgoff), req_len, &end)) + return -EOVERFLOW; + + /* + * Check that the mapping request does not go beyond available device + * memory size + */ + if (end > memregion->memlength) + return -EINVAL; + + /* + * The carved out region of the device memory needs the NORMAL_NC + * property. Communicate as such to the hypervisor. + */ + if (index == RESMEM_REGION_INDEX) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + /* + * Perform a PFN map to the memory and back the device BAR by the + * GPU memory. + * + * The available GPU memory size may not be power-of-2 aligned. The + * remainder is only backed by vfio_device_ops read/write handlers. + * + * During device reset, the GPU is safely disconnected to the CPU + * and access to the BAR will be immediately returned preventing + * machine check. + */ + ret = remap_pfn_range(vma, vma->vm_start, start_pfn, + req_len, vma->vm_page_prot); + if (ret) + return ret; + + vma->vm_pgoff = start_pfn; + + return 0; +} + +static long +nvgrace_gpu_ioctl_get_region_info(struct vfio_device *core_vdev, + unsigned long arg) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + unsigned long minsz = offsetofend(struct vfio_region_info, offset); + struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; + struct vfio_region_info_cap_sparse_mmap *sparse; + struct vfio_region_info info; + struct mem_region *memregion; + u32 size; + int ret; + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + /* + * Request to determine the BAR region information. Send the + * GPU memory information. + */ + memregion = nvgrace_gpu_memregion(info.index, nvdev); + if (!memregion) + return vfio_pci_core_ioctl(core_vdev, + VFIO_DEVICE_GET_REGION_INFO, arg); + + size = struct_size(sparse, areas, 1); + + /* + * Setup for sparse mapping for the device memory. Only the + * available device memory on the hardware is shown as a + * mappable region. + */ + sparse = kzalloc(size, GFP_KERNEL); + if (!sparse) + return -ENOMEM; + + sparse->nr_areas = 1; + sparse->areas[0].offset = 0; + sparse->areas[0].size = memregion->memlength; + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; + sparse->header.version = 1; + + ret = vfio_info_add_capability(&caps, &sparse->header, size); + kfree(sparse); + if (ret) + return ret; + + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + /* + * The region memory size may not be power-of-2 aligned. + * Given that the memory as a BAR and may not be + * aligned, roundup to the next power-of-2. + */ + info.size = memregion->bar_size; + info.flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE | + VFIO_REGION_INFO_FLAG_MMAP; + + if (caps.size) { + info.flags |= VFIO_REGION_INFO_FLAG_CAPS; + if (info.argsz < sizeof(info) + caps.size) { + info.argsz = sizeof(info) + caps.size; + info.cap_offset = 0; + } else { + vfio_info_cap_shift(&caps, sizeof(info)); + if (copy_to_user((void __user *)arg + + sizeof(info), caps.buf, + caps.size)) { + kfree(caps.buf); + return -EFAULT; + } + info.cap_offset = sizeof(info); + } + kfree(caps.buf); + } + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; +} + +static long nvgrace_gpu_ioctl(struct vfio_device *core_vdev, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case VFIO_DEVICE_GET_REGION_INFO: + return nvgrace_gpu_ioctl_get_region_info(core_vdev, arg); + case VFIO_DEVICE_IOEVENTFD: + return -ENOTTY; + case VFIO_DEVICE_RESET: + nvgrace_gpu_init_fake_bar_emu_regs(core_vdev); + fallthrough; + default: + return vfio_pci_core_ioctl(core_vdev, cmd, arg); + } +} + +static __le64 +nvgrace_gpu_get_read_value(size_t bar_size, u64 flags, __le64 val64) +{ + u64 tmp_val; + + tmp_val = le64_to_cpu(val64); + tmp_val &= ~(bar_size - 1); + tmp_val |= flags; + + return cpu_to_le64(tmp_val); +} + +/* + * Both the usable (usemem) and the reserved (resmem) device memory region + * are exposed as a 64b fake device BARs in the VM. These fake BARs must + * respond to the accesses on their respective PCI config space offsets. + * + * resmem BAR owns PCI_BASE_ADDRESS_2 & PCI_BASE_ADDRESS_3. + * usemem BAR owns PCI_BASE_ADDRESS_4 & PCI_BASE_ADDRESS_5. + */ +static ssize_t +nvgrace_gpu_read_config_emu(struct vfio_device *core_vdev, + char __user *buf, size_t count, loff_t *ppos) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + u64 pos = *ppos & VFIO_PCI_OFFSET_MASK; + struct mem_region *memregion = NULL; + __le64 val64; + size_t register_offset; + loff_t copy_offset; + size_t copy_count; + int ret; + + ret = vfio_pci_core_read(core_vdev, buf, count, ppos); + if (ret < 0) + return ret; + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_2, + sizeof(val64), + ©_offset, ©_count, + ®ister_offset)) + memregion = nvgrace_gpu_memregion(RESMEM_REGION_INDEX, nvdev); + else if (vfio_pci_core_range_intersect_range(pos, count, + PCI_BASE_ADDRESS_4, + sizeof(val64), + ©_offset, ©_count, + ®ister_offset)) + memregion = nvgrace_gpu_memregion(USEMEM_REGION_INDEX, nvdev); + + if (memregion) { + val64 = nvgrace_gpu_get_read_value(memregion->bar_size, + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, + memregion->bar_val); + if (copy_to_user(buf + copy_offset, + (void *)&val64 + register_offset, copy_count)) { + /* + * The position has been incremented in + * vfio_pci_core_read. Reset the offset back to the + * starting position. + */ + *ppos -= count; + return -EFAULT; + } + } + + return count; +} + +static ssize_t +nvgrace_gpu_write_config_emu(struct vfio_device *core_vdev, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + u64 pos = *ppos & VFIO_PCI_OFFSET_MASK; + struct mem_region *memregion = NULL; + size_t register_offset; + loff_t copy_offset; + size_t copy_count; + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_2, + sizeof(u64), ©_offset, + ©_count, ®ister_offset)) + memregion = nvgrace_gpu_memregion(RESMEM_REGION_INDEX, nvdev); + else if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_4, + sizeof(u64), ©_offset, + ©_count, ®ister_offset)) + memregion = nvgrace_gpu_memregion(USEMEM_REGION_INDEX, nvdev); + + if (memregion) { + if (copy_from_user((void *)&memregion->bar_val + register_offset, + buf + copy_offset, copy_count)) + return -EFAULT; + *ppos += copy_count; + return copy_count; + } + + return vfio_pci_core_write(core_vdev, buf, count, ppos); +} + +/* + * Ad hoc map the device memory in the module kernel VA space. Primarily needed + * as vfio does not require the userspace driver to only perform accesses through + * mmaps of the vfio-pci BAR regions and such accesses should be supported using + * vfio_device_ops read/write implementations. + * + * The usemem region is cacheable memory and hence is memremaped. + * The resmem region is non-cached and is mapped using ioremap_wc (NORMAL_NC). + */ +static int +nvgrace_gpu_map_device_mem(int index, + struct nvgrace_gpu_pci_core_device *nvdev) +{ + struct mem_region *memregion; + int ret = 0; + + memregion = nvgrace_gpu_memregion(index, nvdev); + if (!memregion) + return -EINVAL; + + mutex_lock(&nvdev->remap_lock); + + if (memregion->memaddr) + goto unlock; + + if (index == USEMEM_REGION_INDEX) + memregion->memaddr = memremap(memregion->memphys, + memregion->memlength, + MEMREMAP_WB); + else + memregion->ioaddr = ioremap_wc(memregion->memphys, + memregion->memlength); + + if (!memregion->memaddr) + ret = -ENOMEM; + +unlock: + mutex_unlock(&nvdev->remap_lock); + + return ret; +} + +/* + * Read the data from the device memory (mapped either through ioremap + * or memremap) into the user buffer. + */ +static int +nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev, + char __user *buf, size_t mem_count, loff_t *ppos) +{ + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + u64 offset = *ppos & VFIO_PCI_OFFSET_MASK; + int ret; + + if (!mem_count) + return 0; + + /* + * Handle read on the BAR regions. Map to the target device memory + * physical address and copy to the request read buffer. + */ + ret = nvgrace_gpu_map_device_mem(index, nvdev); + if (ret) + return ret; + + if (index == USEMEM_REGION_INDEX) { + if (copy_to_user(buf, + (u8 *)nvdev->usemem.memaddr + offset, + mem_count)) + ret = -EFAULT; + } else { + /* + * The hardware ensures that the system does not crash when + * the device memory is accessed with the memory enable + * turned off. It synthesizes ~0 on such read. So there is + * no need to check or support the disablement/enablement of + * BAR through PCI_COMMAND config space register. Pass + * test_mem flag as false. + */ + ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, + nvdev->resmem.ioaddr, + buf, offset, mem_count, + 0, 0, false); + } + + return ret; +} + +/* + * Read count bytes from the device memory at an offset. The actual device + * memory size (available) may not be a power-of-2. So the driver fakes + * the size to a power-of-2 (reported) when exposing to a user space driver. + * + * Reads starting beyond the reported size generate -EINVAL; reads extending + * beyond the actual device size is filled with ~0; reads extending beyond + * the reported size are truncated. + */ +static ssize_t +nvgrace_gpu_read_mem(struct nvgrace_gpu_pci_core_device *nvdev, + char __user *buf, size_t count, loff_t *ppos) +{ + u64 offset = *ppos & VFIO_PCI_OFFSET_MASK; + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + struct mem_region *memregion; + size_t mem_count, i; + u8 val = 0xFF; + int ret; + + /* No need to do NULL check as caller does. */ + memregion = nvgrace_gpu_memregion(index, nvdev); + + if (offset >= memregion->bar_size) + return -EINVAL; + + /* Clip short the read request beyond reported BAR size */ + count = min(count, memregion->bar_size - (size_t)offset); + + /* + * Determine how many bytes to be actually read from the device memory. + * Read request beyond the actual device memory size is filled with ~0, + * while those beyond the actual reported size is skipped. + */ + if (offset >= memregion->memlength) + mem_count = 0; + else + mem_count = min(count, memregion->memlength - (size_t)offset); + + ret = nvgrace_gpu_map_and_read(nvdev, buf, mem_count, ppos); + if (ret) + return ret; + + /* + * Only the device memory present on the hardware is mapped, which may + * not be power-of-2 aligned. A read to an offset beyond the device memory + * size is filled with ~0. + */ + for (i = mem_count; i < count; i++) { + ret = put_user(val, (unsigned char __user *)(buf + i)); + if (ret) + return ret; + } + + *ppos += count; + return count; +} + +static ssize_t +nvgrace_gpu_read(struct vfio_device *core_vdev, + char __user *buf, size_t count, loff_t *ppos) +{ + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + + if (nvgrace_gpu_memregion(index, nvdev)) + return nvgrace_gpu_read_mem(nvdev, buf, count, ppos); + + if (index == VFIO_PCI_CONFIG_REGION_INDEX) + return nvgrace_gpu_read_config_emu(core_vdev, buf, count, ppos); + + return vfio_pci_core_read(core_vdev, buf, count, ppos); +} + +/* + * Write the data to the device memory (mapped either through ioremap + * or memremap) from the user buffer. + */ +static int +nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev, + const char __user *buf, size_t mem_count, + loff_t *ppos) +{ + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + int ret; + + if (!mem_count) + return 0; + + ret = nvgrace_gpu_map_device_mem(index, nvdev); + if (ret) + return ret; + + if (index == USEMEM_REGION_INDEX) { + if (copy_from_user((u8 *)nvdev->usemem.memaddr + pos, + buf, mem_count)) + return -EFAULT; + } else { + /* + * The hardware ensures that the system does not crash when + * the device memory is accessed with the memory enable + * turned off. It drops such writes. So there is no need to + * check or support the disablement/enablement of BAR + * through PCI_COMMAND config space register. Pass test_mem + * flag as false. + */ + ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, + nvdev->resmem.ioaddr, + (char __user *)buf, pos, mem_count, + 0, 0, true); + } + + return ret; +} + +/* + * Write count bytes to the device memory at a given offset. The actual device + * memory size (available) may not be a power-of-2. So the driver fakes the + * size to a power-of-2 (reported) when exposing to a user space driver. + * + * Writes extending beyond the reported size are truncated; writes starting + * beyond the reported size generate -EINVAL. + */ +static ssize_t +nvgrace_gpu_write_mem(struct nvgrace_gpu_pci_core_device *nvdev, + size_t count, loff_t *ppos, const char __user *buf) +{ + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + u64 offset = *ppos & VFIO_PCI_OFFSET_MASK; + struct mem_region *memregion; + size_t mem_count; + int ret = 0; + + /* No need to do NULL check as caller does. */ + memregion = nvgrace_gpu_memregion(index, nvdev); + + if (offset >= memregion->bar_size) + return -EINVAL; + + /* Clip short the write request beyond reported BAR size */ + count = min(count, memregion->bar_size - (size_t)offset); + + /* + * Determine how many bytes to be actually written to the device memory. + * Do not write to the offset beyond available size. + */ + if (offset >= memregion->memlength) + goto exitfn; + + /* + * Only the device memory present on the hardware is mapped, which may + * not be power-of-2 aligned. Drop access outside the available device + * memory on the hardware. + */ + mem_count = min(count, memregion->memlength - (size_t)offset); + + ret = nvgrace_gpu_map_and_write(nvdev, buf, mem_count, ppos); + if (ret) + return ret; + +exitfn: + *ppos += count; + return count; +} + +static ssize_t +nvgrace_gpu_write(struct vfio_device *core_vdev, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct nvgrace_gpu_pci_core_device *nvdev = + container_of(core_vdev, struct nvgrace_gpu_pci_core_device, + core_device.vdev); + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + + if (nvgrace_gpu_memregion(index, nvdev)) + return nvgrace_gpu_write_mem(nvdev, count, ppos, buf); + + if (index == VFIO_PCI_CONFIG_REGION_INDEX) + return nvgrace_gpu_write_config_emu(core_vdev, buf, count, ppos); + + return vfio_pci_core_write(core_vdev, buf, count, ppos); +} + +static const struct vfio_device_ops nvgrace_gpu_pci_ops = { + .name = "nvgrace-gpu-vfio-pci", + .init = vfio_pci_core_init_dev, + .release = vfio_pci_core_release_dev, + .open_device = nvgrace_gpu_open_device, + .close_device = nvgrace_gpu_close_device, + .ioctl = nvgrace_gpu_ioctl, + .device_feature = vfio_pci_core_ioctl_feature, + .read = nvgrace_gpu_read, + .write = nvgrace_gpu_write, + .mmap = nvgrace_gpu_mmap, + .request = vfio_pci_core_request, + .match = vfio_pci_core_match, + .bind_iommufd = vfio_iommufd_physical_bind, + .unbind_iommufd = vfio_iommufd_physical_unbind, + .attach_ioas = vfio_iommufd_physical_attach_ioas, + .detach_ioas = vfio_iommufd_physical_detach_ioas, +}; + +static const struct vfio_device_ops nvgrace_gpu_pci_core_ops = { + .name = "nvgrace-gpu-vfio-pci-core", + .init = vfio_pci_core_init_dev, + .release = vfio_pci_core_release_dev, + .open_device = nvgrace_gpu_open_device, + .close_device = vfio_pci_core_close_device, + .ioctl = vfio_pci_core_ioctl, + .device_feature = vfio_pci_core_ioctl_feature, + .read = vfio_pci_core_read, + .write = vfio_pci_core_write, + .mmap = vfio_pci_core_mmap, + .request = vfio_pci_core_request, + .match = vfio_pci_core_match, + .bind_iommufd = vfio_iommufd_physical_bind, + .unbind_iommufd = vfio_iommufd_physical_unbind, + .attach_ioas = vfio_iommufd_physical_attach_ioas, + .detach_ioas = vfio_iommufd_physical_detach_ioas, +}; + +static int +nvgrace_gpu_fetch_memory_property(struct pci_dev *pdev, + u64 *pmemphys, u64 *pmemlength) +{ + int ret; + + /* + * The memory information is present in the system ACPI tables as DSD + * properties nvidia,gpu-mem-base-pa and nvidia,gpu-mem-size. + */ + ret = device_property_read_u64(&pdev->dev, "nvidia,gpu-mem-base-pa", + pmemphys); + if (ret) + return ret; + + if (*pmemphys > type_max(phys_addr_t)) + return -EOVERFLOW; + + ret = device_property_read_u64(&pdev->dev, "nvidia,gpu-mem-size", + pmemlength); + if (ret) + return ret; + + if (*pmemlength > type_max(size_t)) + return -EOVERFLOW; + + /* + * If the C2C link is not up due to an error, the coherent device + * memory size is returned as 0. Fail in such case. + */ + if (*pmemlength == 0) + return -ENOMEM; + + return ret; +} + +static int +nvgrace_gpu_init_nvdev_struct(struct pci_dev *pdev, + struct nvgrace_gpu_pci_core_device *nvdev, + u64 memphys, u64 memlength) +{ + int ret = 0; + + /* + * The VM GPU device driver needs a non-cacheable region to support + * the MIG feature. Since the device memory is mapped as NORMAL cached, + * carve out a region from the end with a different NORMAL_NC + * property (called as reserved memory and represented as resmem). This + * region then is exposed as a 64b BAR (region 2 and 3) to the VM, while + * exposing the rest (termed as usable memory and represented using usemem) + * as cacheable 64b BAR (region 4 and 5). + * + * devmem (memlength) + * |-------------------------------------------------| + * | | + * usemem.memphys resmem.memphys + */ + nvdev->usemem.memphys = memphys; + + /* + * The device memory exposed to the VM is added to the kernel by the + * VM driver module in chunks of memory block size. Only the usable + * memory (usemem) is added to the kernel for usage by the VM + * workloads. Make the usable memory size memblock aligned. + */ + if (check_sub_overflow(memlength, RESMEM_SIZE, + &nvdev->usemem.memlength)) { + ret = -EOVERFLOW; + goto done; + } + + /* + * The USEMEM part of the device memory has to be MEMBLK_SIZE + * aligned. This is a hardwired ABI value between the GPU FW and + * VFIO driver. The VM device driver is also aware of it and make + * use of the value for its calculation to determine USEMEM size. + */ + nvdev->usemem.memlength = round_down(nvdev->usemem.memlength, + MEMBLK_SIZE); + if (nvdev->usemem.memlength == 0) { + ret = -EINVAL; + goto done; + } + + if ((check_add_overflow(nvdev->usemem.memphys, + nvdev->usemem.memlength, + &nvdev->resmem.memphys)) || + (check_sub_overflow(memlength, nvdev->usemem.memlength, + &nvdev->resmem.memlength))) { + ret = -EOVERFLOW; + goto done; + } + + /* + * The memory regions are exposed as BARs. Calculate and save + * the BAR size for them. + */ + nvdev->usemem.bar_size = roundup_pow_of_two(nvdev->usemem.memlength); + nvdev->resmem.bar_size = roundup_pow_of_two(nvdev->resmem.memlength); +done: + return ret; +} + +static int nvgrace_gpu_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + const struct vfio_device_ops *ops = &nvgrace_gpu_pci_core_ops; + struct nvgrace_gpu_pci_core_device *nvdev; + u64 memphys, memlength; + int ret; + + ret = nvgrace_gpu_fetch_memory_property(pdev, &memphys, &memlength); + if (!ret) + ops = &nvgrace_gpu_pci_ops; + + nvdev = vfio_alloc_device(nvgrace_gpu_pci_core_device, core_device.vdev, + &pdev->dev, ops); + if (IS_ERR(nvdev)) + return PTR_ERR(nvdev); + + dev_set_drvdata(&pdev->dev, &nvdev->core_device); + + if (ops == &nvgrace_gpu_pci_ops) { + /* + * Device memory properties are identified in the host ACPI + * table. Set the nvgrace_gpu_pci_core_device structure. + */ + ret = nvgrace_gpu_init_nvdev_struct(pdev, nvdev, + memphys, memlength); + if (ret) + goto out_put_vdev; + } + + ret = vfio_pci_core_register_device(&nvdev->core_device); + if (ret) + goto out_put_vdev; + + return ret; + +out_put_vdev: + vfio_put_device(&nvdev->core_device.vdev); + return ret; +} + +static void nvgrace_gpu_remove(struct pci_dev *pdev) +{ + struct vfio_pci_core_device *core_device = dev_get_drvdata(&pdev->dev); + + vfio_pci_core_unregister_device(core_device); + vfio_put_device(&core_device->vdev); +} + +static const struct pci_device_id nvgrace_gpu_vfio_pci_table[] = { + /* GH200 120GB */ + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2342) }, + /* GH200 480GB */ + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2345) }, + {} +}; + +MODULE_DEVICE_TABLE(pci, nvgrace_gpu_vfio_pci_table); + +static struct pci_driver nvgrace_gpu_vfio_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = nvgrace_gpu_vfio_pci_table, + .probe = nvgrace_gpu_probe, + .remove = nvgrace_gpu_remove, + .err_handler = &vfio_pci_core_err_handlers, + .driver_managed_dma = true, +}; + +module_pci_driver(nvgrace_gpu_vfio_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ankit Agrawal "); +MODULE_AUTHOR("Aniket Agashe "); +MODULE_DESCRIPTION("VFIO NVGRACE GPU PF - User Level driver for NVIDIA devices with CPU coherently accessible device memory"); From 77bbd20f80f4bcd0681c9f5345357b7e9a750f7e Mon Sep 17 00:00:00 2001 From: Dharma Balasubiramani Date: Fri, 2 Feb 2024 05:47:31 +0530 Subject: [PATCH 450/814] dt-bindings: display: convert Atmel's HLCDC to DT schema Convert the existing DT binding to DT schema of the Atmel's HLCDC display controller. Signed-off-by: Dharma Balasubiramani Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240202001733.91455-2-dharma.b@microchip.com Signed-off-by: Rob Herring --- .../atmel/atmel,hlcdc-display-controller.yaml | 63 ++++++++++++++++ .../bindings/display/atmel/hlcdc-dc.txt | 75 ------------------- 2 files changed, 63 insertions(+), 75 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/atmel/atmel,hlcdc-display-controller.yaml delete mode 100644 Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt diff --git a/Documentation/devicetree/bindings/display/atmel/atmel,hlcdc-display-controller.yaml b/Documentation/devicetree/bindings/display/atmel/atmel,hlcdc-display-controller.yaml new file mode 100644 index 000000000000..29ed42485de3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/atmel/atmel,hlcdc-display-controller.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/atmel/atmel,hlcdc-display-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel's High LCD Controller (HLCDC) + +maintainers: + - Nicolas Ferre + - Alexandre Belloni + - Claudiu Beznea + +description: + The LCD Controller (LCDC) consists of logic for transferring LCD image + data from an external display buffer to a TFT LCD panel. The LCDC has one + display input buffer per layer that fetches pixels through the single bus + host interface and a look-up table to allow palletized display + configurations. + +properties: + compatible: + const: atmel,hlcdc-display-controller + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Output endpoint of the controller, connecting the LCD panel signals. + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + maxItems: 1 + + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + description: + Endpoint connecting the LCD panel signals. + + properties: + bus-width: + enum: [ 12, 16, 18, 24 ] + +required: + - '#address-cells' + - '#size-cells' + - compatible + - port@0 + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt deleted file mode 100644 index 923aea25344c..000000000000 --- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt +++ /dev/null @@ -1,75 +0,0 @@ -Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver - -The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device. -See ../../mfd/atmel-hlcdc.txt for more details. - -Required properties: - - compatible: value should be "atmel,hlcdc-display-controller" - - pinctrl-names: the pin control state names. Should contain "default". - - pinctrl-0: should contain the default pinctrl states. - - #address-cells: should be set to 1. - - #size-cells: should be set to 0. - -Required children nodes: - Children nodes are encoding available output ports and their connections - to external devices using the OF graph representation (see ../graph.txt). - At least one port node is required. - -Optional properties in grandchild nodes: - Any endpoint grandchild node may specify a desired video interface - according to ../../media/video-interfaces.txt, specifically - - bus-width: recognized values are <12>, <16>, <18> and <24>, and - override any output mode selection heuristic, forcing "rgb444", - "rgb565", "rgb666" and "rgb888" respectively. - -Example: - - hlcdc: hlcdc@f0030000 { - compatible = "atmel,sama5d3-hlcdc"; - reg = <0xf0030000 0x2000>; - interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; - clock-names = "periph_clk","sys_clk", "slow_clk"; - - hlcdc-display-controller { - compatible = "atmel,hlcdc-display-controller"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - hlcdc_panel_output: endpoint@0 { - reg = <0>; - remote-endpoint = <&panel_input>; - }; - }; - }; - - hlcdc_pwm: hlcdc-pwm { - compatible = "atmel,hlcdc-pwm"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_lcd_pwm>; - #pwm-cells = <3>; - }; - }; - -Example 2: With a video interface override to force rgb565; as above -but with these changes/additions: - - &hlcdc { - hlcdc-display-controller { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>; - - port@0 { - hlcdc_panel_output: endpoint@0 { - bus-width = <16>; - }; - }; - }; - }; From 08a5b9fe771455b94a0642ed4b4f462e1119bd90 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Feb 2024 20:58:29 -0600 Subject: [PATCH 451/814] dt-bindings: vendor-prefixes: Add missing prefixes used in compatibles A new check for vendor-prefixes used in compatibles finds some missing ones. Add the missing ones already in use. This omits some ancient prefixes in powerpc and arm32 as there are a bunch of out of business one-offs that take too much time to track down who they were. Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240216025839.902288-1-robh@kernel.org Signed-off-by: Rob Herring --- .../devicetree/bindings/vendor-prefixes.yaml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 71e37cea8689..b5c8d385ac62 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -230,6 +230,8 @@ patternProperties: description: ByteDance Ltd. "^calamp,.*": description: CalAmp Corp. + "^calao,.*": + description: CALAO Systems SAS "^calaosystems,.*": description: CALAO Systems SAS "^calxeda,.*": @@ -478,6 +480,9 @@ patternProperties: description: EZchip Semiconductor "^facebook,.*": description: Facebook + "^fairchild,.*": + description: Fairchild Semiconductor (deprecated, use 'onnn') + deprecated: true "^fairphone,.*": description: Fairphone B.V. "^faraday,.*": @@ -542,6 +547,8 @@ patternProperties: description: Giantec Semiconductor, Inc. "^giantplus,.*": description: Giantplus Technology Co., Ltd. + "^glinet,.*": + description: GL Intelligence, Inc. "^globalscale,.*": description: Globalscale Technologies, Inc. "^globaltop,.*": @@ -601,6 +608,8 @@ patternProperties: description: Honestar Technologies Co., Ltd. "^honeywell,.*": description: Honeywell + "^hoperf,.*": + description: Shenzhen Hope Microelectronics Co., Ltd. "^hoperun,.*": description: Jiangsu HopeRun Software Co., Ltd. "^hp,.*": @@ -631,12 +640,16 @@ patternProperties: description: Hyundai Technology "^i2se,.*": description: I2SE GmbH + "^IBM,.*": + description: International Business Machines (IBM) "^ibm,.*": description: International Business Machines (IBM) "^icplus,.*": description: IC Plus Corp. "^idt,.*": description: Integrated Device Technologies, Inc. + "^iei,.*": + description: IEI Integration Corp. "^ifi,.*": description: Ingenieurburo Fur Ic-Technologie (I/F/I) "^ilitek,.*": @@ -821,6 +834,8 @@ patternProperties: description: LSI Corp. (LSI Logic) "^lunzn,.*": description: Shenzhen Lunzn Technology Co., Ltd. + "^luxul,.*": + description: Lagrand | AV "^lwn,.*": description: Liebherr-Werk Nenzing GmbH "^lxa,.*": @@ -899,6 +914,9 @@ patternProperties: description: Miniand Tech "^minix,.*": description: MINIX Technology Ltd. + "^mips,.*": + description: MIPS Technology (deprecated, use 'mti' or 'img') + deprecated: true "^miramems,.*": description: MiraMEMS Sensing Technology Co., Ltd. "^mitsubishi,.*": @@ -993,6 +1011,9 @@ patternProperties: description: Novatek "^novtech,.*": description: NovTech, Inc. + "^numonyx,.*": + description: Numonyx (deprecated, use micron) + deprecated: true "^nutsboard,.*": description: NutsBoard "^nuvoton,.*": @@ -1538,8 +1559,12 @@ patternProperties: description: Voipac Technologies s.r.o. "^vot,.*": description: Vision Optical Technology Co., Ltd. + "^vscom,.*": + description: VS Visions Systems GmbH "^vxt,.*": description: VXT Ltd + "^wacom,.*": + description: Wacom "^wanchanglong,.*": description: Wanchanglong Electronics Technology(SHENZHEN)Co.,Ltd. "^wand,.*": From b1a3c366cbc783d6600b357ccfec2f440eed5453 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:23:40 -0800 Subject: [PATCH 452/814] x86/cpu: Add a VMX flag to enumerate 5-level EPT support to userspace Add a VMX flag in /proc/cpuinfo, ept_5level, so that userspace can query whether or not the CPU supports 5-level EPT paging. EPT capabilities are enumerated via MSR, i.e. aren't accessible to userspace without help from the kernel, and knowing whether or not 5-level EPT is supported is useful for debug, triage, testing, etc. For example, when EPT is enabled, bits 51:48 of guest physical addresses are consumed by the CPU if and only if 5-level EPT is enabled. For CPUs with MAXPHYADDR > 48, KVM *can't* map all legal guest memory without 5-level EPT, making 5-level EPT support valuable information for userspace. Reported-by: Yi Lai Cc: Tao Su Cc: Xudong Hao Link: https://lore.kernel.org/r/20240110002340.485595-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/vmxfeatures.h | 1 + arch/x86/kernel/cpu/feat_ctl.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxfeatures.h index c6a7eed03914..266daf5b5b84 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -25,6 +25,7 @@ #define VMX_FEATURE_EPT_EXECUTE_ONLY ( 0*32+ 17) /* "ept_x_only" EPT entries can be execute only */ #define VMX_FEATURE_EPT_AD ( 0*32+ 18) /* EPT Accessed/Dirty bits */ #define VMX_FEATURE_EPT_1GB ( 0*32+ 19) /* 1GB EPT pages */ +#define VMX_FEATURE_EPT_5LEVEL ( 0*32+ 20) /* 5-level EPT paging */ /* Aggregated APIC features 24-27 */ #define VMX_FEATURE_FLEXPRIORITY ( 0*32+ 24) /* TPR shadow + virt APIC */ diff --git a/arch/x86/kernel/cpu/feat_ctl.c b/arch/x86/kernel/cpu/feat_ctl.c index 03851240c3e3..1640ae76548f 100644 --- a/arch/x86/kernel/cpu/feat_ctl.c +++ b/arch/x86/kernel/cpu/feat_ctl.c @@ -72,6 +72,8 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c) c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_AD); if (ept & VMX_EPT_1GB_PAGE_BIT) c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_1GB); + if (ept & VMX_EPT_PAGE_WALK_5_BIT) + c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_5LEVEL); /* Synthetic APIC features that are aggregates of multiple features. */ if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) && From fc5375dd8c062d81001b50008d65ca09e942f924 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 9 Feb 2024 14:07:51 -0800 Subject: [PATCH 453/814] KVM: x86: Make kvm_get_dr() return a value, not use an out parameter Convert kvm_get_dr()'s output parameter to a return value, and clean up most of the mess that was created by forcing callers to provide a pointer. No functional change intended. Acked-by: Mathias Krause Reviewed-by: Mathias Krause Link: https://lore.kernel.org/r/20240209220752.388160-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/emulate.c | 17 ++++------------- arch/x86/kvm/kvm_emulate.h | 2 +- arch/x86/kvm/smm.c | 15 ++++----------- arch/x86/kvm/svm/svm.c | 7 ++----- arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/vmx/vmx.c | 5 +---- arch/x86/kvm/x86.c | 20 +++++++------------- 8 files changed, 21 insertions(+), 49 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b5b2d0fde579..7a59043a6ab0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2045,7 +2045,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); -void kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val); +unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr); unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw); int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index eafb48f0b745..3328c7c7f2f9 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3013,7 +3013,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, ret = em_push(ctxt); } - ops->get_dr(ctxt, 7, &dr7); + dr7 = ops->get_dr(ctxt, 7); ops->set_dr(ctxt, 7, dr7 & ~(DR_LOCAL_ENABLE_MASK | DR_LOCAL_SLOWDOWN)); return ret; @@ -3868,15 +3868,6 @@ static int check_cr_access(struct x86_emulate_ctxt *ctxt) return X86EMUL_CONTINUE; } -static int check_dr7_gd(struct x86_emulate_ctxt *ctxt) -{ - unsigned long dr7; - - ctxt->ops->get_dr(ctxt, 7, &dr7); - - return dr7 & DR7_GD; -} - static int check_dr_read(struct x86_emulate_ctxt *ctxt) { int dr = ctxt->modrm_reg; @@ -3889,10 +3880,10 @@ static int check_dr_read(struct x86_emulate_ctxt *ctxt) if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5)) return emulate_ud(ctxt); - if (check_dr7_gd(ctxt)) { + if (ctxt->ops->get_dr(ctxt, 7) & DR7_GD) { ulong dr6; - ctxt->ops->get_dr(ctxt, 6, &dr6); + dr6 = ctxt->ops->get_dr(ctxt, 6); dr6 &= ~DR_TRAP_BITS; dr6 |= DR6_BD | DR6_ACTIVE_LOW; ctxt->ops->set_dr(ctxt, 6, dr6); @@ -5451,7 +5442,7 @@ twobyte_insn: ctxt->dst.val = ops->get_cr(ctxt, ctxt->modrm_reg); break; case 0x21: /* mov from dr to reg */ - ops->get_dr(ctxt, ctxt->modrm_reg, &ctxt->dst.val); + ctxt->dst.val = ops->get_dr(ctxt, ctxt->modrm_reg); break; case 0x40 ... 0x4f: /* cmov */ if (test_cc(ctxt->b, ctxt->eflags)) diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index e6d149825169..153977c556f4 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -203,7 +203,7 @@ struct x86_emulate_ops { ulong (*get_cr)(struct x86_emulate_ctxt *ctxt, int cr); int (*set_cr)(struct x86_emulate_ctxt *ctxt, int cr, ulong val); int (*cpl)(struct x86_emulate_ctxt *ctxt); - void (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest); + ulong (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr); int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value); int (*set_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data); int (*get_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index dc3d95fdca7d..19a7a0a31953 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -184,7 +184,6 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, struct kvm_smram_state_32 *smram) { struct desc_ptr dt; - unsigned long val; int i; smram->cr0 = kvm_read_cr0(vcpu); @@ -195,10 +194,8 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, for (i = 0; i < 8; i++) smram->gprs[i] = kvm_register_read_raw(vcpu, i); - kvm_get_dr(vcpu, 6, &val); - smram->dr6 = (u32)val; - kvm_get_dr(vcpu, 7, &val); - smram->dr7 = (u32)val; + smram->dr6 = (u32)kvm_get_dr(vcpu, 6); + smram->dr7 = (u32)kvm_get_dr(vcpu, 7); enter_smm_save_seg_32(vcpu, &smram->tr, &smram->tr_sel, VCPU_SREG_TR); enter_smm_save_seg_32(vcpu, &smram->ldtr, &smram->ldtr_sel, VCPU_SREG_LDTR); @@ -231,7 +228,6 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, struct kvm_smram_state_64 *smram) { struct desc_ptr dt; - unsigned long val; int i; for (i = 0; i < 16; i++) @@ -240,11 +236,8 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, smram->rip = kvm_rip_read(vcpu); smram->rflags = kvm_get_rflags(vcpu); - - kvm_get_dr(vcpu, 6, &val); - smram->dr6 = val; - kvm_get_dr(vcpu, 7, &val); - smram->dr7 = val; + smram->dr6 = kvm_get_dr(vcpu, 6); + smram->dr7 = kvm_get_dr(vcpu, 7); smram->cr0 = kvm_read_cr0(vcpu); smram->cr3 = kvm_read_cr3(vcpu); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e90b429c84f1..dda91f7cd71b 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2735,7 +2735,6 @@ static int dr_interception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); int reg, dr; - unsigned long val; int err = 0; /* @@ -2763,11 +2762,9 @@ static int dr_interception(struct kvm_vcpu *vcpu) dr = svm->vmcb->control.exit_code - SVM_EXIT_READ_DR0; if (dr >= 16) { /* mov to DRn */ dr -= 16; - val = kvm_register_read(vcpu, reg); - err = kvm_set_dr(vcpu, dr, val); + err = kvm_set_dr(vcpu, dr, kvm_register_read(vcpu, reg)); } else { - kvm_get_dr(vcpu, dr, &val); - kvm_register_write(vcpu, reg, val); + kvm_register_write(vcpu, reg, kvm_get_dr(vcpu, dr)); } return kvm_complete_insn_gp(vcpu, err); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 6329a306856b..692fd559f086 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4433,7 +4433,7 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) (vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE); if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) - kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7); + vmcs12->guest_dr7 = kvm_get_dr(vcpu, 7); if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER) vmcs12->guest_ia32_efer = vcpu->arch.efer; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e262bc2ba4e5..aa47433d0c9b 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5566,10 +5566,7 @@ static int handle_dr(struct kvm_vcpu *vcpu) reg = DEBUG_REG_ACCESS_REG(exit_qualification); if (exit_qualification & TYPE_MOV_FROM_DR) { - unsigned long val; - - kvm_get_dr(vcpu, dr, &val); - kvm_register_write(vcpu, reg, val); + kvm_register_write(vcpu, reg, kvm_get_dr(vcpu, dr)); err = 0; } else { err = kvm_set_dr(vcpu, dr, kvm_register_read(vcpu, reg)); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7eb7736cfd76..b195eb21639c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1399,22 +1399,19 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) } EXPORT_SYMBOL_GPL(kvm_set_dr); -void kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val) +unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr) { size_t size = ARRAY_SIZE(vcpu->arch.db); switch (dr) { case 0 ... 3: - *val = vcpu->arch.db[array_index_nospec(dr, size)]; - break; + return vcpu->arch.db[array_index_nospec(dr, size)]; case 4: case 6: - *val = vcpu->arch.dr6; - break; + return vcpu->arch.dr6; case 5: default: /* 7 */ - *val = vcpu->arch.dr7; - break; + return vcpu->arch.dr7; } } EXPORT_SYMBOL_GPL(kvm_get_dr); @@ -5509,7 +5506,6 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, struct kvm_debugregs *dbgregs) { - unsigned long val; unsigned int i; memset(dbgregs, 0, sizeof(*dbgregs)); @@ -5518,8 +5514,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++) dbgregs->db[i] = vcpu->arch.db[i]; - kvm_get_dr(vcpu, 6, &val); - dbgregs->dr6 = val; + dbgregs->dr6 = kvm_get_dr(vcpu, 6); dbgregs->dr7 = vcpu->arch.dr7; } @@ -8173,10 +8168,9 @@ static void emulator_wbinvd(struct x86_emulate_ctxt *ctxt) kvm_emulate_wbinvd_noskip(emul_to_vcpu(ctxt)); } -static void emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, - unsigned long *dest) +static unsigned long emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr) { - kvm_get_dr(emul_to_vcpu(ctxt), dr, dest); + return kvm_get_dr(emul_to_vcpu(ctxt), dr); } static int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, From 2a5f091ce1c9222fc9f98374d92db9539e6004ae Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 9 Feb 2024 14:07:52 -0800 Subject: [PATCH 454/814] KVM: x86: Open code all direct reads to guest DR6 and DR7 Bite the bullet, and open code all direct reads of DR6 and DR7. KVM currently has a mix of open coded accesses and calls to kvm_get_dr(), which is confusing and ugly because there's no rhyme or reason as to why any particular chunk of code uses kvm_get_dr(). The obvious alternative is to force all accesses through kvm_get_dr(), but it's not at all clear that doing so would be a net positive, e.g. even if KVM ends up wanting/needing to force all reads through a common helper, e.g. to play caching games, the cost of reverting this change is likely lower than the ongoing cost of maintaining weird, arbitrary code. No functional change intended. Cc: Mathias Krause Reviewed-by: Mathias Krause Link: https://lore.kernel.org/r/20240209220752.388160-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/smm.c | 8 ++++---- arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/x86.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index 19a7a0a31953..d06d43d8d2aa 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -194,8 +194,8 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, for (i = 0; i < 8; i++) smram->gprs[i] = kvm_register_read_raw(vcpu, i); - smram->dr6 = (u32)kvm_get_dr(vcpu, 6); - smram->dr7 = (u32)kvm_get_dr(vcpu, 7); + smram->dr6 = (u32)vcpu->arch.dr6; + smram->dr7 = (u32)vcpu->arch.dr7; enter_smm_save_seg_32(vcpu, &smram->tr, &smram->tr_sel, VCPU_SREG_TR); enter_smm_save_seg_32(vcpu, &smram->ldtr, &smram->ldtr_sel, VCPU_SREG_LDTR); @@ -236,8 +236,8 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, smram->rip = kvm_rip_read(vcpu); smram->rflags = kvm_get_rflags(vcpu); - smram->dr6 = kvm_get_dr(vcpu, 6); - smram->dr7 = kvm_get_dr(vcpu, 7); + smram->dr6 = vcpu->arch.dr6; + smram->dr7 = vcpu->arch.dr7; smram->cr0 = kvm_read_cr0(vcpu); smram->cr3 = kvm_read_cr3(vcpu); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 692fd559f086..0cd977f22c4b 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4433,7 +4433,7 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) (vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE); if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) - vmcs12->guest_dr7 = kvm_get_dr(vcpu, 7); + vmcs12->guest_dr7 = vcpu->arch.dr7; if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER) vmcs12->guest_ia32_efer = vcpu->arch.efer; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b195eb21639c..f97e443ce853 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5514,7 +5514,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++) dbgregs->db[i] = vcpu->arch.db[i]; - dbgregs->dr6 = kvm_get_dr(vcpu, 6); + dbgregs->dr6 = vcpu->arch.dr6; dbgregs->dr7 = vcpu->arch.dr7; } From 474b99ed703b7e4031f3925adacf19e7c8af2075 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Fri, 2 Feb 2024 16:23:40 -0800 Subject: [PATCH 455/814] KVM: x86/mmu: Don't acquire mmu_lock when using indirect_shadow_pages as a heuristic Drop KVM's completely pointless acquisition of mmu_lock when deciding whether or not to unprotect any shadow pages residing at the gfn before resuming the guest to let it retry an instruction that KVM failed to emulated. In this case, indirect_shadow_pages is used as a coarse-grained heuristic to check if there is any chance of there being a relevant shadow page to unprotected. But acquiring mmu_lock largely defeats any benefit to the heuristic, as taking mmu_lock for write is likely far more costly to the VM as a whole than unnecessarily walking mmu_page_hash. Furthermore, the current code is already prone to false negatives and false positives, as it drops mmu_lock before checking the flag and unprotecting shadow pages. And as evidenced by the lack of bug reports, neither false positives nor false negatives are problematic. A false positive simply means that KVM will try to unprotect shadow pages that have already been zapped. And a false negative means that KVM will resume the guest without unprotecting the gfn, i.e. if a shadow page was _just_ created, the vCPU will hit the same page fault and do the whole dance all over again, and detect and unprotect the shadow page the second time around (or not, if something else zaps it first). Reported-by: Jim Mattson Signed-off-by: Mingwei Zhang [sean: drop READ_ONCE() and comment change, rewrite changelog] Link: https://lore.kernel.org/r/20240203002343.383056-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 363b1c080205..7015f8786397 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8789,13 +8789,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, /* The instructions are well-emulated on direct mmu. */ if (vcpu->arch.mmu->root_role.direct) { - unsigned int indirect_shadow_pages; - - write_lock(&vcpu->kvm->mmu_lock); - indirect_shadow_pages = vcpu->kvm->arch.indirect_shadow_pages; - write_unlock(&vcpu->kvm->mmu_lock); - - if (indirect_shadow_pages) + if (vcpu->kvm->arch.indirect_shadow_pages) kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); return true; From 515c18a64e704bc932c5a64e25aaeb712252cf0b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 2 Feb 2024 16:23:41 -0800 Subject: [PATCH 456/814] KVM: x86: Drop dedicated logic for direct MMUs in reexecute_instruction() Now that KVM doesn't pointlessly acquire mmu_lock for direct MMUs, drop the dedicated path entirely and always query indirect_shadow_pages when deciding whether or not to try unprotecting the gfn. For indirect, a.k.a. shadow MMUs, checking indirect_shadow_pages is harmless; unless *every* shadow page was somehow zapped while KVM was attempting to emulate the instruction, indirect_shadow_pages is guaranteed to be non-zero. Well, unless the instruction used a direct hugepage with 2-level paging for its code page, but in that case, there's obviously nothing to unprotect. And in the extremely unlikely case all shadow pages were zapped, there's again obviously nothing to unprotect. Link: https://lore.kernel.org/r/20240203002343.383056-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7015f8786397..ac3ea5829df6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8787,27 +8787,27 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, kvm_release_pfn_clean(pfn); - /* The instructions are well-emulated on direct mmu. */ - if (vcpu->arch.mmu->root_role.direct) { - if (vcpu->kvm->arch.indirect_shadow_pages) - kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); - - return true; - } + /* + * If emulation may have been triggered by a write to a shadowed page + * table, unprotect the gfn (zap any relevant SPTEs) and re-enter the + * guest to let the CPU re-execute the instruction in the hope that the + * CPU can cleanly execute the instruction that KVM failed to emulate. + */ + if (vcpu->kvm->arch.indirect_shadow_pages) + kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); /* - * if emulation was due to access to shadowed page table - * and it failed try to unshadow page and re-enter the - * guest to let CPU execute the instruction. + * If the failed instruction faulted on an access to page tables that + * are used to translate any part of the instruction, KVM can't resolve + * the issue by unprotecting the gfn, as zapping the shadow page will + * result in the instruction taking a !PRESENT page fault and thus put + * the vCPU into an infinite loop of page faults. E.g. KVM will create + * a SPTE and write-protect the gfn to resolve the !PRESENT fault, and + * then zap the SPTE to unprotect the gfn, and then do it all over + * again. Report the error to userspace. */ - kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); - - /* - * If the access faults on its page table, it can not - * be fixed by unprotecting shadow page and it should - * be reported to userspace. - */ - return !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); + return vcpu->arch.mmu->root_role.direct || + !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); } static bool retry_instruction(struct x86_emulate_ctxt *ctxt, From dfeef3d3f310ee464493e848383c4e9fe879089a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 2 Feb 2024 16:23:42 -0800 Subject: [PATCH 457/814] KVM: x86: Drop superfluous check on direct MMU vs. WRITE_PF_TO_SP flag Remove reexecute_instruction()'s final check on the MMU being direct, as EMULTYPE_WRITE_PF_TO_SP is only ever set if the MMU is indirect, i.e. is a shadow MMU. Prior to commit 93c05d3ef252 ("KVM: x86: improve reexecute_instruction"), the flag simply didn't exist (and KVM actually returned "true" unconditionally for both types of MMUs). I.e. the explicit check for a direct MMU is simply leftover artifact from old code. Link: https://lore.kernel.org/r/20240203002343.383056-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ac3ea5829df6..48ec889452e2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8806,8 +8806,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, * then zap the SPTE to unprotect the gfn, and then do it all over * again. Report the error to userspace. */ - return vcpu->arch.mmu->root_role.direct || - !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); + return !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); } static bool retry_instruction(struct x86_emulate_ctxt *ctxt, From 9c9025ea003a03f967affd690f39b4ef3452c0f5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:00 -0800 Subject: [PATCH 458/814] KVM: x86: Plumb "force_immediate_exit" into kvm_entry() tracepoint Annotate the kvm_entry() tracepoint with "immediate exit" when KVM is forcing a VM-Exit immediately after VM-Enter, e.g. when KVM wants to inject an event but needs to first complete some other operation. Knowing that KVM is (or isn't) forcing an exit is useful information when debugging issues related to event injection. Suggested-by: Maxim Levitsky Link: https://lore.kernel.org/r/20240110012705.506918-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/kvm/svm/svm.c | 5 +++-- arch/x86/kvm/trace.h | 9 ++++++--- arch/x86/kvm/vmx/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7a59043a6ab0..bdda3edddec9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1663,7 +1663,8 @@ struct kvm_x86_ops { void (*flush_tlb_guest)(struct kvm_vcpu *vcpu); int (*vcpu_pre_run)(struct kvm_vcpu *vcpu); - enum exit_fastpath_completion (*vcpu_run)(struct kvm_vcpu *vcpu); + enum exit_fastpath_completion (*vcpu_run)(struct kvm_vcpu *vcpu, + bool force_immediate_exit); int (*handle_exit)(struct kvm_vcpu *vcpu, enum exit_fastpath_completion exit_fastpath); int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index dda91f7cd71b..ab8ad8d0e818 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4112,12 +4112,13 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_in guest_state_exit_irqoff(); } -static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) +static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, + bool force_immediate_exit) { struct vcpu_svm *svm = to_svm(vcpu); bool spec_ctrl_intercepted = msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL); - trace_kvm_entry(vcpu); + trace_kvm_entry(vcpu, force_immediate_exit); svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 83843379813e..88659de4d2a7 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -15,20 +15,23 @@ * Tracepoint for guest mode entry. */ TRACE_EVENT(kvm_entry, - TP_PROTO(struct kvm_vcpu *vcpu), - TP_ARGS(vcpu), + TP_PROTO(struct kvm_vcpu *vcpu, bool force_immediate_exit), + TP_ARGS(vcpu, force_immediate_exit), TP_STRUCT__entry( __field( unsigned int, vcpu_id ) __field( unsigned long, rip ) + __field( bool, immediate_exit ) ), TP_fast_assign( __entry->vcpu_id = vcpu->vcpu_id; __entry->rip = kvm_rip_read(vcpu); + __entry->immediate_exit = force_immediate_exit; ), - TP_printk("vcpu %u, rip 0x%lx", __entry->vcpu_id, __entry->rip) + TP_printk("vcpu %u, rip 0x%lx%s", __entry->vcpu_id, __entry->rip, + __entry->immediate_exit ? "[immediate exit]" : "") ); /* diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index aa47433d0c9b..e3653d11f001 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7265,7 +7265,7 @@ out: guest_state_exit_irqoff(); } -static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) +static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit) { struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long cr3, cr4; @@ -7292,7 +7292,7 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_NONE; } - trace_kvm_entry(vcpu); + trace_kvm_entry(vcpu, force_immediate_exit); if (vmx->ple_window_dirty) { vmx->ple_window_dirty = false; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f97e443ce853..e92f14b9d0d6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10956,7 +10956,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) WARN_ON_ONCE((kvm_vcpu_apicv_activated(vcpu) != kvm_vcpu_apicv_active(vcpu)) && (kvm_get_apic_mode(vcpu) != LAPIC_MODE_DISABLED)); - exit_fastpath = static_call(kvm_x86_vcpu_run)(vcpu); + exit_fastpath = static_call(kvm_x86_vcpu_run)(vcpu, req_immediate_exit); if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST)) break; From e6b5d16bbd2d4c8259ad76aa33de80d561aba5f9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:01 -0800 Subject: [PATCH 459/814] KVM: VMX: Re-enter guest in fastpath for "spurious" preemption timer exits Re-enter the guest in the fast path if VMX preeemption timer VM-Exit was "spurious", i.e. if KVM "soft disabled" the timer by writing -1u and by some miracle the timer expired before any other VM-Exit occurred. This is just an intermediate step to cleaning up the preemption timer handling, optimizing these types of spurious VM-Exits is not interesting as they are extremely rare/infrequent. Link: https://lore.kernel.org/r/20240110012705.506918-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e3653d11f001..a44b09e35fd6 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5992,8 +5992,15 @@ static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (!vmx->req_immediate_exit && - !unlikely(vmx->loaded_vmcs->hv_timer_soft_disabled)) { + /* + * In the *extremely* unlikely scenario that this is a spurious VM-Exit + * due to the timer expiring while it was "soft" disabled, just eat the + * exit and re-enter the guest. + */ + if (unlikely(vmx->loaded_vmcs->hv_timer_soft_disabled)) + return EXIT_FASTPATH_REENTER_GUEST; + + if (!vmx->req_immediate_exit) { kvm_lapic_expired_hv_timer(vcpu); return EXIT_FASTPATH_REENTER_GUEST; } From 11776aa0cfa7d007ad1799b1553bdcbd830e5010 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:02 -0800 Subject: [PATCH 460/814] KVM: VMX: Handle forced exit due to preemption timer in fastpath Handle VMX preemption timer VM-Exits due to KVM forcing an exit in the exit fastpath, i.e. avoid calling back into handle_preemption_timer() for the same exit. There is no work to be done for forced exits, as the name suggests the goal is purely to get control back in KVM. In addition to shaving a few cycles, this will allow cleanly separating handle_fastpath_preemption_timer() from handle_preemption_timer(), e.g. it's not immediately obvious why _apparently_ calling handle_fastpath_preemption_timer() twice on a "slow" exit is necessary: the "slow" call is necessary to handle exits from L2, which are excluded from the fastpath by vmx_vcpu_run(). Link: https://lore.kernel.org/r/20240110012705.506918-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index a44b09e35fd6..7bd360b5bfb9 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6000,12 +6000,15 @@ static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) if (unlikely(vmx->loaded_vmcs->hv_timer_soft_disabled)) return EXIT_FASTPATH_REENTER_GUEST; - if (!vmx->req_immediate_exit) { - kvm_lapic_expired_hv_timer(vcpu); - return EXIT_FASTPATH_REENTER_GUEST; - } + /* + * If the timer expired because KVM used it to force an immediate exit, + * then mission accomplished. + */ + if (vmx->req_immediate_exit) + return EXIT_FASTPATH_EXIT_HANDLED; - return EXIT_FASTPATH_NONE; + kvm_lapic_expired_hv_timer(vcpu); + return EXIT_FASTPATH_REENTER_GUEST; } static int handle_preemption_timer(struct kvm_vcpu *vcpu) From bf1a49436ea37b98dd2f37c57608951d0e28eecc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:03 -0800 Subject: [PATCH 461/814] KVM: x86: Move handling of is_guest_mode() into fastpath exit handlers Let the fastpath code decide which exits can/can't be handled in the fastpath when L2 is active, e.g. when KVM generates a VMX preemption timer exit to forcefully regain control, there is no "work" to be done and so such exits can be handled in the fastpath regardless of whether L1 or L2 is active. Moving the is_guest_mode() check into the fastpath code also makes it easier to see that L2 isn't allowed to use the fastpath in most cases, e.g. it's not immediately obvious why handle_fastpath_preemption_timer() is called from the fastpath and the normal path. Link: https://lore.kernel.org/r/20240110012705.506918-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 6 +++--- arch/x86/kvm/vmx/vmx.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ab8ad8d0e818..fe4ac03aaa3a 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4089,6 +4089,9 @@ static int svm_vcpu_pre_run(struct kvm_vcpu *vcpu) static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) { + if (is_guest_mode(vcpu)) + return EXIT_FASTPATH_NONE; + if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR && to_svm(vcpu)->vmcb->control.exit_info_1) return handle_fastpath_set_msr_irqoff(vcpu); @@ -4235,9 +4238,6 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, svm_complete_interrupts(vcpu); - if (is_guest_mode(vcpu)) - return EXIT_FASTPATH_NONE; - return svm_exit_handlers_fastpath(vcpu); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 7bd360b5bfb9..6f21d389bed5 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7214,6 +7214,9 @@ void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu) { + if (is_guest_mode(vcpu)) + return EXIT_FASTPATH_NONE; + switch (to_vmx(vcpu)->exit_reason.basic) { case EXIT_REASON_MSR_WRITE: return handle_fastpath_set_msr_irqoff(vcpu); @@ -7425,9 +7428,6 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit) vmx_recover_nmi_blocking(vmx); vmx_complete_interrupts(vmx); - if (is_guest_mode(vcpu)) - return EXIT_FASTPATH_NONE; - return vmx_exit_handlers_fastpath(vcpu); } From 7b3d1bbf8d68d76fb21210932a5e8ed8ea80dbcc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:04 -0800 Subject: [PATCH 462/814] KVM: VMX: Handle KVM-induced preemption timer exits in fastpath for L2 Eat VMX treemption timer exits in the fastpath regardless of whether L1 or L2 is active. The VM-Exit is 100% KVM-induced, i.e. there is nothing directly related to the exit that KVM needs to do on behalf of the guest, thus there is no reason to wait until the slow path to do nothing. Opportunistically add comments explaining why preemption timer exits for emulating the guest's APIC timer need to go down the slow path. Link: https://lore.kernel.org/r/20240110012705.506918-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6f21d389bed5..1a3a4a92dc60 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6007,13 +6007,26 @@ static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) if (vmx->req_immediate_exit) return EXIT_FASTPATH_EXIT_HANDLED; + /* + * If L2 is active, go down the slow path as emulating the guest timer + * expiration likely requires synthesizing a nested VM-Exit. + */ + if (is_guest_mode(vcpu)) + return EXIT_FASTPATH_NONE; + kvm_lapic_expired_hv_timer(vcpu); return EXIT_FASTPATH_REENTER_GUEST; } static int handle_preemption_timer(struct kvm_vcpu *vcpu) { - handle_fastpath_preemption_timer(vcpu); + /* + * This non-fastpath handler is reached if and only if the preemption + * timer was being used to emulate a guest timer while L2 is active. + * All other scenarios are supposed to be handled in the fastpath. + */ + WARN_ON_ONCE(!is_guest_mode(vcpu)); + kvm_lapic_expired_hv_timer(vcpu); return 1; } @@ -7214,7 +7227,12 @@ void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu)) + /* + * If L2 is active, some VMX preemption timer exits can be handled in + * the fastpath even, all other exits must use the slow path. + */ + if (is_guest_mode(vcpu) && + to_vmx(vcpu)->exit_reason.basic != EXIT_REASON_PREEMPTION_TIMER) return EXIT_FASTPATH_NONE; switch (to_vmx(vcpu)->exit_reason.basic) { From 0ec3d6d1f169baa7fc512ae4b78d17e7c94b7763 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 17:27:05 -0800 Subject: [PATCH 463/814] KVM: x86: Fully defer to vendor code to decide how to force immediate exit Now that vmx->req_immediate_exit is used only in the scope of vmx_vcpu_run(), use force_immediate_exit to detect that KVM should usurp the VMX preemption to force a VM-Exit and let vendor code fully handle forcing a VM-Exit. Opportunsitically drop __kvm_request_immediate_exit() and just have vendor code call smp_send_reschedule() directly. SVM already does this when injecting an event while also trying to single-step an IRET, i.e. it's not exactly secret knowledge that KVM uses a reschedule IPI to force an exit. Link: https://lore.kernel.org/r/20240110012705.506918-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-ops.h | 1 - arch/x86/include/asm/kvm_host.h | 3 --- arch/x86/kvm/svm/svm.c | 7 ++++--- arch/x86/kvm/vmx/vmx.c | 32 +++++++++++++----------------- arch/x86/kvm/vmx/vmx.h | 2 -- arch/x86/kvm/x86.c | 10 +--------- 6 files changed, 19 insertions(+), 36 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 378ed944b849..3942b74c1b75 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -103,7 +103,6 @@ KVM_X86_OP(write_tsc_multiplier) KVM_X86_OP(get_exit_info) KVM_X86_OP(check_intercept) KVM_X86_OP(handle_exit_irqoff) -KVM_X86_OP(request_immediate_exit) KVM_X86_OP(sched_in) KVM_X86_OP_OPTIONAL(update_cpu_dirty_logging) KVM_X86_OP_OPTIONAL(vcpu_blocking) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bdda3edddec9..198d30cceaf2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1732,8 +1732,6 @@ struct kvm_x86_ops { struct x86_exception *exception); void (*handle_exit_irqoff)(struct kvm_vcpu *vcpu); - void (*request_immediate_exit)(struct kvm_vcpu *vcpu); - void (*sched_in)(struct kvm_vcpu *vcpu, int cpu); /* @@ -2239,7 +2237,6 @@ extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn); int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu); int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err); -void __kvm_request_immediate_exit(struct kvm_vcpu *vcpu); void __user *__x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index fe4ac03aaa3a..b9096bb79c00 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4140,9 +4140,12 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, * is enough to force an immediate vmexit. */ disable_nmi_singlestep(svm); - smp_send_reschedule(vcpu->cpu); + force_immediate_exit = true; } + if (force_immediate_exit) + smp_send_reschedule(vcpu->cpu); + pre_svm_run(vcpu); sync_lapic_to_cr8(vcpu); @@ -4995,8 +4998,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .check_intercept = svm_check_intercept, .handle_exit_irqoff = svm_handle_exit_irqoff, - .request_immediate_exit = __kvm_request_immediate_exit, - .sched_in = svm_sched_in, .nested_ops = &svm_nested_ops, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 1a3a4a92dc60..c9e117506d73 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -49,6 +49,8 @@ #include #include +#include + #include "capabilities.h" #include "cpuid.h" #include "hyperv.h" @@ -1281,8 +1283,6 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu) u16 fs_sel, gs_sel; int i; - vmx->req_immediate_exit = false; - /* * Note that guest MSRs to be saved/restored can also be changed * when guest state is loaded. This happens when guest transitions @@ -5988,7 +5988,8 @@ static int handle_pml_full(struct kvm_vcpu *vcpu) return 1; } -static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) +static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu, + bool force_immediate_exit) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -6004,7 +6005,7 @@ static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) * If the timer expired because KVM used it to force an immediate exit, * then mission accomplished. */ - if (vmx->req_immediate_exit) + if (force_immediate_exit) return EXIT_FASTPATH_EXIT_HANDLED; /* @@ -7166,13 +7167,13 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) msrs[i].host, false); } -static void vmx_update_hv_timer(struct kvm_vcpu *vcpu) +static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit) { struct vcpu_vmx *vmx = to_vmx(vcpu); u64 tscl; u32 delta_tsc; - if (vmx->req_immediate_exit) { + if (force_immediate_exit) { vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, 0); vmx->loaded_vmcs->hv_timer_soft_disabled = false; } else if (vmx->hv_deadline_tsc != -1) { @@ -7225,7 +7226,8 @@ void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, barrier_nospec(); } -static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu) +static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu, + bool force_immediate_exit) { /* * If L2 is active, some VMX preemption timer exits can be handled in @@ -7239,7 +7241,7 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu) case EXIT_REASON_MSR_WRITE: return handle_fastpath_set_msr_irqoff(vcpu); case EXIT_REASON_PREEMPTION_TIMER: - return handle_fastpath_preemption_timer(vcpu); + return handle_fastpath_preemption_timer(vcpu, force_immediate_exit); default: return EXIT_FASTPATH_NONE; } @@ -7382,7 +7384,9 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit) vmx_passthrough_lbr_msrs(vcpu); if (enable_preemption_timer) - vmx_update_hv_timer(vcpu); + vmx_update_hv_timer(vcpu, force_immediate_exit); + else if (force_immediate_exit) + smp_send_reschedule(vcpu->cpu); kvm_wait_lapic_expire(vcpu); @@ -7446,7 +7450,7 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit) vmx_recover_nmi_blocking(vmx); vmx_complete_interrupts(vmx); - return vmx_exit_handlers_fastpath(vcpu); + return vmx_exit_handlers_fastpath(vcpu, force_immediate_exit); } static void vmx_vcpu_free(struct kvm_vcpu *vcpu) @@ -7926,11 +7930,6 @@ static __init void vmx_set_cpu_caps(void) kvm_cpu_cap_check_and_set(X86_FEATURE_WAITPKG); } -static void vmx_request_immediate_exit(struct kvm_vcpu *vcpu) -{ - to_vmx(vcpu)->req_immediate_exit = true; -} - static int vmx_check_intercept_io(struct kvm_vcpu *vcpu, struct x86_instruction_info *info) { @@ -8383,8 +8382,6 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { .check_intercept = vmx_check_intercept, .handle_exit_irqoff = vmx_handle_exit_irqoff, - .request_immediate_exit = vmx_request_immediate_exit, - .sched_in = vmx_sched_in, .cpu_dirty_log_size = PML_ENTITY_NUM, @@ -8644,7 +8641,6 @@ static __init int hardware_setup(void) if (!enable_preemption_timer) { vmx_x86_ops.set_hv_timer = NULL; vmx_x86_ops.cancel_hv_timer = NULL; - vmx_x86_ops.request_immediate_exit = __kvm_request_immediate_exit; } kvm_caps.supported_mce_cap |= MCG_LMCE_P; diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index e3b0985bb74a..65786dbe7d60 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -332,8 +332,6 @@ struct vcpu_vmx { unsigned int ple_window; bool ple_window_dirty; - bool req_immediate_exit; - /* Support for PML */ #define PML_ENTITY_NUM 512 struct page *pml_pg; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e92f14b9d0d6..d9724a35d8f3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10667,12 +10667,6 @@ static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu) static_call_cond(kvm_x86_set_apic_access_page_addr)(vcpu); } -void __kvm_request_immediate_exit(struct kvm_vcpu *vcpu) -{ - smp_send_reschedule(vcpu->cpu); -} -EXPORT_SYMBOL_GPL(__kvm_request_immediate_exit); - /* * Called within kvm->srcu read side. * Returns 1 to let vcpu_run() continue the guest execution loop without @@ -10922,10 +10916,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto cancel_injection; } - if (req_immediate_exit) { + if (req_immediate_exit) kvm_make_request(KVM_REQ_EVENT, vcpu); - static_call(kvm_x86_request_immediate_exit)(vcpu); - } fpregs_assert_state_consistent(); if (test_thread_flag(TIF_NEED_FPU_LOAD)) From a78d9046696b88079a5696bccec4e4e439a3f2a2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 9 Feb 2024 14:20:46 -0800 Subject: [PATCH 464/814] KVM: x86: Move "KVM no-APIC vCPU" key management into local APIC code Move incrementing and decrementing of kvm_has_noapic_vcpu into kvm_create_lapic() and kvm_free_lapic() respectively to fix a benign bug where KVM fails to decrement the count if vCPU creation ultimately fails, e.g. due to a memory allocation failing. Note, the bug is benign as kvm_has_noapic_vcpu is used purely to optimize lapic_in_kernel() checks, and that optimization is quite dubious. That, and practically speaking no setup that cares at all about performance runs with a userspace local APIC. Reported-by: Li RongQing Cc: Maxim Levitsky Reviewed-by: Xu Yilun Link: https://lore.kernel.org/r/20240209222047.394389-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 27 ++++++++++++++++++++++++++- arch/x86/kvm/x86.c | 29 +++-------------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 3242f3da2457..681f6d82d015 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -124,6 +124,9 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap) return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); } +__read_mostly DEFINE_STATIC_KEY_FALSE(kvm_has_noapic_vcpu); +EXPORT_SYMBOL_GPL(kvm_has_noapic_vcpu); + __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(apic_hw_disabled, HZ); __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(apic_sw_disabled, HZ); @@ -2466,8 +2469,10 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu->arch.apic) + if (!vcpu->arch.apic) { + static_branch_dec(&kvm_has_noapic_vcpu); return; + } hrtimer_cancel(&apic->lapic_timer.timer); @@ -2809,6 +2814,11 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns) ASSERT(vcpu != NULL); + if (!irqchip_in_kernel(vcpu->kvm)) { + static_branch_inc(&kvm_has_noapic_vcpu); + return 0; + } + apic = kzalloc(sizeof(*apic), GFP_KERNEL_ACCOUNT); if (!apic) goto nomem; @@ -2844,6 +2854,21 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns) static_branch_inc(&apic_sw_disabled.key); /* sw disabled at reset */ kvm_iodevice_init(&apic->dev, &apic_mmio_ops); + /* + * Defer evaluating inhibits until the vCPU is first run, as this vCPU + * will not get notified of any changes until this vCPU is visible to + * other vCPUs (marked online and added to the set of vCPUs). + * + * Opportunistically mark APICv active as VMX in particularly is highly + * unlikely to have inhibits. Ignore the current per-VM APICv state so + * that vCPU creation is guaranteed to run with a deterministic value, + * the request will ensure the vCPU gets the correct state before VM-Entry. + */ + if (enable_apicv) { + apic->apicv_active = true; + kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); + } + return 0; nomem_free_apic: kfree(apic); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d9724a35d8f3..19b18679779c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12046,27 +12046,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (r < 0) return r; - if (irqchip_in_kernel(vcpu->kvm)) { - r = kvm_create_lapic(vcpu, lapic_timer_advance_ns); - if (r < 0) - goto fail_mmu_destroy; - - /* - * Defer evaluating inhibits until the vCPU is first run, as - * this vCPU will not get notified of any changes until this - * vCPU is visible to other vCPUs (marked online and added to - * the set of vCPUs). Opportunistically mark APICv active as - * VMX in particularly is highly unlikely to have inhibits. - * Ignore the current per-VM APICv state so that vCPU creation - * is guaranteed to run with a deterministic value, the request - * will ensure the vCPU gets the correct state before VM-Entry. - */ - if (enable_apicv) { - vcpu->arch.apic->apicv_active = true; - kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); - } - } else - static_branch_inc(&kvm_has_noapic_vcpu); + r = kvm_create_lapic(vcpu, lapic_timer_advance_ns); + if (r < 0) + goto fail_mmu_destroy; r = -ENOMEM; @@ -12187,8 +12169,6 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) srcu_read_unlock(&vcpu->kvm->srcu, idx); free_page((unsigned long)vcpu->arch.pio_data); kvfree(vcpu->arch.cpuid_entries); - if (!lapic_in_kernel(vcpu)) - static_branch_dec(&kvm_has_noapic_vcpu); } void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) @@ -12465,9 +12445,6 @@ bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) return (vcpu->arch.apic_base & MSR_IA32_APICBASE_BSP) != 0; } -__read_mostly DEFINE_STATIC_KEY_FALSE(kvm_has_noapic_vcpu); -EXPORT_SYMBOL_GPL(kvm_has_noapic_vcpu); - void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); From fc3c94142b3a4391cab94adde56fcfbea25723e5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 9 Feb 2024 14:20:47 -0800 Subject: [PATCH 465/814] KVM: x86: Sanity check that kvm_has_noapic_vcpu is zero at module_exit() WARN if kvm.ko is unloaded with an elevated kvm_has_noapic_vcpu to guard against incorrect management of the key, e.g. to detect if KVM fails to decrement the key in error paths. Because kvm_has_noapic_vcpu is purely an optimization, in all likelihood KVM could completely botch handling of kvm_has_noapic_vcpu and no one would notice (which is a good argument for deleting the key entirely, but that's a problem for another day). Note, ideally the sanity check would be performance when kvm_usage_count goes to zero, but adding an arch callback just for this sanity check isn't at all worth doing. Link: https://lore.kernel.org/r/20240209222047.394389-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 19b18679779c..019320580a84 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13871,9 +13871,6 @@ module_init(kvm_x86_init); static void __exit kvm_x86_exit(void) { - /* - * If module_init() is implemented, module_exit() must also be - * implemented to allow module unload. - */ + WARN_ON_ONCE(static_branch_unlikely(&kvm_has_noapic_vcpu)); } module_exit(kvm_x86_exit); From 77bcd9e6231a5297ef417a7d7f734d61c2bcceb6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:39:35 -0800 Subject: [PATCH 466/814] KVM: Add dedicated arch hook for querying if vCPU was preempted in-kernel Plumb in a dedicated hook for querying whether or not a vCPU was preempted in-kernel. Unlike literally every other architecture, x86's VMX can check if a vCPU is in kernel context if and only if the vCPU is loaded on the current pCPU. x86's kvm_arch_vcpu_in_kernel() works around the limitation by querying kvm_get_running_vcpu() and redirecting to vcpu->arch.preempted_in_kernel as needed. But that's unnecessary, confusing, and fragile, e.g. x86 has had at least one bug where KVM incorrectly used a stale preempted_in_kernel. No functional change intended. Reviewed-by: Yuan Yao Link: https://lore.kernel.org/r/20240110003938.490206-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 5 +++++ include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 14 +++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 019320580a84..94346490f407 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13054,6 +13054,11 @@ bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) return false; } +bool kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu) +{ + return kvm_arch_vcpu_in_kernel(vcpu); +} + bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu) { if (READ_ONCE(vcpu->arch.pv.pv_unhalted)) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7e7fd25b09b3..28b020404a41 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1505,6 +1505,7 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu); int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu); bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu); bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu); +bool kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu); int kvm_arch_post_init_vm(struct kvm *kvm); void kvm_arch_pre_destroy_vm(struct kvm *kvm); int kvm_arch_create_vm_debugfs(struct kvm *kvm); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 10bfc88a69f7..9b92858c8b72 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4042,6 +4042,18 @@ static bool vcpu_dy_runnable(struct kvm_vcpu *vcpu) return false; } +/* + * By default, simply query the target vCPU's current mode when checking if a + * vCPU was preempted in kernel mode. All architectures except x86 (or more + * specifical, except VMX) allow querying whether or not a vCPU is in kernel + * mode even if the vCPU is NOT loaded, i.e. using kvm_arch_vcpu_in_kernel() + * directly for cross-vCPU checks is functionally correct and accurate. + */ +bool __weak kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu) +{ + return kvm_arch_vcpu_in_kernel(vcpu); +} + bool __weak kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) { return false; @@ -4080,7 +4092,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode) continue; if (READ_ONCE(vcpu->preempted) && yield_to_kernel_mode && !kvm_arch_dy_has_pending_interrupt(vcpu) && - !kvm_arch_vcpu_in_kernel(vcpu)) + !kvm_arch_vcpu_preempted_in_kernel(vcpu)) continue; if (!kvm_vcpu_eligible_for_directed_yield(vcpu)) continue; From 9b8615c5d37fca15b330882bafceaf24f2398352 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:39:36 -0800 Subject: [PATCH 467/814] KVM: x86: Rely solely on preempted_in_kernel flag for directed yield Snapshot preempted_in_kernel using kvm_arch_vcpu_in_kernel() so that the flag is "accurate" (or rather, consistent and deterministic within KVM) for guests with protected state, and explicitly use preempted_in_kernel when checking if a vCPU was preempted in kernel mode instead of bouncing through kvm_arch_vcpu_in_kernel(). Drop the gnarly logic in kvm_arch_vcpu_in_kernel() that redirects to preempted_in_kernel if the target vCPU is not the "running", i.e. loaded, vCPU, as the only reason that code existed was for the directed yield case where KVM wants to check the CPL of a vCPU that may or may not be loaded on the current pCPU. Cc: Like Xu Reviewed-by: Yuan Yao Link: https://lore.kernel.org/r/20240110003938.490206-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 94346490f407..ab7d2baaae7a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5059,8 +5059,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) int idx; if (vcpu->preempted) { - if (!vcpu->arch.guest_state_protected) - vcpu->arch.preempted_in_kernel = !static_call(kvm_x86_get_cpl)(vcpu); + vcpu->arch.preempted_in_kernel = kvm_arch_vcpu_in_kernel(vcpu); /* * Take the srcu lock as memslots will be accessed to check the gfn @@ -13056,7 +13055,7 @@ bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) bool kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu) { - return kvm_arch_vcpu_in_kernel(vcpu); + return vcpu->arch.preempted_in_kernel; } bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu) @@ -13079,9 +13078,6 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) if (vcpu->arch.guest_state_protected) return true; - if (vcpu != kvm_get_running_vcpu()) - return vcpu->arch.preempted_in_kernel; - return static_call(kvm_x86_get_cpl)(vcpu) == 0; } From 322d79f1db4b033844dcb2de43abd570abbd04b4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:39:37 -0800 Subject: [PATCH 468/814] KVM: x86: Clean up directed yield API for "has pending interrupt" Directly return the boolean result of whether or not a vCPU has a pending interrupt instead of effectively doing: if (true) return true; return false; Reviewed-by: Yuan Yao Link: https://lore.kernel.org/r/20240110003938.490206-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ab7d2baaae7a..e6283628fd53 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13046,11 +13046,8 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) { - if (kvm_vcpu_apicv_active(vcpu) && - static_call(kvm_x86_dy_apicv_has_pending_interrupt)(vcpu)) - return true; - - return false; + return kvm_vcpu_apicv_active(vcpu) && + static_call(kvm_x86_dy_apicv_has_pending_interrupt)(vcpu); } bool kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu) From dafc17dd529a6194e199b837916062090562ff80 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 9 Jan 2024 16:39:38 -0800 Subject: [PATCH 469/814] KVM: Add a comment explaining the directed yield pending interrupt logic Add a comment to explain why KVM treats vCPUs with pending interrupts as in-kernel when a vCPU wants to yield to a vCPU that was preempted while running in kernel mode. Link: https://lore.kernel.org/r/20240110003938.490206-5-seanjc@google.com Signed-off-by: Sean Christopherson --- virt/kvm/kvm_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9b92858c8b72..c0c2fcdabe1b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4090,6 +4090,13 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode) continue; if (kvm_vcpu_is_blocking(vcpu) && !vcpu_dy_runnable(vcpu)) continue; + + /* + * Treat the target vCPU as being in-kernel if it has a + * pending interrupt, as the vCPU trying to yield may + * be spinning waiting on IPI delivery, i.e. the target + * vCPU is in-kernel for the purposes of directed yield. + */ if (READ_ONCE(vcpu->preempted) && yield_to_kernel_mode && !kvm_arch_dy_has_pending_interrupt(vcpu) && !kvm_arch_vcpu_preempted_in_kernel(vcpu)) From 8ca983631f3c4ba16ac70d3310a31316e06f9e36 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:41 -0800 Subject: [PATCH 470/814] KVM: x86/mmu: Zap invalidated TDP MMU roots at 4KiB granularity Zap invalidated TDP MMU roots at maximum granularity, i.e. with more frequent conditional resched checkpoints, in order to avoid running for an extended duration (milliseconds, or worse) without honoring a reschedule request. And for kernels running with full or real-time preempt models, zapping at 4KiB granularity also provides significantly reduced latency for other tasks that are contending for mmu_lock (which isn't necessarily an overall win for KVM, but KVM should do its best to honor the kernel's preemption model). To keep KVM's assertion that zapping at 1GiB granularity is functionally ok, which is the main reason 1GiB was selected in the past, skip straight to zapping at 1GiB if KVM is configured to prove the MMU. Zapping roots is far more common than a vCPU replacing a 1GiB page table with a hugepage, e.g. generally happens multiple times during boot, and so keeping the test coverage provided by root zaps is desirable, just not for production. Cc: David Matlack Cc: Pattara Teerapong Link: https://lore.kernel.org/r/20240111020048.844847-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 6ae19b4ee5b1..372da098d3ce 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -734,15 +734,26 @@ static void tdp_mmu_zap_root(struct kvm *kvm, struct kvm_mmu_page *root, rcu_read_lock(); /* - * To avoid RCU stalls due to recursively removing huge swaths of SPs, - * split the zap into two passes. On the first pass, zap at the 1gb - * level, and then zap top-level SPs on the second pass. "1gb" is not - * arbitrary, as KVM must be able to zap a 1gb shadow page without - * inducing a stall to allow in-place replacement with a 1gb hugepage. + * Zap roots in multiple passes of decreasing granularity, i.e. zap at + * 4KiB=>2MiB=>1GiB=>root, in order to better honor need_resched() (all + * preempt models) or mmu_lock contention (full or real-time models). + * Zapping at finer granularity marginally increases the total time of + * the zap, but in most cases the zap itself isn't latency sensitive. * - * Because zapping a SP recurses on its children, stepping down to - * PG_LEVEL_4K in the iterator itself is unnecessary. + * If KVM is configured to prove the MMU, skip the 4KiB and 2MiB zaps + * in order to mimic the page fault path, which can replace a 1GiB page + * table with an equivalent 1GiB hugepage, i.e. can get saddled with + * zapping a 1GiB region that's fully populated with 4KiB SPTEs. This + * allows verifying that KVM can safely zap 1GiB regions, e.g. without + * inducing RCU stalls, without relying on a relatively rare event + * (zapping roots is orders of magnitude more common). Note, because + * zapping a SP recurses on its children, stepping down to PG_LEVEL_4K + * in the iterator itself is unnecessary. */ + if (!IS_ENABLED(CONFIG_KVM_PROVE_MMU)) { + __tdp_mmu_zap_root(kvm, root, shared, PG_LEVEL_4K); + __tdp_mmu_zap_root(kvm, root, shared, PG_LEVEL_2M); + } __tdp_mmu_zap_root(kvm, root, shared, PG_LEVEL_1G); __tdp_mmu_zap_root(kvm, root, shared, root->role.level); From fcdffe97f80e6fb488f6b5c6bd38f6cd899944ab Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:42 -0800 Subject: [PATCH 471/814] KVM: x86/mmu: Don't do TLB flush when zappings SPTEs in invalid roots Don't force a TLB flush when zapping SPTEs in invalid roots as vCPUs can't be actively using invalid roots (zapping SPTEs in invalid roots is necessary only to ensure KVM doesn't mark a page accessed/dirty after it is freed by the primary MMU). Link: https://lore.kernel.org/r/20240111020048.844847-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 372da098d3ce..68920877370b 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -811,7 +811,13 @@ static bool tdp_mmu_zap_leafs(struct kvm *kvm, struct kvm_mmu_page *root, continue; tdp_mmu_iter_set_spte(kvm, &iter, 0); - flush = true; + + /* + * Zappings SPTEs in invalid roots doesn't require a TLB flush, + * see kvm_tdp_mmu_zap_invalidated_roots() for details. + */ + if (!root->role.invalid) + flush = true; } rcu_read_unlock(); From 6577f1efdff443277b19c0fbe4b933404e7c84e6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:43 -0800 Subject: [PATCH 472/814] KVM: x86/mmu: Allow passing '-1' for "all" as_id for TDP MMU iterators Modify for_each_tdp_mmu_root() and __for_each_tdp_mmu_root_yield_safe() to accept -1 for _as_id to mean "process all memslot address spaces". That way code that wants to process both SMM and !SMM doesn't need to iterate over roots twice (and likely copy+paste code in the process). Deliberately don't cast _as_id to an "int", just in case not casting helps the compiler elide the "_as_id >=0" check when being passed an unsigned value, e.g. from a memslot. No functional change intended. Link: https://lore.kernel.org/r/20240111020048.844847-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 68920877370b..60fff2aad59e 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -149,11 +149,11 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, * If shared is set, this function is operating under the MMU lock in read * mode. */ -#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _only_valid)\ - for (_root = tdp_mmu_next_root(_kvm, NULL, _only_valid); \ - ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \ - _root = tdp_mmu_next_root(_kvm, _root, _only_valid)) \ - if (kvm_mmu_page_as_id(_root) != _as_id) { \ +#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _only_valid) \ + for (_root = tdp_mmu_next_root(_kvm, NULL, _only_valid); \ + ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \ + _root = tdp_mmu_next_root(_kvm, _root, _only_valid)) \ + if (_as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) { \ } else #define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id) \ @@ -171,10 +171,10 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, * Holding mmu_lock for write obviates the need for RCU protection as the list * is guaranteed to be stable. */ -#define for_each_tdp_mmu_root(_kvm, _root, _as_id) \ - list_for_each_entry(_root, &_kvm->arch.tdp_mmu_roots, link) \ - if (kvm_lockdep_assert_mmu_lock_held(_kvm, false) && \ - kvm_mmu_page_as_id(_root) != _as_id) { \ +#define for_each_tdp_mmu_root(_kvm, _root, _as_id) \ + list_for_each_entry(_root, &_kvm->arch.tdp_mmu_roots, link) \ + if (kvm_lockdep_assert_mmu_lock_held(_kvm, false) && \ + _as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) { \ } else static struct kvm_mmu_page *tdp_mmu_alloc_sp(struct kvm_vcpu *vcpu) From 99b85fda91b164b91a0d4e0aae376f32dc38d59c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:44 -0800 Subject: [PATCH 473/814] KVM: x86/mmu: Skip invalid roots when zapping leaf SPTEs for GFN range When zapping a GFN in response to an APICv or MTRR change, don't zap SPTEs for invalid roots as KVM only needs to ensure the guest can't use stale mappings for the GFN. Unlike kvm_tdp_mmu_unmap_gfn_range(), which must zap "unreachable" SPTEs to ensure KVM doesn't mark a page accessed/dirty, kvm_tdp_mmu_zap_leafs() isn't used (and isn't intended to be used) to handle freeing of host memory. Link: https://lore.kernel.org/r/20240111020048.844847-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 60fff2aad59e..1a9c16e5c287 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -830,16 +830,16 @@ static bool tdp_mmu_zap_leafs(struct kvm *kvm, struct kvm_mmu_page *root, } /* - * Zap leaf SPTEs for the range of gfns, [start, end), for all roots. Returns - * true if a TLB flush is needed before releasing the MMU lock, i.e. if one or - * more SPTEs were zapped since the MMU lock was last acquired. + * Zap leaf SPTEs for the range of gfns, [start, end), for all *VALID** roots. + * Returns true if a TLB flush is needed before releasing the MMU lock, i.e. if + * one or more SPTEs were zapped since the MMU lock was last acquired. */ bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush) { struct kvm_mmu_page *root; lockdep_assert_held_write(&kvm->mmu_lock); - for_each_tdp_mmu_root_yield_safe(kvm, root) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, -1) flush = tdp_mmu_zap_leafs(kvm, root, start, end, true, flush); return flush; From d746182337c205660fd4d8eaa5fdc4f4e8320b9a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:45 -0800 Subject: [PATCH 474/814] KVM: x86/mmu: Skip invalid TDP MMU roots when write-protecting SPTEs When write-protecting SPTEs, don't process invalid roots as invalid roots are unreachable, i.e. can't be used to access guest memory and thus don't need to be write-protected. Note, this is *almost* a nop for kvm_tdp_mmu_clear_dirty_pt_masked(), which is called under slots_lock, i.e. is mutually exclusive with kvm_mmu_zap_all_fast(). But it's possible for something other than the "fast zap" thread to grab a reference to an invalid root and thus keep a root alive (but completely empty) after kvm_mmu_zap_all_fast() completes. The kvm_tdp_mmu_write_protect_gfn() case is more interesting as KVM write- protects SPTEs for reasons other than dirty logging, e.g. if a KVM creates a SPTE for a nested VM while a fast zap is in-progress. Add another TDP MMU iterator to visit only valid roots, and opportunistically convert kvm_tdp_mmu_get_vcpu_root_hpa() to said iterator. Link: https://lore.kernel.org/r/20240111020048.844847-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 1a9c16e5c287..e0a8343f66dc 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -171,12 +171,19 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, * Holding mmu_lock for write obviates the need for RCU protection as the list * is guaranteed to be stable. */ -#define for_each_tdp_mmu_root(_kvm, _root, _as_id) \ +#define __for_each_tdp_mmu_root(_kvm, _root, _as_id, _only_valid) \ list_for_each_entry(_root, &_kvm->arch.tdp_mmu_roots, link) \ if (kvm_lockdep_assert_mmu_lock_held(_kvm, false) && \ - _as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) { \ + ((_as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) || \ + ((_only_valid) && (_root)->role.invalid))) { \ } else +#define for_each_tdp_mmu_root(_kvm, _root, _as_id) \ + __for_each_tdp_mmu_root(_kvm, _root, _as_id, false) + +#define for_each_valid_tdp_mmu_root(_kvm, _root, _as_id) \ + __for_each_tdp_mmu_root(_kvm, _root, _as_id, true) + static struct kvm_mmu_page *tdp_mmu_alloc_sp(struct kvm_vcpu *vcpu) { struct kvm_mmu_page *sp; @@ -224,11 +231,8 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu) lockdep_assert_held_write(&kvm->mmu_lock); - /* - * Check for an existing root before allocating a new one. Note, the - * role check prevents consuming an invalid root. - */ - for_each_tdp_mmu_root(kvm, root, kvm_mmu_role_as_id(role)) { + /* Check for an existing root before allocating a new one. */ + for_each_valid_tdp_mmu_root(kvm, root, kvm_mmu_role_as_id(role)) { if (root->role.word == role.word && kvm_tdp_mmu_get_root(root)) goto out; @@ -1639,7 +1643,7 @@ void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm, { struct kvm_mmu_page *root; - for_each_tdp_mmu_root(kvm, root, slot->as_id) + for_each_valid_tdp_mmu_root(kvm, root, slot->as_id) clear_dirty_pt_masked(kvm, root, gfn, mask, wrprot); } @@ -1757,7 +1761,7 @@ bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm, bool spte_set = false; lockdep_assert_held_write(&kvm->mmu_lock); - for_each_tdp_mmu_root(kvm, root, slot->as_id) + for_each_valid_tdp_mmu_root(kvm, root, slot->as_id) spte_set |= write_protect_gfn(kvm, root, gfn, min_level); return spte_set; From f5238c2a60f1e0eb48ce21037bce6f4781afa37f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:46 -0800 Subject: [PATCH 475/814] KVM: x86/mmu: Check for usable TDP MMU root while holding mmu_lock for read When allocating a new TDP MMU root, check for a usable root while holding mmu_lock for read and only acquire mmu_lock for write if a new root needs to be created. There is no need to serialize other MMU operations if a vCPU is simply grabbing a reference to an existing root, holding mmu_lock for write is "necessary" (spoiler alert, it's not strictly necessary) only to ensure KVM doesn't end up with duplicate roots. Allowing vCPUs to get "new" roots in parallel is beneficial to VM boot and to setups that frequently delete memslots, i.e. which force all vCPUs to reload all roots. Link: https://lore.kernel.org/r/20240111020048.844847-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 8 ++--- arch/x86/kvm/mmu/tdp_mmu.c | 60 +++++++++++++++++++++++++++++++------- arch/x86/kvm/mmu/tdp_mmu.h | 2 +- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 3c193b096b45..c9150080fbd2 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3693,15 +3693,15 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) unsigned i; int r; + if (tdp_mmu_enabled) + return kvm_tdp_mmu_alloc_root(vcpu); + write_lock(&vcpu->kvm->mmu_lock); r = make_mmu_pages_available(vcpu); if (r < 0) goto out_unlock; - if (tdp_mmu_enabled) { - root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu); - mmu->root.hpa = root; - } else if (shadow_root_level >= PT64_ROOT_4LEVEL) { + if (shadow_root_level >= PT64_ROOT_4LEVEL) { root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level); mmu->root.hpa = root; } else if (shadow_root_level == PT32E_ROOT_LEVEL) { diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index e0a8343f66dc..9a8250a14fc1 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -223,21 +223,52 @@ static void tdp_mmu_init_child_sp(struct kvm_mmu_page *child_sp, tdp_mmu_init_sp(child_sp, iter->sptep, iter->gfn, role); } -hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu) +static struct kvm_mmu_page *kvm_tdp_mmu_try_get_root(struct kvm_vcpu *vcpu) { union kvm_mmu_page_role role = vcpu->arch.mmu->root_role; + int as_id = kvm_mmu_role_as_id(role); struct kvm *kvm = vcpu->kvm; struct kvm_mmu_page *root; - lockdep_assert_held_write(&kvm->mmu_lock); - - /* Check for an existing root before allocating a new one. */ - for_each_valid_tdp_mmu_root(kvm, root, kvm_mmu_role_as_id(role)) { - if (root->role.word == role.word && - kvm_tdp_mmu_get_root(root)) - goto out; + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, as_id) { + if (root->role.word == role.word) + return root; } + return NULL; +} + +int kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *mmu = vcpu->arch.mmu; + union kvm_mmu_page_role role = mmu->root_role; + struct kvm *kvm = vcpu->kvm; + struct kvm_mmu_page *root; + + /* + * Check for an existing root while holding mmu_lock for read to avoid + * unnecessary serialization if multiple vCPUs are loading a new root. + * E.g. when bringing up secondary vCPUs, KVM will already have created + * a valid root on behalf of the primary vCPU. + */ + read_lock(&kvm->mmu_lock); + root = kvm_tdp_mmu_try_get_root(vcpu); + read_unlock(&kvm->mmu_lock); + + if (root) + goto out; + + write_lock(&kvm->mmu_lock); + + /* + * Recheck for an existing root after acquiring mmu_lock for write. It + * is possible a new usable root was created between dropping mmu_lock + * (for read) and acquiring it for write. + */ + root = kvm_tdp_mmu_try_get_root(vcpu); + if (root) + goto out_unlock; + root = tdp_mmu_alloc_sp(vcpu); tdp_mmu_init_sp(root, NULL, 0, role); @@ -254,8 +285,17 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu) list_add_rcu(&root->link, &kvm->arch.tdp_mmu_roots); spin_unlock(&kvm->arch.tdp_mmu_pages_lock); +out_unlock: + write_unlock(&kvm->mmu_lock); out: - return __pa(root->spt); + /* + * Note, KVM_REQ_MMU_FREE_OBSOLETE_ROOTS will prevent entering the guest + * and actually consuming the root if it's invalidated after dropping + * mmu_lock, and the root can't be freed as this vCPU holds a reference. + */ + mmu->root.hpa = __pa(root->spt); + mmu->root.pgd = 0; + return 0; } static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, @@ -917,7 +957,7 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm) * the VM is being destroyed). * * Note, kvm_tdp_mmu_zap_invalidated_roots() is gifted the TDP MMU's reference. - * See kvm_tdp_mmu_get_vcpu_root_hpa(). + * See kvm_tdp_mmu_alloc_root(). */ void kvm_tdp_mmu_invalidate_all_roots(struct kvm *kvm) { diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 20d97aa46c49..6e1ea04ca885 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -10,7 +10,7 @@ void kvm_mmu_init_tdp_mmu(struct kvm *kvm); void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm); -hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu); +int kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu); __must_check static inline bool kvm_tdp_mmu_get_root(struct kvm_mmu_page *root) { From dab285e4ec736d964cfa6c7fd6eebd22666b5ebc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:47 -0800 Subject: [PATCH 476/814] KVM: x86/mmu: Alloc TDP MMU roots while holding mmu_lock for read Allocate TDP MMU roots while holding mmu_lock for read, and instead use tdp_mmu_pages_lock to guard against duplicate roots. This allows KVM to create new roots without forcing kvm_tdp_mmu_zap_invalidated_roots() to yield, e.g. allows vCPUs to load new roots after memslot deletion without forcing the zap thread to detect contention and yield (or complete if the kernel isn't preemptible). Note, creating a new TDP MMU root as an mmu_lock reader is safe for two reasons: (1) paths that must guarantee all roots/SPTEs are *visited* take mmu_lock for write and so are still mutually exclusive, e.g. mmu_notifier invalidations, and (2) paths that require all roots/SPTEs to *observe* some given state without holding mmu_lock for write must ensure freshness through some other means, e.g. toggling dirty logging must first wait for SRCU readers to recognize the memslot flags change before processing existing roots/SPTEs. Link: https://lore.kernel.org/r/20240111020048.844847-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/tdp_mmu.c | 55 +++++++++++++++----------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 9a8250a14fc1..d078157e62aa 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -223,51 +223,42 @@ static void tdp_mmu_init_child_sp(struct kvm_mmu_page *child_sp, tdp_mmu_init_sp(child_sp, iter->sptep, iter->gfn, role); } -static struct kvm_mmu_page *kvm_tdp_mmu_try_get_root(struct kvm_vcpu *vcpu) -{ - union kvm_mmu_page_role role = vcpu->arch.mmu->root_role; - int as_id = kvm_mmu_role_as_id(role); - struct kvm *kvm = vcpu->kvm; - struct kvm_mmu_page *root; - - for_each_valid_tdp_mmu_root_yield_safe(kvm, root, as_id) { - if (root->role.word == role.word) - return root; - } - - return NULL; -} - int kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu) { struct kvm_mmu *mmu = vcpu->arch.mmu; union kvm_mmu_page_role role = mmu->root_role; + int as_id = kvm_mmu_role_as_id(role); struct kvm *kvm = vcpu->kvm; struct kvm_mmu_page *root; /* - * Check for an existing root while holding mmu_lock for read to avoid + * Check for an existing root before acquiring the pages lock to avoid * unnecessary serialization if multiple vCPUs are loading a new root. * E.g. when bringing up secondary vCPUs, KVM will already have created * a valid root on behalf of the primary vCPU. */ read_lock(&kvm->mmu_lock); - root = kvm_tdp_mmu_try_get_root(vcpu); - read_unlock(&kvm->mmu_lock); - if (root) - goto out; + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, as_id) { + if (root->role.word == role.word) + goto out_read_unlock; + } - write_lock(&kvm->mmu_lock); + spin_lock(&kvm->arch.tdp_mmu_pages_lock); /* - * Recheck for an existing root after acquiring mmu_lock for write. It - * is possible a new usable root was created between dropping mmu_lock - * (for read) and acquiring it for write. + * Recheck for an existing root after acquiring the pages lock, another + * vCPU may have raced ahead and created a new usable root. Manually + * walk the list of roots as the standard macros assume that the pages + * lock is *not* held. WARN if grabbing a reference to a usable root + * fails, as the last reference to a root can only be put *after* the + * root has been invalidated, which requires holding mmu_lock for write. */ - root = kvm_tdp_mmu_try_get_root(vcpu); - if (root) - goto out_unlock; + list_for_each_entry(root, &kvm->arch.tdp_mmu_roots, link) { + if (root->role.word == role.word && + !WARN_ON_ONCE(!kvm_tdp_mmu_get_root(root))) + goto out_spin_unlock; + } root = tdp_mmu_alloc_sp(vcpu); tdp_mmu_init_sp(root, NULL, 0, role); @@ -280,14 +271,12 @@ int kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu) * is ultimately put by kvm_tdp_mmu_zap_invalidated_roots(). */ refcount_set(&root->tdp_mmu_root_count, 2); - - spin_lock(&kvm->arch.tdp_mmu_pages_lock); list_add_rcu(&root->link, &kvm->arch.tdp_mmu_roots); - spin_unlock(&kvm->arch.tdp_mmu_pages_lock); -out_unlock: - write_unlock(&kvm->mmu_lock); -out: +out_spin_unlock: + spin_unlock(&kvm->arch.tdp_mmu_pages_lock); +out_read_unlock: + read_unlock(&kvm->mmu_lock); /* * Note, KVM_REQ_MMU_FREE_OBSOLETE_ROOTS will prevent entering the guest * and actually consuming the root if it's invalidated after dropping From 576a15de8d299d9d225b86504547ff6498bc2eeb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 10 Jan 2024 18:00:48 -0800 Subject: [PATCH 477/814] KVM: x86/mmu: Free TDP MMU roots while holding mmy_lock for read Free TDP MMU roots from vCPU context while holding mmu_lock for read, it is completely legal to invoke kvm_tdp_mmu_put_root() as a reader. This eliminates the last mmu_lock writer in the TDP MMU's "fast zap" path after requesting vCPUs to reload roots, i.e. allows KVM to zap invalidated roots, free obsolete roots, and allocate new roots in parallel. On large VMs, e.g. 100+ vCPUs, allowing the bulk of the "fast zap" operation to run in parallel with freeing and allocating roots reduces the worst case latency for a vCPU to reload a root from 2-3ms to <100us. Link: https://lore.kernel.org/r/20240111020048.844847-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c9150080fbd2..e5e2af69e24d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3575,10 +3575,14 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa, if (WARN_ON_ONCE(!sp)) return; - if (is_tdp_mmu_page(sp)) + if (is_tdp_mmu_page(sp)) { + lockdep_assert_held_read(&kvm->mmu_lock); kvm_tdp_mmu_put_root(kvm, sp); - else if (!--sp->root_count && sp->role.invalid) - kvm_mmu_prepare_zap_page(kvm, sp, invalid_list); + } else { + lockdep_assert_held_write(&kvm->mmu_lock); + if (!--sp->root_count && sp->role.invalid) + kvm_mmu_prepare_zap_page(kvm, sp, invalid_list); + } *root_hpa = INVALID_PAGE; } @@ -3587,6 +3591,7 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa, void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, ulong roots_to_free) { + bool is_tdp_mmu = tdp_mmu_enabled && mmu->root_role.direct; int i; LIST_HEAD(invalid_list); bool free_active_root; @@ -3609,7 +3614,10 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, return; } - write_lock(&kvm->mmu_lock); + if (is_tdp_mmu) + read_lock(&kvm->mmu_lock); + else + write_lock(&kvm->mmu_lock); for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) if (roots_to_free & KVM_MMU_ROOT_PREVIOUS(i)) @@ -3635,8 +3643,13 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, mmu->root.pgd = 0; } - kvm_mmu_commit_zap_page(kvm, &invalid_list); - write_unlock(&kvm->mmu_lock); + if (is_tdp_mmu) { + read_unlock(&kvm->mmu_lock); + WARN_ON_ONCE(!list_empty(&invalid_list)); + } else { + kvm_mmu_commit_zap_page(kvm, &invalid_list); + write_unlock(&kvm->mmu_lock); + } } EXPORT_SYMBOL_GPL(kvm_mmu_free_roots); From ea3689d9df50c283cb5d647a74aa45e2cc3f8064 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Feb 2024 12:24:10 +0100 Subject: [PATCH 478/814] KVM: fix kvm_mmu_memory_cache allocation warning gcc-14 notices that the arguments to kvmalloc_array() are mixed up: arch/x86/kvm/../../../virt/kvm/kvm_main.c: In function '__kvm_mmu_topup_memory_cache': arch/x86/kvm/../../../virt/kvm/kvm_main.c:424:53: error: 'kvmalloc_array' sizes specified with 'sizeof' in the earlier argument and not in the later argument [-Werror=calloc-transposed-args] 424 | mc->objects = kvmalloc_array(sizeof(void *), capacity, gfp); | ^~~~ arch/x86/kvm/../../../virt/kvm/kvm_main.c:424:53: note: earlier argument should specify number of elements, later size of each element The code still works correctly, but the incorrect order prevents the compiler from properly tracking the object sizes. Fixes: 837f66c71207 ("KVM: Allow for different capacities in kvm_mmu_memory_cache structs") Signed-off-by: Arnd Bergmann Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240212112419.1186065-1-arnd@kernel.org Signed-off-by: Sean Christopherson --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8f03b56dafbd..4c48f61cae35 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -421,7 +421,7 @@ int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity, if (WARN_ON_ONCE(!capacity)) return -EIO; - mc->objects = kvmalloc_array(sizeof(void *), capacity, gfp); + mc->objects = kvmalloc_array(capacity, sizeof(void *), gfp); if (!mc->objects) return -ENOMEM; From 18ca63a2e23c5e170d2d7552b64b1f5ad019cd9b Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:40 +0000 Subject: [PATCH 479/814] MIPS: Probe toolchain support of -msym32 msym32 is not supported by LLVM toolchain. Workaround by probe toolchain support of msym32 for KBUILD_SYM32 feature. Link: https://github.com/ClangBuiltLinux/linux/issues/1544 Signed-off-by: Jiaxun Yang 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 f49807e1f19b..0888074f4dfe 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -299,7 +299,7 @@ drivers-$(CONFIG_PCI) += arch/mips/pci/ ifdef CONFIG_64BIT ifndef KBUILD_SYM32 ifeq ($(shell expr $(load-y) \< 0xffffffff80000000), 0) - KBUILD_SYM32 = y + KBUILD_SYM32 = $(call cc-option-yn, -msym32) endif endif From 1d59822a7ed152f6a253a49978890ffefa8ef40e Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:41 +0000 Subject: [PATCH 480/814] MIPS: Remove cc-option checks for -march=octeon Nowadays our minimal supported GCC/Clang all support -march=octeon. Remove cc-option checks to simplify code. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 0888074f4dfe..daa569ca4372 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -174,10 +174,7 @@ cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mdmx) cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mips3d) cflags-$(CONFIG_CPU_R10000) += $(call cc-option,-march=r10000,-march=r8000) \ -Wa,--trap -cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += $(call cc-option,-march=octeon) -Wa,--trap -ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON)))) -cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon -endif +cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -march=octeon -Wa,--trap cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap From bfc0a330c1b4526b88f6f9e711484b342cb00fb5 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:42 +0000 Subject: [PATCH 481/814] MIPS: Fallback CPU -march flag to ISA level if unsupported LLVM does not implement some of -march options. However those options are not mandatory for kernel to build for those CPUs. Fallback -march CFLAG to ISA level if unsupported by toolchain so we can get those kernel to build with LLVM. Link: https://github.com/ClangBuiltLinux/linux/issues/1544 Reported-by: Nathan Chancellor Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index daa569ca4372..91470931a5b8 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -148,10 +148,10 @@ cflags-y += $(call cc-option,-Wa$(comma)-mno-fix-loongson3-llsc,) # # CPU-dependent compiler/assembler options for optimization. # -cflags-$(CONFIG_CPU_R3000) += -march=r3000 -cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap -cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap -cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap +cflags-$(CONFIG_CPU_R3000) += $(call cc-option,-march=r3000,-march=mips1) +cflags-$(CONFIG_CPU_R4300) += $(call cc-option,-march=r4300,-march=mips3) -Wa,--trap +cflags-$(CONFIG_CPU_R4X00) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap +cflags-$(CONFIG_CPU_TX49XX) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg @@ -160,26 +160,30 @@ cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap cflags-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,--trap cflags-$(CONFIG_CPU_MIPS64_R5) += -march=mips64r5 -Wa,--trap cflags-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,--trap -cflags-$(CONFIG_CPU_P5600) += -march=p5600 -Wa,--trap -modd-spreg -cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap -cflags-$(CONFIG_CPU_R5500) += $(call cc-option,-march=r5500,-march=r5000) \ +cflags-$(CONFIG_CPU_P5600) += $(call cc-option,-march=p5600,-march=mips32r5) \ + -Wa,--trap -modd-spreg +cflags-$(CONFIG_CPU_R5000) += $(call cc-option,-march=r5000,-march=mips4) \ -Wa,--trap -cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \ +cflags-$(CONFIG_CPU_R5500) += $(call cc-option,-march=r5500,-march=mips4) \ -Wa,--trap -cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \ +cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=mips4) \ -Wa,--trap -cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=r5000) \ +cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=mips4) \ + -Wa,--trap +cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=mips64) \ -Wa,--trap cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mdmx) cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mips3d) -cflags-$(CONFIG_CPU_R10000) += $(call cc-option,-march=r10000,-march=r8000) \ +cflags-$(CONFIG_CPU_R10000) += $(call cc-option,-march=r10000,-march=mips4) \ -Wa,--trap cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -march=octeon -Wa,--trap cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2E) += \ + $(call cc-option,-march=loongson2e,-march=mips3) -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2F) += \ + $(call cc-option,-march=loongson2f,-march=mips3) -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) From e7a30874b348d23898f64545b4086edc0741d715 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:43 +0000 Subject: [PATCH 482/814] MIPS: BMIPS: Drop unnecessary assembler flag Nowadays GCC will always pass -march flag to gas, so there is no need to pass another mips32 flag to assembler. Signed-off-by: Jiaxun Yang 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 91470931a5b8..5a078c5487d6 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -170,7 +170,7 @@ cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=mips4) \ -Wa,--trap cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=mips4) \ -Wa,--trap -cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=mips64) \ +cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=mips64r1) \ -Wa,--trap cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mdmx) cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mips3d) @@ -178,7 +178,7 @@ cflags-$(CONFIG_CPU_R10000) += $(call cc-option,-march=r10000,-march=mips4) \ -Wa,--trap cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -march=octeon -Wa,--trap cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 -cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap +cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,--trap cflags-$(CONFIG_CPU_LOONGSON2E) += \ $(call cc-option,-march=loongson2e,-march=mips3) -Wa,--trap From 8a61869706c38b4760e1cd67dd27e36391e44ada Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:44 +0000 Subject: [PATCH 483/814] MIPS: Loongson64: test for -march=loongson3a cflag Currently march flag is hardcoded to loongson3a for GCC and mips64r2 for clang. We can actually test it to simplify the code. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 5a078c5487d6..80aecba24892 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -187,11 +187,8 @@ cflags-$(CONFIG_CPU_LOONGSON2F) += \ # 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,-march=loongson3a,-march=mips64r2) -Wa,--trap cflags-$(CONFIG_CPU_LOONGSON64) += $(call cc-option,-mno-loongson-mmi) cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) From 74efddad96fb37f66906850da0ab9cca59446e49 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:45 +0000 Subject: [PATCH 484/814] MIPS: Limit MIPS_MT_SMP support by ISA reversion MIPS MT ASE is only available on ISA between Release 1 and Release 5. Add ISA level dependency to Kconfig to fix build. Reported-by: Guenter Roeck Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 492d7b900929..50fdf6d99255 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2230,7 +2230,8 @@ config CPU_R4K_CACHE_TLB config MIPS_MT_SMP bool "MIPS MT SMP support (1 TC on each available VPE)" default y - depends on SYS_SUPPORTS_MULTITHREADING && !CPU_MIPSR6 && !CPU_MICROMIPS + depends on TARGET_ISA_REV > 0 && TARGET_ISA_REV < 6 + depends on SYS_SUPPORTS_MULTITHREADING && !CPU_MICROMIPS select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select SYNC_R4K From dd6d29a6148990bb1d39a37c6c2830e6daf9cb46 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:46 +0000 Subject: [PATCH 485/814] MIPS: Implement microMIPS MT ASE helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement various microMIPS MT ASE helpers accroading to: MIPS® Architecture for Programmers Volume IV-f: The MIPS® MT Module for the microMIPS32™ Architecture Fixes build error: {standard input}:2616: Error: branch to a symbol in another ISA mode This make MT ASE available on microMIPS as well. Boot tested on M5150 with microMIPS enabled on M5150. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/asmmacro.h | 22 ++- arch/mips/include/asm/mipsmtregs.h | 256 +++++++++++++++++------------ arch/mips/include/asm/mipsregs.h | 9 + arch/mips/kernel/vpe-mt.c | 4 +- 4 files changed, 179 insertions(+), 112 deletions(-) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 067a635d3bc8..18c2ae58cdf3 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -216,27 +216,33 @@ * Temporary until all gas have MT ASE support */ .macro DMT reg=0 - .word 0x41600bc1 | (\reg << 16) + insn_if_mips 0x41600bc1 | (\reg << 16) + insn32_if_mm 0x0000057C | (\reg << 21) .endm .macro EMT reg=0 - .word 0x41600be1 | (\reg << 16) + insn_if_mips 0x41600be1 | (\reg << 16) + insn32_if_mm 0x0000257C | (\reg << 21) .endm .macro DVPE reg=0 - .word 0x41600001 | (\reg << 16) + insn_if_mips 0x41600001 | (\reg << 16) + insn32_if_mm 0x0000157C | (\reg << 21) .endm .macro EVPE reg=0 - .word 0x41600021 | (\reg << 16) + insn_if_mips 0x41600021 | (\reg << 16) + insn32_if_mm 0x0000357C | (\reg << 21) .endm - .macro MFTR rt=0, rd=0, u=0, sel=0 - .word 0x41000000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel) + .macro MFTR rs=0, rt=0, u=0, sel=0 + insn_if_mips 0x41000000 | (\rt << 16) | (\rs << 11) | (\u << 5) | (\sel) + insn32_if_mm 0x0000000E | (\rt << 21) | (\rs << 16) | (\u << 10) | (\sel << 4) .endm - .macro MTTR rt=0, rd=0, u=0, sel=0 - .word 0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel) + .macro MTTR rt=0, rs=0, u=0, sel=0 + insn_if_mips 0x41800000 | (\rt << 16) | (\rs << 11) | (\u << 5) | (\sel) + insn32_if_mm 0x00000006 | (\rt << 21) | (\rs << 16) | (\u << 10) | (\sel << 4) .endm #ifdef TOOLCHAIN_SUPPORTS_MSA diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h index a8d67c2f4f7b..30e86861c206 100644 --- a/arch/mips/include/asm/mipsmtregs.h +++ b/arch/mips/include/asm/mipsmtregs.h @@ -189,19 +189,24 @@ static inline unsigned core_nvpes(void) return ((conf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; } +#define _ASM_SET_DVPE \ + _ASM_MACRO_1R(dvpe, rt, \ + _ASM_INSN_IF_MIPS(0x41600001 | __rt << 16) \ + _ASM_INSN32_IF_MM(0x0000157C | __rt << 21)) +#define _ASM_UNSET_DVPE ".purgem dvpe\n\t" + static inline unsigned int dvpe(void) { int res = 0; __asm__ __volatile__( - " .set push \n" - " .set noreorder \n" - " .set noat \n" - " .set mips32r2 \n" - " .word 0x41610001 # dvpe $1 \n" - " move %0, $1 \n" - " ehb \n" - " .set pop \n" + " .set push \n" + " .set "MIPS_ISA_LEVEL" \n" + _ASM_SET_DVPE + " dvpe %0 \n" + " ehb \n" + _ASM_UNSET_DVPE + " .set pop \n" : "=r" (res)); instruction_hazard(); @@ -209,16 +214,22 @@ static inline unsigned int dvpe(void) return res; } +#define _ASM_SET_EVPE \ + _ASM_MACRO_1R(evpe, rt, \ + _ASM_INSN_IF_MIPS(0x41600021 | __rt << 16) \ + _ASM_INSN32_IF_MM(0x0000357C | __rt << 21)) +#define _ASM_UNSET_EVPE ".purgem evpe\n\t" + static inline void __raw_evpe(void) { __asm__ __volatile__( - " .set push \n" - " .set noreorder \n" - " .set noat \n" - " .set mips32r2 \n" - " .word 0x41600021 # evpe \n" - " ehb \n" - " .set pop \n"); + " .set push \n" + " .set "MIPS_ISA_LEVEL" \n" + _ASM_SET_EVPE + " evpe $0 \n" + " ehb \n" + _ASM_UNSET_EVPE + " .set pop \n"); } /* Enable virtual processor execution if previous suggested it should be. @@ -232,18 +243,24 @@ static inline void evpe(int previous) __raw_evpe(); } +#define _ASM_SET_DMT \ + _ASM_MACRO_1R(dmt, rt, \ + _ASM_INSN_IF_MIPS(0x41600bc1 | __rt << 16) \ + _ASM_INSN32_IF_MM(0x0000057C | __rt << 21)) +#define _ASM_UNSET_DMT ".purgem dmt\n\t" + static inline unsigned int dmt(void) { int res; __asm__ __volatile__( - " .set push \n" - " .set mips32r2 \n" - " .set noat \n" - " .word 0x41610BC1 # dmt $1 \n" - " ehb \n" - " move %0, $1 \n" - " .set pop \n" + " .set push \n" + " .set "MIPS_ISA_LEVEL" \n" + _ASM_SET_DMT + " dmt %0 \n" + " ehb \n" + _ASM_UNSET_DMT + " .set pop \n" : "=r" (res)); instruction_hazard(); @@ -251,14 +268,21 @@ static inline unsigned int dmt(void) return res; } +#define _ASM_SET_EMT \ + _ASM_MACRO_1R(emt, rt, \ + _ASM_INSN_IF_MIPS(0x41600be1 | __rt << 16) \ + _ASM_INSN32_IF_MM(0x0000257C | __rt << 21)) +#define _ASM_UNSET_EMT ".purgem emt\n\t" + static inline void __raw_emt(void) { __asm__ __volatile__( - " .set push \n" - " .set noreorder \n" - " .set mips32r2 \n" - " .word 0x41600be1 # emt \n" - " ehb \n" + " .set push \n" + " .set "MIPS_ISA_LEVEL" \n" + _ASM_SET_EMT + " emt $0 \n" + _ASM_UNSET_EMT + " ehb \n" " .set pop"); } @@ -276,41 +300,55 @@ static inline void emt(int previous) static inline void ehb(void) { __asm__ __volatile__( - " .set push \n" - " .set mips32r2 \n" - " ehb \n" - " .set pop \n"); + " .set push \n" + " .set "MIPS_ISA_LEVEL" \n" + " ehb \n" + " .set pop \n"); } -#define mftc0(rt,sel) \ +#define _ASM_SET_MFTC0 \ + _ASM_MACRO_2R_1S(mftc0, rs, rt, sel, \ + _ASM_INSN_IF_MIPS(0x41000000 | __rt << 16 | \ + __rs << 11 | \\sel) \ + _ASM_INSN32_IF_MM(0x0000000E | __rt << 21 | \ + __rs << 16 | \\sel << 4)) +#define _ASM_UNSET_MFTC0 ".purgem mftc0\n\t" + +#define mftc0(rt, sel) \ ({ \ - unsigned long __res; \ + unsigned long __res; \ \ __asm__ __volatile__( \ - " .set push \n" \ - " .set mips32r2 \n" \ - " .set noat \n" \ - " # mftc0 $1, $" #rt ", " #sel " \n" \ - " .word 0x41000800 | (" #rt " << 16) | " #sel " \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ + " .set push \n" \ + " .set "MIPS_ISA_LEVEL" \n" \ + _ASM_SET_MFTC0 \ + " mftc0 $1, " #rt ", " #sel " \n" \ + _ASM_UNSET_MFTC0 \ + " .set pop \n" \ : "=r" (__res)); \ \ __res; \ }) +#define _ASM_SET_MFTGPR \ + _ASM_MACRO_2R(mftgpr, rs, rt, \ + _ASM_INSN_IF_MIPS(0x41000020 | __rt << 16 | \ + __rs << 11) \ + _ASM_INSN32_IF_MM(0x0000040E | __rt << 21 | \ + __rs << 16)) +#define _ASM_UNSET_MFTGPR ".purgem mftgpr\n\t" + #define mftgpr(rt) \ ({ \ unsigned long __res; \ \ __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " .set mips32r2 \n" \ - " # mftgpr $1," #rt " \n" \ - " .word 0x41000820 | (" #rt " << 16) \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ + " .set push \n" \ + " .set "MIPS_ISA_LEVEL" \n" \ + _ASM_SET_MFTGPR \ + " mftgpr %0," #rt " \n" \ + _ASM_UNSET_MFTGPR \ + " .set pop \n" \ : "=r" (__res)); \ \ __res; \ @@ -321,35 +359,49 @@ static inline void ehb(void) unsigned long __res; \ \ __asm__ __volatile__( \ - " mftr %0, " #rt ", " #u ", " #sel " \n" \ + " mftr %0, " #rt ", " #u ", " #sel " \n" \ : "=r" (__res)); \ \ __res; \ }) -#define mttgpr(rd,v) \ +#define _ASM_SET_MTTGPR \ + _ASM_MACRO_2R(mttgpr, rt, rs, \ + _ASM_INSN_IF_MIPS(0x41800020 | __rt << 16 | \ + __rs << 11) \ + _ASM_INSN32_IF_MM(0x00000406 | __rt << 21 | \ + __rs << 16)) +#define _ASM_UNSET_MTTGPR ".purgem mttgpr\n\t" + +#define mttgpr(rs, v) \ do { \ __asm__ __volatile__( \ - " .set push \n" \ - " .set mips32r2 \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mttgpr $1, " #rd " \n" \ - " .word 0x41810020 | (" #rd " << 11) \n" \ - " .set pop \n" \ + " .set push \n" \ + " .set "MIPS_ISA_LEVEL" \n" \ + _ASM_SET_MTTGPR \ + " mttgpr %0, " #rs " \n" \ + _ASM_UNSET_MTTGPR \ + " .set pop \n" \ : : "r" (v)); \ } while (0) -#define mttc0(rd, sel, v) \ +#define _ASM_SET_MTTC0 \ + _ASM_MACRO_2R_1S(mttc0, rt, rs, sel, \ + _ASM_INSN_IF_MIPS(0x41800000 | __rt << 16 | \ + __rs << 11 | \\sel) \ + _ASM_INSN32_IF_MM(0x0000040E | __rt << 21 | \ + __rs << 16 | \\sel << 4)) +#define _ASM_UNSET_MTTC0 ".purgem mttc0\n\t" + +#define mttc0(rs, sel, v) \ ({ \ __asm__ __volatile__( \ - " .set push \n" \ - " .set mips32r2 \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mttc0 %0," #rd ", " #sel " \n" \ - " .word 0x41810000 | (" #rd " << 11) | " #sel " \n" \ - " .set pop \n" \ + " .set push \n" \ + " .set "MIPS_ISA_LEVEL" \n" \ + _ASM_SET_MTTC0 \ + " mttc0 %0," #rs ", " #sel " \n" \ + _ASM_UNSET_MTTC0 \ + " .set pop \n" \ : \ : "r" (v)); \ }) @@ -371,49 +423,49 @@ do { \ /* you *must* set the target tc (settc) before trying to use these */ -#define read_vpe_c0_vpecontrol() mftc0(1, 1) -#define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) -#define read_vpe_c0_vpeconf0() mftc0(1, 2) -#define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) -#define read_vpe_c0_vpeconf1() mftc0(1, 3) -#define write_vpe_c0_vpeconf1(val) mttc0(1, 3, val) -#define read_vpe_c0_count() mftc0(9, 0) -#define write_vpe_c0_count(val) mttc0(9, 0, val) -#define read_vpe_c0_status() mftc0(12, 0) -#define write_vpe_c0_status(val) mttc0(12, 0, val) -#define read_vpe_c0_cause() mftc0(13, 0) -#define write_vpe_c0_cause(val) mttc0(13, 0, val) -#define read_vpe_c0_config() mftc0(16, 0) -#define write_vpe_c0_config(val) mttc0(16, 0, val) -#define read_vpe_c0_config1() mftc0(16, 1) -#define write_vpe_c0_config1(val) mttc0(16, 1, val) -#define read_vpe_c0_config7() mftc0(16, 7) -#define write_vpe_c0_config7(val) mttc0(16, 7, val) -#define read_vpe_c0_ebase() mftc0(15, 1) -#define write_vpe_c0_ebase(val) mttc0(15, 1, val) -#define write_vpe_c0_compare(val) mttc0(11, 0, val) -#define read_vpe_c0_badvaddr() mftc0(8, 0) -#define read_vpe_c0_epc() mftc0(14, 0) -#define write_vpe_c0_epc(val) mttc0(14, 0, val) +#define read_vpe_c0_vpecontrol() mftc0($1, 1) +#define write_vpe_c0_vpecontrol(val) mttc0($1, 1, val) +#define read_vpe_c0_vpeconf0() mftc0($1, 2) +#define write_vpe_c0_vpeconf0(val) mttc0($1, 2, val) +#define read_vpe_c0_vpeconf1() mftc0($1, 3) +#define write_vpe_c0_vpeconf1(val) mttc0($1, 3, val) +#define read_vpe_c0_count() mftc0($9, 0) +#define write_vpe_c0_count(val) mttc0($9, 0, val) +#define read_vpe_c0_status() mftc0($12, 0) +#define write_vpe_c0_status(val) mttc0($12, 0, val) +#define read_vpe_c0_cause() mftc0($13, 0) +#define write_vpe_c0_cause(val) mttc0($13, 0, val) +#define read_vpe_c0_config() mftc0($16, 0) +#define write_vpe_c0_config(val) mttc0($16, 0, val) +#define read_vpe_c0_config1() mftc0($16, 1) +#define write_vpe_c0_config1(val) mttc0($16, 1, val) +#define read_vpe_c0_config7() mftc0($16, 7) +#define write_vpe_c0_config7(val) mttc0($16, 7, val) +#define read_vpe_c0_ebase() mftc0($15, 1) +#define write_vpe_c0_ebase(val) mttc0($15, 1, val) +#define write_vpe_c0_compare(val) mttc0($11, 0, val) +#define read_vpe_c0_badvaddr() mftc0($8, 0) +#define read_vpe_c0_epc() mftc0($14, 0) +#define write_vpe_c0_epc(val) mttc0($14, 0, val) /* TC */ -#define read_tc_c0_tcstatus() mftc0(2, 1) -#define write_tc_c0_tcstatus(val) mttc0(2, 1, val) -#define read_tc_c0_tcbind() mftc0(2, 2) -#define write_tc_c0_tcbind(val) mttc0(2, 2, val) -#define read_tc_c0_tcrestart() mftc0(2, 3) -#define write_tc_c0_tcrestart(val) mttc0(2, 3, val) -#define read_tc_c0_tchalt() mftc0(2, 4) -#define write_tc_c0_tchalt(val) mttc0(2, 4, val) -#define read_tc_c0_tccontext() mftc0(2, 5) -#define write_tc_c0_tccontext(val) mttc0(2, 5, val) +#define read_tc_c0_tcstatus() mftc0($2, 1) +#define write_tc_c0_tcstatus(val) mttc0($2, 1, val) +#define read_tc_c0_tcbind() mftc0($2, 2) +#define write_tc_c0_tcbind(val) mttc0($2, 2, val) +#define read_tc_c0_tcrestart() mftc0($2, 3) +#define write_tc_c0_tcrestart(val) mttc0($2, 3, val) +#define read_tc_c0_tchalt() mftc0($2, 4) +#define write_tc_c0_tchalt(val) mttc0($2, 4, val) +#define read_tc_c0_tccontext() mftc0($2, 5) +#define write_tc_c0_tccontext(val) mttc0($2, 5, val) /* GPR */ -#define read_tc_gpr_sp() mftgpr(29) -#define write_tc_gpr_sp(val) mttgpr(29, val) -#define read_tc_gpr_gp() mftgpr(28) -#define write_tc_gpr_gp(val) mttgpr(28, val) +#define read_tc_gpr_sp() mftgpr($29) +#define write_tc_gpr_sp(val) mttgpr($29, val) +#define read_tc_gpr_gp() mftgpr($28) +#define write_tc_gpr_gp(val) mttgpr($28, val) __BUILD_SET_C0(mvpcontrol) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 59ea637c5975..b5a8fdeb9cf3 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1452,6 +1452,15 @@ static inline int mm_insn_16bit(u16 insn) * the ENC encodings. */ +/* Instructions with 1 register operand */ +#define _ASM_MACRO_1R(OP, R1, ENC) \ + ".macro " #OP " " #R1 "\n\t" \ + _ASM_SET_PARSE_R \ + "parse_r __" #R1 ", \\" #R1 "\n\t" \ + ENC \ + _ASM_UNSET_PARSE_R \ + ".endm\n\t" + /* Instructions with 1 register operand & 1 immediate operand */ #define _ASM_MACRO_1R1I(OP, R1, I2, ENC) \ ".macro " #OP " " #R1 ", " #I2 "\n\t" \ diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c index 667bc75f6420..84124ac2d2a5 100644 --- a/arch/mips/kernel/vpe-mt.c +++ b/arch/mips/kernel/vpe-mt.c @@ -95,8 +95,8 @@ int vpe_run(struct vpe *v) * We don't pass the memsize here, so VPE programs need to be * compiled with DFLT_STACK_SIZE and DFLT_HEAP_SIZE defined. */ - mttgpr(7, 0); - mttgpr(6, v->ntcs); + mttgpr($7, 0); + mttgpr($6, v->ntcs); /* set up VPE1 */ /* From a640d6762a7d404644201ebf6d2a078e8dc84f97 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Fri, 2 Feb 2024 18:21:47 +0000 Subject: [PATCH 486/814] MIPS: mipsregs: Set proper ISA level for virt extensions c994a3ec7ecc ("MIPS: set mips32r5 for virt extensions") setted some instructions in virt extensions to ISA level mips32r5. However TLB related vz instructions was leftover, also this shouldn't be done to a R5 or R6 kernel buid. Reorg macros to set ISA level as needed when _ASM_SET_VIRT is called. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mipsregs.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b5a8fdeb9cf3..d2c7bc241a84 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -2232,7 +2232,14 @@ do { \ _ASM_INSN_IF_MIPS(0x4200000c) \ _ASM_INSN32_IF_MM(0x0000517c) #else /* !TOOLCHAIN_SUPPORTS_VIRT */ -#define _ASM_SET_VIRT ".set\tvirt\n\t" +#if MIPS_ISA_REV >= 5 +#define _ASM_SET_VIRT_ISA +#elif defined(CONFIG_64BIT) +#define _ASM_SET_VIRT_ISA ".set\tmips64r5\n\t" +#else +#define _ASM_SET_VIRT_ISA ".set\tmips32r5\n\t" +#endif +#define _ASM_SET_VIRT _ASM_SET_VIRT_ISA ".set\tvirt\n\t" #define _ASM_SET_MFGC0 _ASM_SET_VIRT #define _ASM_SET_DMFGC0 _ASM_SET_VIRT #define _ASM_SET_MTGC0 _ASM_SET_VIRT @@ -2253,7 +2260,6 @@ do { \ ({ int __res; \ __asm__ __volatile__( \ ".set\tpush\n\t" \ - ".set\tmips32r5\n\t" \ _ASM_SET_MFGC0 \ "mfgc0\t%0, " #source ", %1\n\t" \ _ASM_UNSET_MFGC0 \ @@ -2267,7 +2273,6 @@ do { \ ({ unsigned long long __res; \ __asm__ __volatile__( \ ".set\tpush\n\t" \ - ".set\tmips64r5\n\t" \ _ASM_SET_DMFGC0 \ "dmfgc0\t%0, " #source ", %1\n\t" \ _ASM_UNSET_DMFGC0 \ @@ -2281,7 +2286,6 @@ do { \ do { \ __asm__ __volatile__( \ ".set\tpush\n\t" \ - ".set\tmips32r5\n\t" \ _ASM_SET_MTGC0 \ "mtgc0\t%z0, " #register ", %1\n\t" \ _ASM_UNSET_MTGC0 \ @@ -2294,7 +2298,6 @@ do { \ do { \ __asm__ __volatile__( \ ".set\tpush\n\t" \ - ".set\tmips64r5\n\t" \ _ASM_SET_DMTGC0 \ "dmtgc0\t%z0, " #register ", %1\n\t" \ _ASM_UNSET_DMTGC0 \ From 6d778f61bedabc69be37dcdcabf4a7dc9a7b96d2 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 15 Feb 2024 20:17:28 +0300 Subject: [PATCH 487/814] mips: zboot: Fix "no previous prototype" build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without having the putc() prototype forwardly declared the next build-warning is printed: arch/mips/boot/compressed/uart-prom.c:6:6: warning: no previous prototype for ‘putc’ [-Wmissing-prototypes] ... Fix that by adding the "decompress.h" header file with the putc() function declaration to the source files which have the method redefined. Signed-off-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/compressed/uart-16550.c | 2 ++ arch/mips/boot/compressed/uart-alchemy.c | 2 ++ arch/mips/boot/compressed/uart-prom.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c index 09dcd2c561d9..db618e72a0c4 100644 --- a/arch/mips/boot/compressed/uart-16550.c +++ b/arch/mips/boot/compressed/uart-16550.c @@ -8,6 +8,8 @@ #include +#include "decompress.h" + #if defined(CONFIG_MACH_LOONGSON64) || defined(CONFIG_MIPS_MALTA) #define UART_BASE 0x1fd003f8 #define PORT(offset) (CKSEG1ADDR(UART_BASE) + (offset)) diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c index 8ec63011e7dc..003967c084b3 100644 --- a/arch/mips/boot/compressed/uart-alchemy.c +++ b/arch/mips/boot/compressed/uart-alchemy.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include "decompress.h" + void putc(char c) { alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); diff --git a/arch/mips/boot/compressed/uart-prom.c b/arch/mips/boot/compressed/uart-prom.c index a8a0a32e05d1..5fa3b9945333 100644 --- a/arch/mips/boot/compressed/uart-prom.c +++ b/arch/mips/boot/compressed/uart-prom.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include "decompress.h" + void putc(char c) { prom_putchar(c); From 188942f05ce45f80c06f7242ad7478bd204c3387 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 15 Feb 2024 20:17:29 +0300 Subject: [PATCH 488/814] tty: mips_ejtag_fdc: Fix passing incompatible pointer type warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mips_ejtag_fdc_encode() method expects having a first argument passed of the "u8 **" type, meanwhile the driver passes the "const char **" type. That causes the next build-warning: drivers/tty/mips_ejtag_fdc.c: In function ‘mips_ejtag_fdc_console_write’: drivers/tty/mips_ejtag_fdc.c:343:32: error: passing argument 1 of ‘mips_ejtag_fdc_encode’ from incompatible pointer type [-Werror=incompatible-pointer-types] word = mips_ejtag_fdc_encode(&buf_ptr, &buf_len, 1); ^ drivers/tty/mips_ejtag_fdc.c:216:24: note: expected ‘const u8 ** {aka const unsigned char **}’ but argument is of type ‘const char **’ static struct fdc_word mips_ejtag_fdc_encode(const u8 **ptrs, ^~~~~~~~~~~~~~~~~~~~~ Fix it by altering the type of the pointer which is passed to the mips_ejtag_fdc_encode() method. Fixes: ce7cbd9a6c81 ("tty: mips_ejtag_fdc: use u8 for character pointers") Signed-off-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- drivers/tty/mips_ejtag_fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index aac80b69a069..afbf7738c7c4 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -309,7 +309,7 @@ static void mips_ejtag_fdc_console_write(struct console *c, const char *s, unsigned int i, buf_len, cpu; bool done_cr = false; char buf[4]; - const char *buf_ptr = buf; + const u8 *buf_ptr = buf; /* Number of bytes of input data encoded up to each byte in buf */ u8 inc[4]; From 0cbca1bf44a0b8666c91ce3438f235c6fe70fbf1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 23 Feb 2024 05:17:53 -0500 Subject: [PATCH 489/814] x86: irq: unconditionally define KVM interrupt vectors Unlike arch/x86/kernel/idt.c, FRED support chose to remove the #ifdefs from the .c files and concentrate them in the headers, where unused handlers are #define'd to NULL. However, the constants for KVM's 3 posted interrupt vectors are still defined conditionally in irq_vectors.h. In the tree that FRED support was developed on, this is innocuous because CONFIG_HAVE_KVM was effectively always set. With the cleanups that recently went into the KVM tree to remove CONFIG_HAVE_KVM, the conditional became IS_ENABLED(CONFIG_KVM). This causes a linux-next compilation failure in FRED code, when CONFIG_KVM=n. In preparation for the merging of FRED in Linux 6.9, define the interrupt vector numbers unconditionally. Cc: x86@kernel.org Reported-by: Stephen Rothwell Suggested-by: Xin Li (Intel) Suggested-by: Thomas Gleixner Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/irq_vectors.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 3f73ac3ed3a0..d18bfb238f66 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -84,11 +84,9 @@ #define HYPERVISOR_CALLBACK_VECTOR 0xf3 /* Vector for KVM to deliver posted interrupt IPI */ -#if IS_ENABLED(CONFIG_KVM) #define POSTED_INTR_VECTOR 0xf2 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 #define POSTED_INTR_NESTED_VECTOR 0xf0 -#endif #define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef From 00ca8a15dafa990d391abc37f2b8256ddf909b35 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 17 Feb 2024 10:39:37 +0100 Subject: [PATCH 490/814] phy: constify of_phandle_args in xlate The xlate callbacks are supposed to translate of_phandle_args to proper provider without modifying the of_phandle_args. Make the argument pointer to const for code safety and readability. Signed-off-by: Krzysztof Kozlowski Acked-by: Thierry Reding Acked-by: Linus Walleij Acked-by: Florian Fainelli #Broadcom Link: https://lore.kernel.org/r/20240217093937.58234-1-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/allwinner/phy-sun4i-usb.c | 2 +- drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c | 2 +- drivers/phy/broadcom/phy-bcm-sr-pcie.c | 2 +- drivers/phy/broadcom/phy-bcm-sr-usb.c | 2 +- drivers/phy/broadcom/phy-bcm63xx-usbh.c | 2 +- drivers/phy/broadcom/phy-brcm-usb.c | 2 +- drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c | 2 +- drivers/phy/freescale/phy-fsl-lynx-28g.c | 2 +- drivers/phy/hisilicon/phy-histb-combphy.c | 2 +- drivers/phy/intel/phy-intel-lgm-combo.c | 2 +- drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c | 2 +- drivers/phy/marvell/phy-armada375-usb2.c | 2 +- drivers/phy/marvell/phy-armada38x-comphy.c | 2 +- drivers/phy/marvell/phy-berlin-sata.c | 2 +- drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 2 +- drivers/phy/marvell/phy-mvebu-cp110-comphy.c | 2 +- drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c | 2 +- drivers/phy/mediatek/phy-mtk-tphy.c | 2 +- drivers/phy/mediatek/phy-mtk-xsphy.c | 2 +- drivers/phy/microchip/lan966x_serdes.c | 2 +- drivers/phy/microchip/sparx5_serdes.c | 2 +- drivers/phy/mscc/phy-ocelot-serdes.c | 2 +- drivers/phy/phy-core.c | 8 ++++---- drivers/phy/phy-xgene.c | 2 +- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 +- drivers/phy/ralink/phy-mt7621-pci.c | 2 +- drivers/phy/renesas/phy-rcar-gen2.c | 2 +- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- drivers/phy/renesas/r8a779f0-ether-serdes.c | 2 +- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 2 +- drivers/phy/rockchip/phy-rockchip-pcie.c | 2 +- drivers/phy/samsung/phy-exynos-mipi-video.c | 2 +- drivers/phy/samsung/phy-exynos5-usbdrd.c | 2 +- drivers/phy/samsung/phy-samsung-usb2.c | 2 +- drivers/phy/socionext/phy-uniphier-usb2.c | 2 +- drivers/phy/st/phy-miphy28lp.c | 2 +- drivers/phy/st/phy-spear1310-miphy.c | 2 +- drivers/phy/st/phy-spear1340-miphy.c | 2 +- drivers/phy/st/phy-stm32-usbphyc.c | 2 +- drivers/phy/tegra/xusb.c | 2 +- drivers/phy/ti/phy-am654-serdes.c | 2 +- drivers/phy/ti/phy-da8xx-usb.c | 2 +- drivers/phy/ti/phy-gmii-sel.c | 2 +- drivers/phy/xilinx/phy-zynqmp.c | 2 +- drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | 2 +- include/linux/phy/phy.h | 14 +++++++------- 46 files changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index e53a9a9317bc..b0f19e950601 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -683,7 +683,7 @@ static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb, } static struct phy *sun4i_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c index 2712c4bd549d..5468831d6ab9 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c @@ -350,7 +350,7 @@ static int phy_g12a_usb3_pcie_exit(struct phy *phy) } static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); unsigned int mode; diff --git a/drivers/phy/broadcom/phy-bcm-sr-pcie.c b/drivers/phy/broadcom/phy-bcm-sr-pcie.c index 8a4aadf166cf..ff9b3862bf7a 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-sr-pcie.c @@ -195,7 +195,7 @@ static const struct phy_ops sr_paxc_phy_ops = { }; static struct phy *sr_pcie_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sr_pcie_phy_core *core; int phy_idx; diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c index b0bd18a5df87..6bcfe83609c8 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-usb.c +++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c @@ -209,7 +209,7 @@ static const struct phy_ops sr_phy_ops = { }; static struct phy *bcm_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct bcm_usb_phy_cfg *phy_cfg; int phy_idx; diff --git a/drivers/phy/broadcom/phy-bcm63xx-usbh.c b/drivers/phy/broadcom/phy-bcm63xx-usbh.c index f8183dea774b..647644de041b 100644 --- a/drivers/phy/broadcom/phy-bcm63xx-usbh.c +++ b/drivers/phy/broadcom/phy-bcm63xx-usbh.c @@ -366,7 +366,7 @@ static const struct phy_ops bcm63xx_usbh_phy_ops = { }; static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct bcm63xx_usbh_phy *usbh = dev_get_drvdata(dev); diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index a16f0b58eb74..ad2eec095601 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -175,7 +175,7 @@ static const struct phy_ops brcm_usb_phy_ops = { }; static struct phy *brcm_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct brcm_usb_phy_data *data = dev_get_drvdata(dev); diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index 0ae052df3765..38388dd04bdc 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -294,7 +294,7 @@ static int mixel_lvds_phy_reset(struct device *dev) } static struct phy *mixel_lvds_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); unsigned int phy_id; diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index e2187767ce00..b86da8e9daa4 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -556,7 +556,7 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) } static struct phy *lynx_28g_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct lynx_28g_priv *priv = dev_get_drvdata(dev); int idx = args->args[0]; diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index c44588fd5a53..7436dcae3981 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -163,7 +163,7 @@ static const struct phy_ops histb_combphy_ops = { }; static struct phy *histb_combphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct histb_combphy_priv *priv = dev_get_drvdata(dev); struct histb_combphy_mode *mode = &priv->mode; diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index d32e267c0001..f8e3054a9e59 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -508,7 +508,7 @@ static const struct phy_ops intel_cbphy_ops = { }; static struct phy *intel_cbphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct intel_combo_phy *cbphy = dev_get_drvdata(dev); u32 iphy_id; diff --git a/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c b/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c index ef93bf2cba10..406a87c8b759 100644 --- a/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c +++ b/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c @@ -358,7 +358,7 @@ static const struct phy_ops ltq_vrx200_pcie_phy_ops = { }; static struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct ltq_vrx200_pcie_phy_priv *priv = dev_get_drvdata(dev); unsigned int mode; diff --git a/drivers/phy/marvell/phy-armada375-usb2.c b/drivers/phy/marvell/phy-armada375-usb2.c index b141e3cd8a94..3731f9b25655 100644 --- a/drivers/phy/marvell/phy-armada375-usb2.c +++ b/drivers/phy/marvell/phy-armada375-usb2.c @@ -61,7 +61,7 @@ static const struct phy_ops armada375_usb_phy_ops = { * USB3 case it still optional and we use ENODEV. */ static struct phy *armada375_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/marvell/phy-armada38x-comphy.c b/drivers/phy/marvell/phy-armada38x-comphy.c index d3259984ee8e..5063361b0120 100644 --- a/drivers/phy/marvell/phy-armada38x-comphy.c +++ b/drivers/phy/marvell/phy-armada38x-comphy.c @@ -160,7 +160,7 @@ static const struct phy_ops a38x_comphy_ops = { }; static struct phy *a38x_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct a38x_comphy_lane *lane; struct phy *phy; diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index f972d78372ea..c90e2867900c 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -155,7 +155,7 @@ static int phy_berlin_sata_power_off(struct phy *phy) } static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_berlin_priv *priv = dev_get_drvdata(dev); int i; diff --git a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c index 24c3371e2bb2..41162d7228c9 100644 --- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c @@ -1213,7 +1213,7 @@ static const struct phy_ops mvebu_a3700_comphy_ops = { }; static struct phy *mvebu_a3700_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mvebu_a3700_comphy_lane *lane; unsigned int port; diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c index b0dd13366598..da5e8f405749 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c @@ -917,7 +917,7 @@ static const struct phy_ops mvebu_comphy_ops = { }; static struct phy *mvebu_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mvebu_comphy_lane *lane; struct phy *phy; diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c index 972c129185f7..058e1d926630 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c @@ -165,7 +165,7 @@ static int mtk_mipi_phy_power_off(struct phy *phy) } static struct phy *mtk_mipi_cdphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mtk_mipi_cdphy_port *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index a4746f6cb8a1..25b86bbb9cec 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -1467,7 +1467,7 @@ static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) } static struct phy *mtk_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mtk_tphy *tphy = dev_get_drvdata(dev); struct mtk_phy_instance *instance = NULL; diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c index b222fbbd71d1..064fd0941727 100644 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c @@ -378,7 +378,7 @@ static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) } static struct phy *mtk_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mtk_xsphy *xsphy = dev_get_drvdata(dev); struct xsphy_instance *inst = NULL; diff --git a/drivers/phy/microchip/lan966x_serdes.c b/drivers/phy/microchip/lan966x_serdes.c index c1a41b6cd29b..0188b0f01a8d 100644 --- a/drivers/phy/microchip/lan966x_serdes.c +++ b/drivers/phy/microchip/lan966x_serdes.c @@ -516,7 +516,7 @@ static const struct phy_ops serdes_ops = { }; static struct phy *serdes_simple_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_ctrl *ctrl = dev_get_drvdata(dev); unsigned int port, idx, i; diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c index 01bd5ea620c5..7cb85029fab3 100644 --- a/drivers/phy/microchip/sparx5_serdes.c +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -2509,7 +2509,7 @@ static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = { /* Client lookup function, uses serdes index */ static struct phy *sparx5_serdes_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sparx5_serdes_private *priv = dev_get_drvdata(dev); int idx; diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c index d9443e865a78..1cd1b5db2ad7 100644 --- a/drivers/phy/mscc/phy-ocelot-serdes.c +++ b/drivers/phy/mscc/phy-ocelot-serdes.c @@ -441,7 +441,7 @@ static const struct phy_ops serdes_ops = { }; static struct phy *serdes_simple_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_ctrl *ctrl = dev_get_drvdata(dev); unsigned int port, idx, i; diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index d9be6a4d5383..7f9b4de772ee 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -700,8 +700,8 @@ EXPORT_SYMBOL_GPL(devm_phy_put); * should provide a custom of_xlate function that reads the *args* and returns * the appropriate phy. */ -struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args - *args) +struct phy *of_phy_simple_xlate(struct device *dev, + const struct of_phandle_args *args) { struct phy *phy; struct class_dev_iter iter; @@ -1095,7 +1095,7 @@ EXPORT_SYMBOL_GPL(devm_phy_destroy); struct phy_provider *__of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct phy_provider *phy_provider; @@ -1158,7 +1158,7 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register); struct phy_provider *__devm_of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct phy_provider **ptr, *phy_provider; diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 1f0f908323f0..5007dc7a357c 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -1611,7 +1611,7 @@ static const struct phy_ops xgene_phy_ops = { }; static struct phy *xgene_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct xgene_phy_ctx *ctx = dev_get_drvdata(dev); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index b6908a03da58..546d3c6bee32 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -3454,7 +3454,7 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp) return 0; } -static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_args *args) +static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phandle_args *args) { struct qmp_combo *qmp = dev_get_drvdata(dev); diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 2f876f158e1d..a591ad95347c 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -263,7 +263,7 @@ static const struct phy_ops mt7621_pci_phy_ops = { }; static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index 507435af2656..c0221e7258c0 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c @@ -306,7 +306,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = { MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); static struct phy *rcar_gen2_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rcar_gen2_phy_driver *drv; struct device_node *np = args->np; diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index e53eace7c91e..c8b58607b037 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -608,7 +608,7 @@ static const unsigned int rcar_gen3_phy_cable[] = { }; static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index fc6e398fa3bf..f1f1da4a0b1f 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -334,7 +334,7 @@ static const struct phy_ops r8a779f0_eth_serdes_ops = { }; static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev); diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 5de5e2e97ffa..76b9cf417591 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -251,7 +251,7 @@ static const struct phy_ops rochchip_combphy_ops = { .owner = THIS_MODULE, }; -static struct phy *rockchip_combphy_xlate(struct device *dev, struct of_phandle_args *args) +static struct phy *rockchip_combphy_xlate(struct device *dev, const struct of_phandle_args *args) { struct rockchip_combphy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c index 1bbd6be2a584..51cc5ece0e63 100644 --- a/drivers/phy/rockchip/phy-rockchip-pcie.c +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -82,7 +82,7 @@ static struct rockchip_pcie_phy *to_pcie_phy(struct phy_pcie_instance *inst) } static struct phy *rockchip_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rockchip_pcie_phy *rk_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c index 592d8067e848..f6756a609a9a 100644 --- a/drivers/phy/samsung/phy-exynos-mipi-video.c +++ b/drivers/phy/samsung/phy-exynos-mipi-video.c @@ -274,7 +274,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy) } static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index 3f310b28bfff..04171eed5b16 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -715,7 +715,7 @@ static int exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy *phy_drd) } static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev); diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index 68a174eca0ba..9de744cd6f39 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -87,7 +87,7 @@ static const struct phy_ops samsung_usb2_phy_ops = { }; static struct phy *samsung_usb2_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct samsung_usb2_phy_driver *drv; diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c index 3f2086ed4fe4..21c201717d95 100644 --- a/drivers/phy/socionext/phy-uniphier-usb2.c +++ b/drivers/phy/socionext/phy-uniphier-usb2.c @@ -81,7 +81,7 @@ static int uniphier_u2phy_init(struct phy *phy) } static struct phy *uniphier_u2phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c index e30305b77f0d..063fc38788ed 100644 --- a/drivers/phy/st/phy-miphy28lp.c +++ b/drivers/phy/st/phy-miphy28lp.c @@ -1074,7 +1074,7 @@ static int miphy28lp_get_addr(struct miphy28lp_phy *miphy_phy) } static struct phy *miphy28lp_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct miphy28lp_dev *miphy_dev = dev_get_drvdata(dev); struct miphy28lp_phy *miphy_phy = NULL; diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c index 35a9831b5161..c661ab63505f 100644 --- a/drivers/phy/st/phy-spear1310-miphy.c +++ b/drivers/phy/st/phy-spear1310-miphy.c @@ -183,7 +183,7 @@ static const struct phy_ops spear1310_miphy_ops = { }; static struct phy *spear1310_miphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct spear1310_miphy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c index 34a1cf21015f..85a60d64ebb7 100644 --- a/drivers/phy/st/phy-spear1340-miphy.c +++ b/drivers/phy/st/phy-spear1340-miphy.c @@ -220,7 +220,7 @@ static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend, spear1340_miphy_resume); static struct phy *spear1340_miphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index d5e7e44000b5..9dbe60dcf319 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -574,7 +574,7 @@ static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, } static struct phy *stm32_usbphyc_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); struct stm32_usbphyc_phy *usbphyc_phy = NULL; diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 142ebe0247cc..0dc86a7740e3 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -22,7 +22,7 @@ #include "xusb.h" static struct phy *tegra_xusb_pad_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct tegra_xusb_pad *pad = dev_get_drvdata(dev); struct phy *phy = NULL; diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 3f1d43e8b7ad..8b3b937de624 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -495,7 +495,7 @@ static void serdes_am654_release(struct phy *x) } static struct phy *serdes_am654_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_am654 *am654_phy; struct phy *phy; diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c index b7a9ef3f4654..0fe577f0d6c1 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -119,7 +119,7 @@ static const struct phy_ops da8xx_usb20_phy_ops = { }; static struct phy *da8xx_usb_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 81dd1c3449d9..b30bf740e2e0 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -297,7 +297,7 @@ static const struct phy_ops phy_gmii_sel_ops = { }; static struct phy *phy_gmii_sel_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); int phy_id = args->args[0]; diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 2559c6594cea..f72c5257d712 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -768,7 +768,7 @@ static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = { /* Translate OF phandle and args to PHY instance. */ static struct phy *xpsgtr_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); struct xpsgtr_phy *gtr_phy; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c index 7641848be4de..96ef57a7d385 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c @@ -685,7 +685,7 @@ static const struct phy_ops sata_phy_ops = { }; static struct phy *tegra_xusb_padctl_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev); unsigned int index = args->args[0]; diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index f6d607ef0e80..58be86e6fe83 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -176,7 +176,7 @@ struct phy_provider { struct module *owner; struct list_head list; struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args); + const struct of_phandle_args *args); }; /** @@ -265,7 +265,7 @@ void phy_put(struct device *dev, struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_get(struct device_node *np, const char *con_id); struct phy *of_phy_simple_xlate(struct device *dev, - struct of_phandle_args *args); + const struct of_phandle_args *args); struct phy *phy_create(struct device *dev, struct device_node *node, const struct phy_ops *ops); struct phy *devm_phy_create(struct device *dev, struct device_node *node, @@ -275,11 +275,11 @@ void devm_phy_destroy(struct device *dev, struct phy *phy); struct phy_provider *__of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)); + const struct of_phandle_args *args)); struct phy_provider *__devm_of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)); + const struct of_phandle_args *args)); void of_phy_provider_unregister(struct phy_provider *phy_provider); void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider); @@ -479,7 +479,7 @@ static inline struct phy *of_phy_get(struct device_node *np, const char *con_id) } static inline struct phy *of_phy_simple_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { return ERR_PTR(-ENOSYS); } @@ -509,7 +509,7 @@ static inline void devm_phy_destroy(struct device *dev, struct phy *phy) static inline struct phy_provider *__of_phy_provider_register( struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { return ERR_PTR(-ENOSYS); } @@ -517,7 +517,7 @@ static inline struct phy_provider *__of_phy_provider_register( static inline struct phy_provider *__devm_of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { return ERR_PTR(-ENOSYS); } From 00de073e2420df02ac0f1a19dbfb60ff8eb198be Mon Sep 17 00:00:00 2001 From: Nina Schoetterl-Glausch Date: Thu, 11 Jan 2024 10:48:05 +0100 Subject: [PATCH 491/814] KVM: s390: selftest: memop: Fix undefined behavior If an integer's type has x bits, shifting the integer left by x or more is undefined behavior. This can happen in the rotate function when attempting to do a rotation of the whole value by 0. Fixes: 0dd714bfd200 ("KVM: s390: selftest: memop: Add cmpxchg tests") Signed-off-by: Nina Schoetterl-Glausch Link: https://lore.kernel.org/r/20240111094805.363047-1-nsg@linux.ibm.com Acked-by: Janosch Frank Signed-off-by: Janosch Frank Message-Id: <20240111094805.363047-1-nsg@linux.ibm.com> --- tools/testing/selftests/kvm/s390x/memop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index bb3ca9a5d731..4ec8d0181e8d 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -489,6 +489,8 @@ static __uint128_t rotate(int size, __uint128_t val, int amount) amount = (amount + bits) % bits; val = cut_to_size(size, val); + if (!amount) + return val; return (val << (bits - amount)) | (val >> amount); } From 284851ee5caef1b42b513752bf1642ce4570bdc1 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 16 Feb 2024 15:59:41 +0000 Subject: [PATCH 492/814] KVM: Get rid of return value from kvm_arch_create_vm_debugfs() The general expectation with debugfs is that any initialization failure is nonfatal. Nevertheless, kvm_arch_create_vm_debugfs() allows implementations to return an error and kvm_create_vm_debugfs() allows that to fail VM creation. Change to a void return to discourage architectures from making debugfs failures fatal for the VM. Seems like everyone already had the right idea, as all implementations already return 0 unconditionally. Acked-by: Marc Zyngier Acked-by: Paolo Bonzini Link: https://lore.kernel.org/r/20240216155941.2029458-1-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/powerpc/kvm/powerpc.c | 3 +-- arch/x86/kvm/debugfs.c | 3 +-- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 8 ++------ 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 23407fbd73c9..d32abe7fe6ab 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -2538,9 +2538,8 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_ vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs(vcpu, debugfs_dentry); } -int kvm_arch_create_vm_debugfs(struct kvm *kvm) +void kvm_arch_create_vm_debugfs(struct kvm *kvm) { if (kvm->arch.kvm_ops->create_vm_debugfs) kvm->arch.kvm_ops->create_vm_debugfs(kvm); - return 0; } diff --git a/arch/x86/kvm/debugfs.c b/arch/x86/kvm/debugfs.c index 95ea1a1f7403..999227fc7c66 100644 --- a/arch/x86/kvm/debugfs.c +++ b/arch/x86/kvm/debugfs.c @@ -189,9 +189,8 @@ static const struct file_operations mmu_rmaps_stat_fops = { .release = kvm_mmu_rmaps_stat_release, }; -int kvm_arch_create_vm_debugfs(struct kvm *kvm) +void kvm_arch_create_vm_debugfs(struct kvm *kvm) { debugfs_create_file("mmu_rmaps_stat", 0644, kvm->debugfs_dentry, kvm, &mmu_rmaps_stat_fops); - return 0; } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7e7fd25b09b3..9a45f673f687 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1507,7 +1507,7 @@ bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu); bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu); int kvm_arch_post_init_vm(struct kvm *kvm); void kvm_arch_pre_destroy_vm(struct kvm *kvm); -int kvm_arch_create_vm_debugfs(struct kvm *kvm); +void kvm_arch_create_vm_debugfs(struct kvm *kvm); #ifndef __KVM_HAVE_ARCH_VM_ALLOC /* diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 10bfc88a69f7..c681149c382a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1150,10 +1150,7 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, const char *fdname) &stat_fops_per_vm); } - ret = kvm_arch_create_vm_debugfs(kvm); - if (ret) - goto out_err; - + kvm_arch_create_vm_debugfs(kvm); return 0; out_err: kvm_destroy_vm_debugfs(kvm); @@ -1183,9 +1180,8 @@ void __weak kvm_arch_pre_destroy_vm(struct kvm *kvm) * Cleanup should be automatic done in kvm_destroy_vm_debugfs() recursively, so * a per-arch destroy interface is not needed. */ -int __weak kvm_arch_create_vm_debugfs(struct kvm *kvm) +void __weak kvm_arch_create_vm_debugfs(struct kvm *kvm) { - return 0; } static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) From 1d6f83f60f79ff0118823d904dc1f04ba89f9428 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:44 +0000 Subject: [PATCH 493/814] KVM: arm64: vgic: Store LPIs in an xarray Using a linked-list for LPIs is less than ideal as it of course requires iterative searches to find a particular entry. An xarray is a better data structure for this use case, as it provides faster searches and can still handle a potentially sparse range of INTID allocations. Start by storing LPIs in an xarray, punting usage of the xarray to a subsequent change. The observant among you will notice that we added yet another lock to the chain of locking order rules; document the ordering of the xa_lock. Don't worry, we'll get rid of the lpi_list_lock one day... Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-2-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-init.c | 3 +++ arch/arm64/kvm/vgic/vgic-its.c | 16 ++++++++++++++++ arch/arm64/kvm/vgic/vgic.c | 4 +++- include/kvm/arm_vgic.h | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index e949e1d0fd9f..411719053107 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -56,6 +56,7 @@ void kvm_vgic_early_init(struct kvm *kvm) INIT_LIST_HEAD(&dist->lpi_list_head); INIT_LIST_HEAD(&dist->lpi_translation_cache); raw_spin_lock_init(&dist->lpi_list_lock); + xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ); } /* CREATION */ @@ -366,6 +367,8 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm) if (vgic_supports_direct_msis(kvm)) vgic_v4_teardown(kvm); + + xa_destroy(&dist->lpi_xa); } static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index e2764d0ffa9f..fb2d3c356984 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -52,6 +52,12 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, if (!irq) return ERR_PTR(-ENOMEM); + ret = xa_reserve_irq(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT); + if (ret) { + kfree(irq); + return ERR_PTR(ret); + } + INIT_LIST_HEAD(&irq->lpi_list); INIT_LIST_HEAD(&irq->ap_list); raw_spin_lock_init(&irq->irq_lock); @@ -86,12 +92,22 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, goto out_unlock; } + ret = xa_err(xa_store(&dist->lpi_xa, intid, irq, 0)); + if (ret) { + xa_release(&dist->lpi_xa, intid); + kfree(irq); + goto out_unlock; + } + list_add_tail(&irq->lpi_list, &dist->lpi_list_head); dist->lpi_list_count++; out_unlock: raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); + if (ret) + return ERR_PTR(ret); + /* * We "cache" the configuration table entries in our struct vgic_irq's. * However we only have those structs for mapped IRQs, so we read in diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index db2a95762b1b..92e4d2fea365 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -30,7 +30,8 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = { * its->its_lock (mutex) * vgic_cpu->ap_list_lock must be taken with IRQs disabled * kvm->lpi_list_lock must be taken with IRQs disabled - * vgic_irq->irq_lock must be taken with IRQs disabled + * vgic_dist->lpi_xa.xa_lock must be taken with IRQs disabled + * vgic_irq->irq_lock must be taken with IRQs disabled * * As the ap_list_lock might be taken from the timer interrupt handler, * we have to disable IRQs before taking this lock and everything lower @@ -131,6 +132,7 @@ void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq) return; list_del(&irq->lpi_list); + xa_erase(&dist->lpi_xa, irq->intid); dist->lpi_list_count--; kfree(irq); diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 8cc38e836f54..795b35656b54 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -275,6 +276,7 @@ struct vgic_dist { /* Protects the lpi_list and the count value below. */ raw_spinlock_t lpi_list_lock; + struct xarray lpi_xa; struct list_head lpi_list_head; int lpi_list_count; From 5a021df719164abdc64757993a41fe673a63323b Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:45 +0000 Subject: [PATCH 494/814] KVM: arm64: vgic: Use xarray to find LPI in vgic_get_lpi() Iterating over the LPI linked-list is less than ideal when the desired index is already known. Use the INTID to index the LPI xarray instead. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-3-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 92e4d2fea365..7d17dbc8f5dc 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -55,8 +55,9 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = { */ /* - * Iterate over the VM's list of mapped LPIs to find the one with a - * matching interrupt ID and return a reference to the IRQ structure. + * Index the VM's xarray of mapped LPIs and return a reference to the IRQ + * structure. The caller is expected to call vgic_put_irq() later once it's + * finished with the IRQ. */ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) { @@ -66,20 +67,10 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); - list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { - if (irq->intid != intid) - continue; - - /* - * This increases the refcount, the caller is expected to - * call vgic_put_irq() later once it's finished with the IRQ. - */ + irq = xa_load(&dist->lpi_xa, intid); + if (irq) vgic_get_irq_kref(irq); - goto out_unlock; - } - irq = NULL; -out_unlock: raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); return irq; From 49f0a468a158daa10e730e9050587a6014f8cf87 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:46 +0000 Subject: [PATCH 495/814] KVM: arm64: vgic-v3: Iterate the xarray to find pending LPIs Start walking the LPI xarray to find pending LPIs in preparation for the removal of the LPI linked-list. Note that the 'basic' iterator is chosen here as each iteration needs to drop the xarray read lock (RCU) as reads/writes to guest memory can potentially block. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-4-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-v3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index 9465d3706ab9..4ea3340786b9 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -380,6 +380,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm) struct vgic_irq *irq; gpa_t last_ptr = ~(gpa_t)0; bool vlpi_avail = false; + unsigned long index; int ret = 0; u8 val; @@ -396,7 +397,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm) vlpi_avail = true; } - list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { + xa_for_each(&dist->lpi_xa, index, irq) { int byte_offset, bit_nr; struct kvm_vcpu *vcpu; gpa_t pendbase, ptr; From 2798683b8c8024ceb295389a016acf14e53d725a Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:47 +0000 Subject: [PATCH 496/814] KVM: arm64: vgic-its: Walk the LPI xarray in vgic_copy_lpi_list() Start iterating the LPI xarray in anticipation of removing the LPI linked-list. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-5-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-its.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index fb2d3c356984..b9874dc04608 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -327,6 +327,8 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, return 0; } +#define GIC_LPI_MAX_INTID ((1 << INTERRUPT_ID_BITS_ITS) - 1) + /* * Create a snapshot of the current LPIs targeting @vcpu, so that we can * enumerate those LPIs without holding any lock. @@ -335,6 +337,7 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, int vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr) { struct vgic_dist *dist = &kvm->arch.vgic; + XA_STATE(xas, &dist->lpi_xa, GIC_LPI_OFFSET); struct vgic_irq *irq; unsigned long flags; u32 *intids; @@ -353,7 +356,9 @@ int vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr) return -ENOMEM; raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); - list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { + rcu_read_lock(); + + xas_for_each(&xas, irq, GIC_LPI_MAX_INTID) { if (i == irq_count) break; /* We don't need to "get" the IRQ, as we hold the list lock. */ @@ -361,6 +366,8 @@ int vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr) continue; intids[i++] = irq->intid; } + + rcu_read_unlock(); raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); *intid_ptr = intids; From 9880835af78e05eb8e1f2f330c11840d96f815a3 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:48 +0000 Subject: [PATCH 497/814] KVM: arm64: vgic: Get rid of the LPI linked-list All readers of LPI configuration have been transitioned to use the LPI xarray. Get rid of the linked-list altogether. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-6-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-init.c | 1 - arch/arm64/kvm/vgic/vgic-its.c | 8 ++------ arch/arm64/kvm/vgic/vgic.c | 1 - include/kvm/arm_vgic.h | 2 -- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 411719053107..e25672d6e846 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -53,7 +53,6 @@ void kvm_vgic_early_init(struct kvm *kvm) { struct vgic_dist *dist = &kvm->arch.vgic; - INIT_LIST_HEAD(&dist->lpi_list_head); INIT_LIST_HEAD(&dist->lpi_translation_cache); raw_spin_lock_init(&dist->lpi_list_lock); xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ); diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index b9874dc04608..3d0208162bcd 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -58,7 +58,6 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, return ERR_PTR(ret); } - INIT_LIST_HEAD(&irq->lpi_list); INIT_LIST_HEAD(&irq->ap_list); raw_spin_lock_init(&irq->irq_lock); @@ -74,10 +73,8 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, * There could be a race with another vgic_add_lpi(), so we need to * check that we don't add a second list entry with the same LPI. */ - list_for_each_entry(oldirq, &dist->lpi_list_head, lpi_list) { - if (oldirq->intid != intid) - continue; - + oldirq = xa_load(&dist->lpi_xa, intid); + if (oldirq) { /* Someone was faster with adding this LPI, lets use that. */ kfree(irq); irq = oldirq; @@ -99,7 +96,6 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, goto out_unlock; } - list_add_tail(&irq->lpi_list, &dist->lpi_list_head); dist->lpi_list_count++; out_unlock: diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 7d17dbc8f5dc..6240faab0127 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -122,7 +122,6 @@ void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq) if (!kref_put(&irq->refcount, vgic_irq_release)) return; - list_del(&irq->lpi_list); xa_erase(&dist->lpi_xa, irq->intid); dist->lpi_list_count--; diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 795b35656b54..aeff363e3ba6 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -117,7 +117,6 @@ struct irq_ops { struct vgic_irq { raw_spinlock_t irq_lock; /* Protects the content of the struct */ - struct list_head lpi_list; /* Used to link all LPIs together */ struct list_head ap_list; struct kvm_vcpu *vcpu; /* SGIs and PPIs: The VCPU @@ -277,7 +276,6 @@ struct vgic_dist { /* Protects the lpi_list and the count value below. */ raw_spinlock_t lpi_list_lock; struct xarray lpi_xa; - struct list_head lpi_list_head; int lpi_list_count; /* LPI translation cache */ From 05f4d4f5d462618150a199bf26fd442b54b5d41a Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:49 +0000 Subject: [PATCH 498/814] KVM: arm64: vgic: Use atomics to count LPIs Switch to using atomics for LPI accounting, allowing vgic_irq references to be dropped in parallel. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-7-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-debug.c | 2 +- arch/arm64/kvm/vgic/vgic-its.c | 4 ++-- arch/arm64/kvm/vgic/vgic.c | 2 +- include/kvm/arm_vgic.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c index 85606a531dc3..389025ce7749 100644 --- a/arch/arm64/kvm/vgic/vgic-debug.c +++ b/arch/arm64/kvm/vgic/vgic-debug.c @@ -149,7 +149,7 @@ static void print_dist_state(struct seq_file *s, struct vgic_dist *dist) seq_printf(s, "vgic_model:\t%s\n", v3 ? "GICv3" : "GICv2"); seq_printf(s, "nr_spis:\t%d\n", dist->nr_spis); if (v3) - seq_printf(s, "nr_lpis:\t%d\n", dist->lpi_list_count); + seq_printf(s, "nr_lpis:\t%d\n", atomic_read(&dist->lpi_count)); seq_printf(s, "enabled:\t%d\n", dist->enabled); seq_printf(s, "\n"); diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 3d0208162bcd..0be3c33676c3 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -96,7 +96,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, goto out_unlock; } - dist->lpi_list_count++; + atomic_inc(&dist->lpi_count); out_unlock: raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); @@ -346,7 +346,7 @@ int vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr) * command). If coming from another path (such as enabling LPIs), * we must be careful not to overrun the array. */ - irq_count = READ_ONCE(dist->lpi_list_count); + irq_count = atomic_read(&dist->lpi_count); intids = kmalloc_array(irq_count, sizeof(intids[0]), GFP_KERNEL_ACCOUNT); if (!intids) return -ENOMEM; diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 6240faab0127..15dbd17b3a9e 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -123,7 +123,7 @@ void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq) return; xa_erase(&dist->lpi_xa, irq->intid); - dist->lpi_list_count--; + atomic_dec(&dist->lpi_count); kfree(irq); } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index aeff363e3ba6..71e9d719533b 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -273,10 +273,10 @@ struct vgic_dist { */ u64 propbaser; - /* Protects the lpi_list and the count value below. */ + /* Protects the lpi_list. */ raw_spinlock_t lpi_list_lock; struct xarray lpi_xa; - int lpi_list_count; + atomic_t lpi_count; /* LPI translation cache */ struct list_head lpi_translation_cache; From a5c7f011cb584a4713b3defc533ed55e237210a4 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:50 +0000 Subject: [PATCH 499/814] KVM: arm64: vgic: Free LPI vgic_irq structs in an RCU-safe manner Free the vgic_irq structs in an RCU-safe manner to allow reads of the LPI configuration data to happen in parallel with the release of LPIs. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-8-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic.c | 2 +- include/kvm/arm_vgic.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 15dbd17b3a9e..3fedc58e663a 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -125,7 +125,7 @@ void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq) xa_erase(&dist->lpi_xa, irq->intid); atomic_dec(&dist->lpi_count); - kfree(irq); + kfree_rcu(irq, rcu); } void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 71e9d719533b..47035946648e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -117,6 +117,7 @@ struct irq_ops { struct vgic_irq { raw_spinlock_t irq_lock; /* Protects the content of the struct */ + struct rcu_head rcu; struct list_head ap_list; struct kvm_vcpu *vcpu; /* SGIs and PPIs: The VCPU From 864d4304ec1e67b8235e2aae5d31bdad6dd8aa7c Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:51 +0000 Subject: [PATCH 500/814] KVM: arm64: vgic: Rely on RCU protection in vgic_get_lpi() Stop acquiring the lpi_list_lock in favor of RCU for protecting the read-side critical section in vgic_get_lpi(). In order for this to be safe, we also need to be careful not to take a reference on an irq with a refcount of 0, as it is about to be freed. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-9-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic.c | 9 ++++----- arch/arm64/kvm/vgic/vgic.h | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 3fedc58e663a..76abf3d946fe 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -63,15 +63,14 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) { struct vgic_dist *dist = &kvm->arch.vgic; struct vgic_irq *irq = NULL; - unsigned long flags; - raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); + rcu_read_lock(); irq = xa_load(&dist->lpi_xa, intid); - if (irq) - vgic_get_irq_kref(irq); + if (!vgic_try_get_irq_kref(irq)) + irq = NULL; - raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); + rcu_read_unlock(); return irq; } diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 8d134569d0a1..f874b9932c5a 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -220,12 +220,20 @@ void vgic_v2_vmcr_sync(struct kvm_vcpu *vcpu); void vgic_v2_save_state(struct kvm_vcpu *vcpu); void vgic_v2_restore_state(struct kvm_vcpu *vcpu); +static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq) +{ + if (!irq) + return false; + + if (irq->intid < VGIC_MIN_LPI) + return true; + + return kref_get_unless_zero(&irq->refcount); +} + static inline void vgic_get_irq_kref(struct vgic_irq *irq) { - if (irq->intid < VGIC_MIN_LPI) - return; - - kref_get(&irq->refcount); + WARN_ON_ONCE(!vgic_try_get_irq_kref(irq)); } void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu); From 50ac89bb709275731217f74da8ccef8c99def319 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:52 +0000 Subject: [PATCH 501/814] KVM: arm64: vgic: Ensure the irq refcount is nonzero when taking a ref It will soon be possible for get() and put() calls to happen in parallel, which means in most cases we must ensure the refcount is nonzero when taking a new reference. Switch to using vgic_try_get_irq_kref() where necessary, and document the few conditions where an IRQ's refcount is guaranteed to be nonzero. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-10-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-its.c | 18 ++++++++---------- arch/arm64/kvm/vgic/vgic.c | 3 ++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 0be3c33676c3..dad6f0ee7c49 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -74,18 +74,11 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, * check that we don't add a second list entry with the same LPI. */ oldirq = xa_load(&dist->lpi_xa, intid); - if (oldirq) { + if (vgic_try_get_irq_kref(oldirq)) { /* Someone was faster with adding this LPI, lets use that. */ kfree(irq); irq = oldirq; - /* - * This increases the refcount, the caller is expected to - * call vgic_put_irq() on the returned pointer once it's - * finished with the IRQ. - */ - vgic_get_irq_kref(irq); - goto out_unlock; } @@ -611,8 +604,8 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db, raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); irq = __vgic_its_check_cache(dist, db, devid, eventid); - if (irq) - vgic_get_irq_kref(irq); + if (!vgic_try_get_irq_kref(irq)) + irq = NULL; raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); @@ -658,6 +651,11 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its, if (cte->irq) __vgic_put_lpi_locked(kvm, cte->irq); + /* + * The irq refcount is guaranteed to be nonzero while holding the + * its_lock, as the ITE (and the reference it holds) cannot be freed. + */ + lockdep_assert_held(&its->its_lock); vgic_get_irq_kref(irq); cte->db = db; diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 76abf3d946fe..df9e1aa1956c 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -395,7 +395,8 @@ retry: /* * Grab a reference to the irq to reflect the fact that it is - * now in the ap_list. + * now in the ap_list. This is safe as the caller must already hold a + * reference on the irq. */ vgic_get_irq_kref(irq); list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head); From e27f2d561fee873d415697e6e5e3ec78efc9c259 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 21 Feb 2024 05:42:53 +0000 Subject: [PATCH 502/814] KVM: arm64: vgic: Don't acquire the lpi_list_lock in vgic_put_irq() The LPI xarray's xa_lock is sufficient for synchronizing writers when freeing a given LPI. Furthermore, readers can only take a new reference on an IRQ if it was already nonzero. Stop taking the lpi_list_lock unnecessarily and get rid of __vgic_put_lpi_locked(). Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240221054253.3848076-11-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-its.c | 4 ++-- arch/arm64/kvm/vgic/vgic.c | 28 +++++++++------------------- arch/arm64/kvm/vgic/vgic.h | 1 - 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index dad6f0ee7c49..f6025886071c 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -649,7 +649,7 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its, * was in the cache, and increment it on the new interrupt. */ if (cte->irq) - __vgic_put_lpi_locked(kvm, cte->irq); + vgic_put_irq(kvm, cte->irq); /* * The irq refcount is guaranteed to be nonzero while holding the @@ -686,7 +686,7 @@ void vgic_its_invalidate_cache(struct kvm *kvm) if (!cte->irq) break; - __vgic_put_lpi_locked(kvm, cte->irq); + vgic_put_irq(kvm, cte->irq); cte->irq = NULL; } diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index df9e1aa1956c..f963f410788a 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -111,22 +111,6 @@ static void vgic_irq_release(struct kref *ref) { } -/* - * Drop the refcount on the LPI. Must be called with lpi_list_lock held. - */ -void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq) -{ - struct vgic_dist *dist = &kvm->arch.vgic; - - if (!kref_put(&irq->refcount, vgic_irq_release)) - return; - - xa_erase(&dist->lpi_xa, irq->intid); - atomic_dec(&dist->lpi_count); - - kfree_rcu(irq, rcu); -} - void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) { struct vgic_dist *dist = &kvm->arch.vgic; @@ -135,9 +119,15 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) if (irq->intid < VGIC_MIN_LPI) return; - raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); - __vgic_put_lpi_locked(kvm, irq); - raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); + if (!kref_put(&irq->refcount, vgic_irq_release)) + return; + + xa_lock_irqsave(&dist->lpi_xa, flags); + __xa_erase(&dist->lpi_xa, irq->intid); + xa_unlock_irqrestore(&dist->lpi_xa, flags); + + atomic_dec(&dist->lpi_count); + kfree_rcu(irq, rcu); } void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index f874b9932c5a..0c2b82de8fa3 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -180,7 +180,6 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev, gpa_t addr, int len); struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 intid); -void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq); void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq); bool vgic_get_phys_line_level(struct vgic_irq *irq); void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending); From 2ecd43413d7668d67b9b8a56f882aa1ea12b8a62 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Mon, 12 Feb 2024 13:05:09 +0000 Subject: [PATCH 503/814] Documentation: qat: fix auto_reset section Remove unneeded colon in the auto_reset section. This resolves the following errors when building the documentation: Documentation/ABI/testing/sysfs-driver-qat:146: ERROR: Unexpected indentation. Documentation/ABI/testing/sysfs-driver-qat:146: WARNING: Block quote ends without a blank line; unexpected unindent. Fixes: f5419a4239af ("crypto: qat - add auto reset on error") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-kernel/20240212144830.70495d07@canb.auug.org.au/T/ Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- Documentation/ABI/testing/sysfs-driver-qat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-qat b/Documentation/ABI/testing/sysfs-driver-qat index 6778f1fea874..96020fb051c3 100644 --- a/Documentation/ABI/testing/sysfs-driver-qat +++ b/Documentation/ABI/testing/sysfs-driver-qat @@ -153,7 +153,7 @@ Description: (RW) Reports the current state of the autoreset feature Device auto reset is disabled by default. - The values are:: + The values are: * 1/Yy/on: auto reset enabled. If the device encounters an unrecoverable error, it will be reset automatically. From 53cc9baeb9bc2a187eb9c9790d30995148852b12 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 14:49:46 +0100 Subject: [PATCH 504/814] crypto: arm/sha - fix function cast warnings clang-16 warns about casting between incompatible function types: arch/arm/crypto/sha256_glue.c:37:5: error: cast from 'void (*)(u32 *, const void *, unsigned int)' (aka 'void (*)(unsigned int *, const void *, unsigned int)') to 'sha256_block_fn *' (aka 'void (*)(struct sha256_state *, const unsigned char *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 37 | (sha256_block_fn *)sha256_block_data_order); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arch/arm/crypto/sha512-glue.c:34:3: error: cast from 'void (*)(u64 *, const u8 *, int)' (aka 'void (*)(unsigned long long *, const unsigned char *, int)') to 'sha512_block_fn *' (aka 'void (*)(struct sha512_state *, const unsigned char *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 34 | (sha512_block_fn *)sha512_block_data_order); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix the prototypes for the assembler functions to match the typedef. The code already relies on the digest being the first part of the state structure, so there is no change in behavior. Fixes: c80ae7ca3726 ("crypto: arm/sha512 - accelerated SHA-512 using ARM generic ASM and NEON") Fixes: b59e2ae3690c ("crypto: arm/sha256 - move SHA-224/256 ASM/NEON implementation to base layer") Signed-off-by: Arnd Bergmann Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/sha256_glue.c | 13 +++++-------- arch/arm/crypto/sha512-glue.c | 12 +++++------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/arch/arm/crypto/sha256_glue.c b/arch/arm/crypto/sha256_glue.c index 433ee4ddce6c..f85933fdec75 100644 --- a/arch/arm/crypto/sha256_glue.c +++ b/arch/arm/crypto/sha256_glue.c @@ -24,8 +24,8 @@ #include "sha256_glue.h" -asmlinkage void sha256_block_data_order(u32 *digest, const void *data, - unsigned int num_blks); +asmlinkage void sha256_block_data_order(struct sha256_state *state, + const u8 *data, int num_blks); int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, unsigned int len) @@ -33,23 +33,20 @@ int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, /* make sure casting to sha256_block_fn() is safe */ BUILD_BUG_ON(offsetof(struct sha256_state, state) != 0); - return sha256_base_do_update(desc, data, len, - (sha256_block_fn *)sha256_block_data_order); + return sha256_base_do_update(desc, data, len, sha256_block_data_order); } EXPORT_SYMBOL(crypto_sha256_arm_update); static int crypto_sha256_arm_final(struct shash_desc *desc, u8 *out) { - sha256_base_do_finalize(desc, - (sha256_block_fn *)sha256_block_data_order); + sha256_base_do_finalize(desc, sha256_block_data_order); return sha256_base_finish(desc, out); } int crypto_sha256_arm_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - sha256_base_do_update(desc, data, len, - (sha256_block_fn *)sha256_block_data_order); + sha256_base_do_update(desc, data, len, sha256_block_data_order); return crypto_sha256_arm_final(desc, out); } EXPORT_SYMBOL(crypto_sha256_arm_finup); diff --git a/arch/arm/crypto/sha512-glue.c b/arch/arm/crypto/sha512-glue.c index 0635a65aa488..1be5bd498af3 100644 --- a/arch/arm/crypto/sha512-glue.c +++ b/arch/arm/crypto/sha512-glue.c @@ -25,27 +25,25 @@ MODULE_ALIAS_CRYPTO("sha512"); MODULE_ALIAS_CRYPTO("sha384-arm"); MODULE_ALIAS_CRYPTO("sha512-arm"); -asmlinkage void sha512_block_data_order(u64 *state, u8 const *src, int blocks); +asmlinkage void sha512_block_data_order(struct sha512_state *state, + u8 const *src, int blocks); int sha512_arm_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha512_base_do_update(desc, data, len, - (sha512_block_fn *)sha512_block_data_order); + return sha512_base_do_update(desc, data, len, sha512_block_data_order); } static int sha512_arm_final(struct shash_desc *desc, u8 *out) { - sha512_base_do_finalize(desc, - (sha512_block_fn *)sha512_block_data_order); + sha512_base_do_finalize(desc, sha512_block_data_order); return sha512_base_finish(desc, out); } int sha512_arm_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - sha512_base_do_update(desc, data, len, - (sha512_block_fn *)sha512_block_data_order); + sha512_base_do_update(desc, data, len, sha512_block_data_order); return sha512_arm_final(desc, out); } From 0e8fca2f12ceb77c3a6b6f210135031f264aa612 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 13 Feb 2024 11:34:28 -0600 Subject: [PATCH 505/814] crypto: ccp - Avoid discarding errors in psp_send_platform_access_msg() Errors can potentially occur in the "processing" of PSP commands or commands can be processed successfully but still return an error code in the header. This second case was being discarded because PSP communication worked but the command returned an error code in the payload header. Capture both cases and return them to the caller as -EIO for the caller to investigate. The caller can detect the latter by looking at `req->header->status`. Reported-and-tested-by: Tim Van Patten Fixes: 7ccc4f4e2e50 ("crypto: ccp - Add support for an interface for platform features") Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu --- drivers/crypto/ccp/platform-access.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c index 94367bc49e35..1b8ed3389733 100644 --- a/drivers/crypto/ccp/platform-access.c +++ b/drivers/crypto/ccp/platform-access.c @@ -118,9 +118,16 @@ int psp_send_platform_access_msg(enum psp_platform_access_msg msg, goto unlock; } - /* Store the status in request header for caller to investigate */ + /* + * Read status from PSP. If status is non-zero, it indicates an error + * occurred during "processing" of the command. + * If status is zero, it indicates the command was "processed" + * successfully, but the result of the command is in the payload. + * Return both cases to the caller as -EIO to investigate. + */ cmd_reg = ioread32(cmd); - req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); + if (FIELD_GET(PSP_CMDRESP_STS, cmd_reg)) + req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); if (req->header.status) { ret = -EIO; goto unlock; From 14af865be47ac16ba9f3c98d031dc1f30cb1a642 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 13 Feb 2024 11:34:29 -0600 Subject: [PATCH 506/814] crypto: ccp - Update return values for some unit tests Until authenticated the platform enforces a state machine. Adjust unit tests with this in mind. Correct the return codes for all the states the unit tests ends up hitting: * Set Param / Get Param: DBC_ERROR_BAD_STATE * Set UID: DBC_ERROR_SIGNATURE_INVALID * Authencitated Nonce: DBC_ERROR_BAD_PARAMETERS Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu --- tools/crypto/ccp/test_dbc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/crypto/ccp/test_dbc.py b/tools/crypto/ccp/test_dbc.py index 79de3638a01a..bb0e671be96d 100755 --- a/tools/crypto/ccp/test_dbc.py +++ b/tools/crypto/ccp/test_dbc.py @@ -138,12 +138,14 @@ class TestInvalidSignature(DynamicBoostControlTest): def test_authenticated_nonce(self) -> None: """fetch authenticated nonce""" + get_nonce(self.d, None) with self.assertRaises(OSError) as error: get_nonce(self.d, self.signature) - self.assertEqual(error.exception.errno, 1) + self.assertEqual(error.exception.errno, 22) def test_set_uid(self) -> None: """set uid""" + get_nonce(self.d, None) with self.assertRaises(OSError) as error: set_uid(self.d, self.uid, self.signature) self.assertEqual(error.exception.errno, 1) @@ -152,13 +154,13 @@ class TestInvalidSignature(DynamicBoostControlTest): """fetch a parameter""" with self.assertRaises(OSError) as error: process_param(self.d, PARAM_GET_SOC_PWR_CUR, self.signature) - self.assertEqual(error.exception.errno, 1) + self.assertEqual(error.exception.errno, 11) def test_set_param(self) -> None: """set a parameter""" with self.assertRaises(OSError) as error: process_param(self.d, PARAM_SET_PWR_CAP, self.signature, 1000) - self.assertEqual(error.exception.errno, 1) + self.assertEqual(error.exception.errno, 11) class TestUnFusedSystem(DynamicBoostControlTest): From bcc06e1b3dadc76140203753a08979374c965ada Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 13 Feb 2024 21:09:41 +0300 Subject: [PATCH 507/814] crypto: qat - uninitialized variable in adf_hb_error_inject_write() There are a few issues in this code. If *ppos is non-zero then the first part of the buffer is not initialized. We never initialize the last character of the buffer. The return is not checked so it's possible that none of the buffer is initialized. This is debugfs code which is root only and the impact of these bugs is very small. However, it's still worth fixing. To fix this: 1) Check that *ppos is zero. 2) Use copy_from_user() instead of simple_write_to_buffer(). 3) Explicitly add a NUL terminator. Fixes: e2b67859ab6e ("crypto: qat - add heartbeat error simulator") Signed-off-by: Dan Carpenter Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c index 5cd6c2d6f90a..cccdff24b48d 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c @@ -160,16 +160,17 @@ static ssize_t adf_hb_error_inject_write(struct file *file, size_t count, loff_t *ppos) { struct adf_accel_dev *accel_dev = file->private_data; - size_t written_chars; char buf[3]; int ret; /* last byte left as string termination */ - if (count != 2) + if (*ppos != 0 || count != 2) return -EINVAL; - written_chars = simple_write_to_buffer(buf, sizeof(buf) - 1, - ppos, user_buf, count); + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + buf[count] = '\0'; + if (buf[0] != '1') return -EINVAL; @@ -183,7 +184,7 @@ static ssize_t adf_hb_error_inject_write(struct file *file, dev_info(&GET_DEV(accel_dev), "Heartbeat error injection enabled\n"); - return written_chars; + return count; } static const struct file_operations adf_hb_error_inject_fops = { From dfff0e35fa5dd84ae75052ba129b0219d83e46dc Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:19:55 +0000 Subject: [PATCH 508/814] crypto: qat - remove unused macros in qat_comp_alg.c As a result of the removal of qat_zlib_deflate, some defines where not removed. Remove them. This is to fix the following warning when compiling the QAT driver using the clang compiler with CC=clang W=2: drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:21:9: warning: macro is not used [-Wunused-macros] 21 | #define QAT_RFC_1950_CM_OFFSET 4 | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:16:9: warning: macro is not used [-Wunused-macros] 16 | #define QAT_RFC_1950_HDR_SIZE 2 | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:17:9: warning: macro is not used [-Wunused-macros] 17 | #define QAT_RFC_1950_FOOTER_SIZE 4 | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:22:9: warning: macro is not used [-Wunused-macros] 22 | #define QAT_RFC_1950_DICT_MASK 0x20 | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:18:9: warning: macro is not used [-Wunused-macros] 18 | #define QAT_RFC_1950_CM_DEFLATE 8 | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:20:9: warning: macro is not used [-Wunused-macros] 20 | #define QAT_RFC_1950_CM_MASK 0x0f | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:23:9: warning: macro is not used [-Wunused-macros] 23 | #define QAT_RFC_1950_COMP_HDR 0x785e | ^ drivers/crypto/intel/qat/qat_common/qat_comp_algs.c:19:9: warning: macro is not used [-Wunused-macros] 19 | #define QAT_RFC_1950_CM_DEFLATE_CINFO_32K 7 | ^ Fixes: e9dd20e0e5f6 ("crypto: qat - Remove zlib-deflate") Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/qat_comp_algs.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c index bf8c0ee62917..2ba4aa22e092 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c @@ -13,15 +13,6 @@ #include "qat_compression.h" #include "qat_algs_send.h" -#define QAT_RFC_1950_HDR_SIZE 2 -#define QAT_RFC_1950_FOOTER_SIZE 4 -#define QAT_RFC_1950_CM_DEFLATE 8 -#define QAT_RFC_1950_CM_DEFLATE_CINFO_32K 7 -#define QAT_RFC_1950_CM_MASK 0x0f -#define QAT_RFC_1950_CM_OFFSET 4 -#define QAT_RFC_1950_DICT_MASK 0x20 -#define QAT_RFC_1950_COMP_HDR 0x785e - static DEFINE_MUTEX(algs_lock); static unsigned int active_devs; From 9a5dcada14d5e027856a1bc38443e54111438da6 Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:19:56 +0000 Subject: [PATCH 509/814] crypto: qat - removed unused macro in adf_cnv_dbgfs.c This macro was added but never used, remove it. This is to fix the following warning when compiling the QAT driver using the clang compiler with CC=clang W=2: drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c:19:9: warning: macro is not used [-Wunused-macros] 19 | #define CNV_SLICE_ERR_MASK GENMASK(7, 0) | ^ Fixes: d807f0240c71 ("crypto: qat - add cnv_errors debugfs file") Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c index 07119c487da0..627953a72d47 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c @@ -16,7 +16,6 @@ #define CNV_ERR_INFO_MASK GENMASK(11, 0) #define CNV_ERR_TYPE_MASK GENMASK(15, 12) -#define CNV_SLICE_ERR_MASK GENMASK(7, 0) #define CNV_SLICE_ERR_SIGN_BIT_INDEX 7 #define CNV_DELTA_ERR_SIGN_BIT_INDEX 11 From f99fb7d660f7c818105803f1f1915396a14d18ad Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:19:57 +0000 Subject: [PATCH 510/814] crypto: qat - avoid division by zero Check if delta_us is not zero and return -EINVAL if it is. delta_us is unlikely to be zero as there is a sleep between the reads of the two timestamps. This is to fix the following warning when compiling the QAT driver using clang scan-build: drivers/crypto/intel/qat/qat_common/adf_clock.c:87:9: warning: Division by zero [core.DivideZero] 87 | temp = DIV_ROUND_CLOSEST_ULL(temp, delta_us); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fixes: e2980ba57e79 ("crypto: qat - add measure clock frequency") Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_clock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_clock.c b/drivers/crypto/intel/qat/qat_common/adf_clock.c index 01e0a389e462..cf89f57de2a7 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_clock.c +++ b/drivers/crypto/intel/qat/qat_common/adf_clock.c @@ -83,6 +83,9 @@ static int measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency) } delta_us = timespec_to_us(&ts3) - timespec_to_us(&ts1); + if (!delta_us) + return -EINVAL; + temp = (timestamp2 - timestamp1) * ME_CLK_DIVIDER * 10; temp = DIV_ROUND_CLOSEST_ULL(temp, delta_us); /* From a66cf93ab33853f17b8cc33a99263dd0a383a1a1 Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:19:58 +0000 Subject: [PATCH 511/814] crypto: qat - remove double initialization of value Remove double initialization of the reg variable. This is to fix the following warning when compiling the QAT driver using clang scan-build: drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c:1010:6: warning: Value stored to 'reg' during its initialization is never read [deadcode.DeadStores] 1010 | u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SSMCPPERR); | ^~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c:1109:6: warning: Value stored to 'reg' during its initialization is never read [deadcode.DeadStores] 1109 | u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SER_ERR_SSMSH); | ^~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fixes: 99b1c9826e48 ("crypto: qat - count QAT GEN4 errors") Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c index 048c24607939..2dd3772bf58a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c @@ -1007,8 +1007,7 @@ static bool adf_handle_spppar_err(struct adf_accel_dev *accel_dev, static bool adf_handle_ssmcpppar_err(struct adf_accel_dev *accel_dev, void __iomem *csr, u32 iastatssm) { - u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SSMCPPERR); - u32 bits_num = BITS_PER_REG(reg); + u32 reg, bits_num = BITS_PER_REG(reg); bool reset_required = false; unsigned long errs_bits; u32 bit_iterator; @@ -1106,8 +1105,7 @@ static bool adf_handle_rf_parr_err(struct adf_accel_dev *accel_dev, static bool adf_handle_ser_err_ssmsh(struct adf_accel_dev *accel_dev, void __iomem *csr, u32 iastatssm) { - u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SER_ERR_SSMSH); - u32 bits_num = BITS_PER_REG(reg); + u32 reg, bits_num = BITS_PER_REG(reg); bool reset_required = false; unsigned long errs_bits; u32 bit_iterator; From ff391345141e727320ca906e6928c6a1f14e7e37 Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:19:59 +0000 Subject: [PATCH 512/814] crypto: qat - remove unnecessary description from comment Remove extra description from comments as it is not required. This is to fix the following warning when compiling the QAT driver using the clang compiler with CC=clang W=2: drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c:65: warning: contents before sections drivers/crypto/intel/qat/qat_common/adf_isr.c:380: warning: contents before sections drivers/crypto/intel/qat/qat_common/adf_vf_isr.c:298: warning: contents before sections Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c | 4 ++-- drivers/crypto/intel/qat/qat_common/adf_isr.c | 2 -- drivers/crypto/intel/qat/qat_common/adf_vf_isr.c | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c index 86ee36feefad..f07b748795f7 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c @@ -60,10 +60,10 @@ static int adf_get_vf_real_id(u32 fake) /** * adf_clean_vf_map() - Cleans VF id mapings - * - * Function cleans internal ids for virtual functions. * @vf: flag indicating whether mappings is cleaned * for vfs only or for vfs and pfs + * + * Function cleans internal ids for virtual functions. */ void adf_clean_vf_map(bool vf) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c index 020d213f4c99..cae1aee5479a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c @@ -380,8 +380,6 @@ EXPORT_SYMBOL_GPL(adf_isr_resource_alloc); /** * adf_init_misc_wq() - Init misc workqueue * - * Function init workqueue 'qat_misc_wq' for general purpose. - * * Return: 0 on success, error code otherwise. */ int __init adf_init_misc_wq(void) diff --git a/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c index b05c3957a160..cdbb2d687b1b 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c @@ -293,8 +293,6 @@ EXPORT_SYMBOL_GPL(adf_flush_vf_wq); /** * adf_init_vf_wq() - Init workqueue for VF * - * Function init workqueue 'adf_vf_stop_wq' for VF. - * * Return: 0 on success, error code otherwise. */ int __init adf_init_vf_wq(void) From bca79b9f5639b2fd4692904bce696291336e0246 Mon Sep 17 00:00:00 2001 From: Adam Guerin Date: Fri, 16 Feb 2024 15:20:00 +0000 Subject: [PATCH 513/814] crypto: qat - fix comment structure Move comment description to the same line as the function name. This is to fix the following warning when compiling the QAT driver using the clang compiler with CC=clang W=2: drivers/crypto/intel/qat/qat_common/qat_crypto.c:108: warning: missing initial short description on line: * qat_crypto_vf_dev_config() Signed-off-by: Adam Guerin Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/qat_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/qat_crypto.c b/drivers/crypto/intel/qat/qat_common/qat_crypto.c index 40c8e74d1cf9..101c6ea41673 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/intel/qat/qat_common/qat_crypto.c @@ -105,8 +105,8 @@ struct qat_crypto_instance *qat_crypto_get_instance_node(int node) } /** - * qat_crypto_vf_dev_config() - * create dev config required to create crypto inst. + * qat_crypto_vf_dev_config() - create dev config required to create + * crypto inst. * * @accel_dev: Pointer to acceleration device. * From df018f82002a8b4dc407bc9a6f416b9241d14415 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 16 Feb 2024 18:21:54 +0100 Subject: [PATCH 514/814] crypto: qat - fix ring to service map for dcc in 4xxx If a device is configured for data compression chaining (dcc), half of the engines are loaded with the symmetric crypto image and the rest are loaded with the compression image. However, in such configuration all rings can handle compression requests. Fix the ring to service mapping so that when a device is configured for dcc, the ring to service mapping reports that all rings in a bank can be used for compression. Fixes: a238487f7965 ("crypto: qat - fix ring to service map for QAT GEN4") Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c index 94a0ebb03d8c..e171cddf6f02 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -331,6 +331,13 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) if (!fw_config) return 0; + /* If dcc, all rings handle compression requests */ + if (adf_get_service_enabled(accel_dev) == SVC_DCC) { + for (i = 0; i < RP_GROUP_COUNT; i++) + rps[i] = COMP; + goto set_mask; + } + for (i = 0; i < RP_GROUP_COUNT; i++) { switch (fw_config[i].ae_mask) { case ADF_AE_GROUP_0: @@ -359,6 +366,7 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) } } +set_mask: ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | From a20a6060e0dd57fecaf55487985aef28bd08c6bf Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 16 Feb 2024 18:21:55 +0100 Subject: [PATCH 515/814] crypto: qat - fix ring to service map for dcc in 420xx If a device is configured for data compression chaining (dcc), half of the engines are loaded with the symmetric crypto image and the rest are loaded with the compression image. However, in such configuration all rings can handle compression requests. Fix the ring to service mapping so that when a device is configured for dcc, the ring to service mapping reports that all rings in a bank can be used for compression. Fixes: fcf60f4bcf54 ("crypto: qat - add support for 420xx devices") Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c index a87d29ae724f..7909b51e97c3 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c @@ -372,6 +372,13 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) if (!fw_config) return 0; + /* If dcc, all rings handle compression requests */ + if (adf_get_service_enabled(accel_dev) == SVC_DCC) { + for (i = 0; i < RP_GROUP_COUNT; i++) + rps[i] = COMP; + goto set_mask; + } + for (i = 0; i < RP_GROUP_COUNT; i++) { switch (fw_config[i].ae_mask) { case ADF_AE_GROUP_0: @@ -400,6 +407,7 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) } } +set_mask: ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | From ed3d95fe788dec7c23bb20b41f8af47cbce04715 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Fri, 16 Feb 2024 18:21:56 +0100 Subject: [PATCH 516/814] crypto: qat - make ring to service map common for QAT GEN4 The function get_ring_to_svc_map() is present in both 420xx and 4xxx drivers. Rework the logic to make it generic to GEN4 devices and move it to qat_common/adf_gen4_hw_data.c. Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../intel/qat/qat_420xx/adf_420xx_hw_data.c | 72 +++++-------------- .../intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 72 +++++-------------- .../intel/qat/qat_common/adf_accel_devices.h | 1 + .../intel/qat/qat_common/adf_gen4_hw_data.c | 56 +++++++++++++++ .../intel/qat/qat_common/adf_gen4_hw_data.h | 1 + 5 files changed, 90 insertions(+), 112 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c index 7909b51e97c3..1102c47f8293 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c @@ -361,61 +361,6 @@ static u32 get_ena_thd_mask(struct adf_accel_dev *accel_dev, u32 obj_num) } } -static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) -{ - enum adf_cfg_service_type rps[RP_GROUP_COUNT] = { }; - const struct adf_fw_config *fw_config; - u16 ring_to_svc_map; - int i, j; - - fw_config = get_fw_config(accel_dev); - if (!fw_config) - return 0; - - /* If dcc, all rings handle compression requests */ - if (adf_get_service_enabled(accel_dev) == SVC_DCC) { - for (i = 0; i < RP_GROUP_COUNT; i++) - rps[i] = COMP; - goto set_mask; - } - - for (i = 0; i < RP_GROUP_COUNT; i++) { - switch (fw_config[i].ae_mask) { - case ADF_AE_GROUP_0: - j = RP_GROUP_0; - break; - case ADF_AE_GROUP_1: - j = RP_GROUP_1; - break; - default: - return 0; - } - - switch (fw_config[i].obj) { - case ADF_FW_SYM_OBJ: - rps[j] = SYM; - break; - case ADF_FW_ASYM_OBJ: - rps[j] = ASYM; - break; - case ADF_FW_DC_OBJ: - rps[j] = COMP; - break; - default: - rps[j] = 0; - break; - } - } - -set_mask: - ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | - rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | - rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | - rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_3_SHIFT; - - return ring_to_svc_map; -} - static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, const char * const fw_objs[], int num_objs) { @@ -441,6 +386,20 @@ static const char *uof_get_name_420xx(struct adf_accel_dev *accel_dev, u32 obj_n return uof_get_name(accel_dev, obj_num, adf_420xx_fw_objs, num_fw_objs); } +static int uof_get_obj_type(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + if (obj_num >= uof_get_num_objs(accel_dev)) + return -EINVAL; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return -EINVAL; + + return fw_config[obj_num].obj; +} + static u32 uof_get_ae_mask(struct adf_accel_dev *accel_dev, u32 obj_num) { const struct adf_fw_config *fw_config; @@ -504,12 +463,13 @@ void adf_init_hw_data_420xx(struct adf_hw_device_data *hw_data, u32 dev_id) hw_data->fw_mmp_name = ADF_420XX_MMP; hw_data->uof_get_name = uof_get_name_420xx; hw_data->uof_get_num_objs = uof_get_num_objs; + hw_data->uof_get_obj_type = uof_get_obj_type; hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->get_rp_group = get_rp_group; hw_data->get_ena_thd_mask = get_ena_thd_mask; hw_data->set_msix_rttable = adf_gen4_set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; - hw_data->get_ring_to_svc_map = get_ring_to_svc_map; + hw_data->get_ring_to_svc_map = adf_gen4_get_ring_to_svc_map; hw_data->disable_iov = adf_disable_sriov; hw_data->ring_pair_reset = adf_gen4_ring_pair_reset; hw_data->enable_pm = adf_gen4_enable_pm; diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c index e171cddf6f02..927506cf271d 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -320,61 +320,6 @@ static u32 get_ena_thd_mask_401xx(struct adf_accel_dev *accel_dev, u32 obj_num) } } -static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) -{ - enum adf_cfg_service_type rps[RP_GROUP_COUNT]; - const struct adf_fw_config *fw_config; - u16 ring_to_svc_map; - int i, j; - - fw_config = get_fw_config(accel_dev); - if (!fw_config) - return 0; - - /* If dcc, all rings handle compression requests */ - if (adf_get_service_enabled(accel_dev) == SVC_DCC) { - for (i = 0; i < RP_GROUP_COUNT; i++) - rps[i] = COMP; - goto set_mask; - } - - for (i = 0; i < RP_GROUP_COUNT; i++) { - switch (fw_config[i].ae_mask) { - case ADF_AE_GROUP_0: - j = RP_GROUP_0; - break; - case ADF_AE_GROUP_1: - j = RP_GROUP_1; - break; - default: - return 0; - } - - switch (fw_config[i].obj) { - case ADF_FW_SYM_OBJ: - rps[j] = SYM; - break; - case ADF_FW_ASYM_OBJ: - rps[j] = ASYM; - break; - case ADF_FW_DC_OBJ: - rps[j] = COMP; - break; - default: - rps[j] = 0; - break; - } - } - -set_mask: - ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | - rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | - rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | - rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_3_SHIFT; - - return ring_to_svc_map; -} - static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, const char * const fw_objs[], int num_objs) { @@ -407,6 +352,20 @@ static const char *uof_get_name_402xx(struct adf_accel_dev *accel_dev, u32 obj_n return uof_get_name(accel_dev, obj_num, adf_402xx_fw_objs, num_fw_objs); } +static int uof_get_obj_type(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + if (obj_num >= uof_get_num_objs(accel_dev)) + return -EINVAL; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return -EINVAL; + + return fw_config[obj_num].obj; +} + static u32 uof_get_ae_mask(struct adf_accel_dev *accel_dev, u32 obj_num) { const struct adf_fw_config *fw_config; @@ -487,11 +446,12 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) break; } hw_data->uof_get_num_objs = uof_get_num_objs; + hw_data->uof_get_obj_type = uof_get_obj_type; hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->get_rp_group = get_rp_group; hw_data->set_msix_rttable = adf_gen4_set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; - hw_data->get_ring_to_svc_map = get_ring_to_svc_map; + hw_data->get_ring_to_svc_map = adf_gen4_get_ring_to_svc_map; hw_data->disable_iov = adf_disable_sriov; hw_data->ring_pair_reset = adf_gen4_ring_pair_reset; hw_data->enable_pm = adf_gen4_enable_pm; diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index 0f26aa976c8c..08658c3a01e9 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -248,6 +248,7 @@ struct adf_hw_device_data { void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); const char *(*uof_get_name)(struct adf_accel_dev *accel_dev, u32 obj_num); u32 (*uof_get_num_objs)(struct adf_accel_dev *accel_dev); + int (*uof_get_obj_type)(struct adf_accel_dev *accel_dev, u32 obj_num); u32 (*uof_get_ae_mask)(struct adf_accel_dev *accel_dev, u32 obj_num); int (*get_rp_group)(struct adf_accel_dev *accel_dev, u32 ae_mask); u32 (*get_ena_thd_mask)(struct adf_accel_dev *accel_dev, u32 obj_num); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c index f752653ccb47..d28e1921940a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c @@ -4,6 +4,7 @@ #include "adf_accel_devices.h" #include "adf_cfg_services.h" #include "adf_common_drv.h" +#include "adf_fw_config.h" #include "adf_gen4_hw_data.h" #include "adf_gen4_pm.h" @@ -433,3 +434,58 @@ int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev) return 0; } EXPORT_SYMBOL_GPL(adf_gen4_init_thd2arb_map); + +u16 adf_gen4_get_ring_to_svc_map(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + enum adf_cfg_service_type rps[RP_GROUP_COUNT] = { }; + unsigned int ae_mask, start_id, worker_obj_cnt, i; + u16 ring_to_svc_map; + int rp_group; + + if (!hw_data->get_rp_group || !hw_data->uof_get_ae_mask || + !hw_data->uof_get_obj_type || !hw_data->uof_get_num_objs) + return 0; + + /* If dcc, all rings handle compression requests */ + if (adf_get_service_enabled(accel_dev) == SVC_DCC) { + for (i = 0; i < RP_GROUP_COUNT; i++) + rps[i] = COMP; + goto set_mask; + } + + worker_obj_cnt = hw_data->uof_get_num_objs(accel_dev) - + ADF_GEN4_ADMIN_ACCELENGINES; + start_id = worker_obj_cnt - RP_GROUP_COUNT; + + for (i = start_id; i < worker_obj_cnt; i++) { + ae_mask = hw_data->uof_get_ae_mask(accel_dev, i); + rp_group = hw_data->get_rp_group(accel_dev, ae_mask); + if (rp_group >= RP_GROUP_COUNT || rp_group < RP_GROUP_0) + return 0; + + switch (hw_data->uof_get_obj_type(accel_dev, i)) { + case ADF_FW_SYM_OBJ: + rps[rp_group] = SYM; + break; + case ADF_FW_ASYM_OBJ: + rps[rp_group] = ASYM; + break; + case ADF_FW_DC_OBJ: + rps[rp_group] = COMP; + break; + default: + rps[rp_group] = 0; + break; + } + } + +set_mask: + ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | + rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_3_SHIFT; + + return ring_to_svc_map; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_ring_to_svc_map); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h index 7d8a774cadc8..c6e80df5a85a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h @@ -235,5 +235,6 @@ int adf_gen4_ring_pair_reset(struct adf_accel_dev *accel_dev, u32 bank_number); void adf_gen4_set_msix_default_rttable(struct adf_accel_dev *accel_dev); void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev); +u16 adf_gen4_get_ring_to_svc_map(struct adf_accel_dev *accel_dev); #endif From e63df1ec9a16dd9e13e9068243e64876de06f795 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 17 Feb 2024 08:55:13 -0800 Subject: [PATCH 517/814] crypto: jitter - fix CRYPTO_JITTERENTROPY help text Correct various small problems in the help text: a. change 2 spaces to ", " b. finish an incomplete sentence c. change non-working URL to working URL Fixes: a9a98d49da52 ("crypto: Kconfig - simplify compression/RNG entries") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218458 Signed-off-by: Randy Dunlap Cc: Bagas Sanjaya Cc: Robert Elliott Cc: Christoph Biedl Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Acked-by: Bagas Sanjaya Signed-off-by: Herbert Xu --- crypto/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 7d156c75f15f..44661c2e30ca 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1269,10 +1269,11 @@ config CRYPTO_JITTERENTROPY A non-physical non-deterministic ("true") RNG (e.g., an entropy source compliant with NIST SP800-90B) intended to provide a seed to a - deterministic RNG (e.g. per NIST SP800-90C). + deterministic RNG (e.g., per NIST SP800-90C). This RNG does not perform any cryptographic whitening of the generated + random numbers. - See https://www.chronox.de/jent.html + See https://www.chronox.de/jent/ if CRYPTO_JITTERENTROPY if CRYPTO_FIPS && EXPERT From a24e3b583ea2db3418f0c6ae1f12b07ca96531cc Mon Sep 17 00:00:00 2001 From: Kilian Zinnecker Date: Sun, 18 Feb 2024 23:16:58 +0100 Subject: [PATCH 518/814] crypto: rockchip - fix to check return value crypto_engine_alloc_init may fail, e.g., as result of a fail of devm_kzalloc or kthread_create_worker. Other drivers (e.g., amlogic-gxl-core.c, aspeed-acry.c, aspeed-hace.c, jr.c, etc.) check crypto_engine_alloc_init's return value and return -ENOMEM in case a NULL pointer is returned. This patch inserts a corresponding return value check to rk3288_crypto.c. Signed-off-by: Kilian Zinnecker Signed-off-by: Herbert Xu --- drivers/crypto/rockchip/rk3288_crypto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c index 70edf40bc523..f74b3c81ba6d 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.c +++ b/drivers/crypto/rockchip/rk3288_crypto.c @@ -371,6 +371,11 @@ static int rk_crypto_probe(struct platform_device *pdev) } crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); + if (!crypto_info->engine) { + err = -ENOMEM; + goto err_crypto; + } + crypto_engine_start(crypto_info->engine); init_completion(&crypto_info->complete); From 75841d89f3ed51ba1ee5fd341488fe1f55f4eb06 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 3 Jan 2024 17:16:02 -0600 Subject: [PATCH 519/814] KVM: arm64: Fix typos Fix typos, most reported by "codespell arch/arm64". Only touches comments, no code changes. Signed-off-by: Bjorn Helgaas Cc: James Morse Cc: Suzuki K Poulose Cc: Zenghui Yu Cc: Catalin Marinas Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: kvmarm@lists.linux.dev Reviewed-by: Zenghui Yu Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20240103231605.1801364-6-helgaas@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_hyp.h | 2 +- arch/arm64/kvm/arch_timer.c | 2 +- arch/arm64/kvm/fpsimd.c | 2 +- arch/arm64/kvm/hyp/nvhe/host.S | 2 +- arch/arm64/kvm/hyp/nvhe/mm.c | 4 ++-- arch/arm64/kvm/inject_fault.c | 2 +- arch/arm64/kvm/vgic/vgic-init.c | 2 +- arch/arm64/kvm/vgic/vgic-its.c | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 145ce73fc16c..3e2a1ac0c9bb 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -70,7 +70,7 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); /* * Without an __arch_swab32(), we fall back to ___constant_swab32(), but the * static inline can allow the compiler to out-of-line this. KVM always wants - * the macro version as its always inlined. + * the macro version as it's always inlined. */ #define __kvm_swab32(x) ___constant_swab32(x) diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 9dec8c419bf4..879982b1cc73 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -745,7 +745,7 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu, WARN_ON_ONCE(ret); /* - * The virtual offset behaviour is "interresting", as it + * The virtual offset behaviour is "interesting", as it * always applies when HCR_EL2.E2H==0, but only when * accessed from EL1 when HCR_EL2.E2H==1. So make sure we * track E2H when putting the HV timer in "direct" mode. diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index 8c1d0d4853df..571cf6eef1e1 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -117,7 +117,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) } /* - * Called just before entering the guest once we are no longer preemptable + * Called just before entering the guest once we are no longer preemptible * and interrupts are disabled. If we have managed to run anything using * FP while we were preemptible (such as off the back of an interrupt), * then neither the host nor the guest own the FP hardware (and it was the diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S index 7693a6757cd7..135cfb294ee5 100644 --- a/arch/arm64/kvm/hyp/nvhe/host.S +++ b/arch/arm64/kvm/hyp/nvhe/host.S @@ -110,7 +110,7 @@ SYM_FUNC_END(__host_enter) * u64 elr, u64 par); */ SYM_FUNC_START(__hyp_do_panic) - /* Prepare and exit to the host's panic funciton. */ + /* Prepare and exit to the host's panic function. */ mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ PSR_MODE_EL1h) msr spsr_el2, lr diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index b01a3d1078a8..8850b591d775 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -155,7 +155,7 @@ int hyp_back_vmemmap(phys_addr_t back) start = hyp_memory[i].base; start = ALIGN_DOWN((u64)hyp_phys_to_page(start), PAGE_SIZE); /* - * The begining of the hyp_vmemmap region for the current + * The beginning of the hyp_vmemmap region for the current * memblock may already be backed by the page backing the end * the previous region, so avoid mapping it twice. */ @@ -408,7 +408,7 @@ static void *admit_host_page(void *arg) return pop_hyp_memcache(host_mc, hyp_phys_to_virt); } -/* Refill our local memcache by poping pages from the one provided by the host. */ +/* Refill our local memcache by popping pages from the one provided by the host. */ int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, struct kvm_hyp_memcache *host_mc) { diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 0bd93a5f21ce..a640e839848e 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -134,7 +134,7 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr) if (vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE) { fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE; } else { - /* no need to shuffle FS[4] into DFSR[10] as its 0 */ + /* no need to shuffle FS[4] into DFSR[10] as it's 0 */ fsr = DFSR_FSC_EXTABT_nLPAE; } diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index e949e1d0fd9f..df51157420e8 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -309,7 +309,7 @@ int vgic_init(struct kvm *kvm) vgic_lpi_translation_cache_init(kvm); /* - * If we have GICv4.1 enabled, unconditionnaly request enable the + * If we have GICv4.1 enabled, unconditionally request enable the * v4 support so that we get HW-accelerated vSGIs. Otherwise, only * enable it if we present a virtual ITS to the guest. */ diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index e2764d0ffa9f..c734180a5bcf 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -1342,8 +1342,8 @@ static int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its, } /** - * vgic_its_invall - invalidate all LPIs targetting a given vcpu - * @vcpu: the vcpu for which the RD is targetted by an invalidation + * vgic_its_invall - invalidate all LPIs targeting a given vcpu + * @vcpu: the vcpu for which the RD is targeted by an invalidation * * Contrary to the INVALL command, this targets a RD instead of a * collection, and we don't need to hold the its_lock, since no ITS is From c034ec84e8795cf379bd47cc8871445f070a0110 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Sat, 24 Feb 2024 20:35:43 +0530 Subject: [PATCH 520/814] KVM: arm64: Introduce new flag for non-cacheable IO memory Currently, KVM for ARM64 maps at stage 2 memory that is considered device (i.e. it is not RAM) with DEVICE_nGnRE memory attributes; this setting overrides (as per the ARM architecture [1]) any device MMIO mapping present at stage 1, resulting in a set-up whereby a guest operating system cannot determine device MMIO mapping memory attributes on its own but it is always overridden by the KVM stage 2 default. This set-up does not allow guest operating systems to select device memory attributes independently from KVM stage-2 mappings (refer to [1], "Combining stage 1 and stage 2 memory type attributes"), which turns out to be an issue in that guest operating systems (e.g. Linux) may request to map devices MMIO regions with memory attributes that guarantee better performance (e.g. gathering attribute - that for some devices can generate larger PCIe memory writes TLPs) and specific operations (e.g. unaligned transactions) such as the NormalNC memory type. The default device stage 2 mapping was chosen in KVM for ARM64 since it was considered safer (i.e. it would not allow guests to trigger uncontained failures ultimately crashing the machine) but this turned out to be asynchronous (SError) defeating the purpose. Failures containability is a property of the platform and is independent from the memory type used for MMIO device memory mappings. Actually, DEVICE_nGnRE memory type is even more problematic than Normal-NC memory type in terms of faults containability in that e.g. aborts triggered on DEVICE_nGnRE loads cannot be made, architecturally, synchronous (i.e. that would imply that the processor should issue at most 1 load transaction at a time - it cannot pipeline them - otherwise the synchronous abort semantics would break the no-speculation attribute attached to DEVICE_XXX memory). This means that regardless of the combined stage1+stage2 mappings a platform is safe if and only if device transactions cannot trigger uncontained failures and that in turn relies on platform capabilities and the device type being assigned (i.e. PCIe AER/DPC error containment and RAS architecture[3]); therefore the default KVM device stage 2 memory attributes play no role in making device assignment safer for a given platform (if the platform design adheres to design guidelines outlined in [3]) and therefore can be relaxed. For all these reasons, relax the KVM stage 2 device memory attributes from DEVICE_nGnRE to Normal-NC. The NormalNC was chosen over a different Normal memory type default at stage-2 (e.g. Normal Write-through) to avoid cache allocation/snooping. Relaxing S2 KVM device MMIO mappings to Normal-NC is not expected to trigger any issue on guest device reclaim use cases either (i.e. device MMIO unmap followed by a device reset) at least for PCIe devices, in that in PCIe a device reset is architected and carried out through PCI config space transactions that are naturally ordered with respect to MMIO transactions according to the PCI ordering rules. Having Normal-NC S2 default puts guests in control (thanks to stage1+stage2 combined memory attributes rules [1]) of device MMIO regions memory mappings, according to the rules described in [1] and summarized here ([(S1) - stage1], [(S2) - stage 2]): S1 | S2 | Result NORMAL-WB | NORMAL-NC | NORMAL-NC NORMAL-WT | NORMAL-NC | NORMAL-NC NORMAL-NC | NORMAL-NC | NORMAL-NC DEVICE | NORMAL-NC | DEVICE It is worth noting that currently, to map devices MMIO space to user space in a device pass-through use case the VFIO framework applies memory attributes derived from pgprot_noncached() settings applied to VMAs, which result in device-nGnRnE memory attributes for the stage-1 VMM mappings. This means that a userspace mapping for device MMIO space carried out with the current VFIO framework and a guest OS mapping for the same MMIO space may result in a mismatched alias as described in [2]. Defaulting KVM device stage-2 mappings to Normal-NC attributes does not change anything in this respect, in that the mismatched aliases would only affect (refer to [2] for a detailed explanation) ordering between the userspace and GuestOS mappings resulting stream of transactions (i.e. it does not cause loss of property for either stream of transactions on its own), which is harmless given that the userspace and GuestOS access to the device is carried out through independent transactions streams. A Normal-NC flag is not present today. So add a new kvm_pgtable_prot (KVM_PGTABLE_PROT_NORMAL_NC) flag for it, along with its corresponding PTE value 0x5 (0b101) determined from [1]. Lastly, adapt the stage2 PTE property setter function (stage2_set_prot_attr) to handle the NormalNC attribute. The entire discussion leading to this patch series may be followed through the following links. Link: https://lore.kernel.org/all/20230907181459.18145-3-ankita@nvidia.com Link: https://lore.kernel.org/r/20231205033015.10044-1-ankita@nvidia.com [1] section D8.5.5 - DDI0487J_a_a-profile_architecture_reference_manual.pdf [2] section B2.8 - DDI0487J_a_a-profile_architecture_reference_manual.pdf [3] sections 1.7.7.3/1.8.5.2/appendix C - DEN0029H_SBSA_7.1.pdf Suggested-by: Jason Gunthorpe Acked-by: Catalin Marinas Acked-by: Will Deacon Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240224150546.368-2-ankita@nvidia.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_pgtable.h | 2 ++ arch/arm64/include/asm/memory.h | 2 ++ arch/arm64/kvm/hyp/pgtable.c | 24 +++++++++++++++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index cfdf40f734b1..19278dfe7978 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -197,6 +197,7 @@ enum kvm_pgtable_stage2_flags { * @KVM_PGTABLE_PROT_W: Write permission. * @KVM_PGTABLE_PROT_R: Read permission. * @KVM_PGTABLE_PROT_DEVICE: Device attributes. + * @KVM_PGTABLE_PROT_NORMAL_NC: Normal noncacheable attributes. * @KVM_PGTABLE_PROT_SW0: Software bit 0. * @KVM_PGTABLE_PROT_SW1: Software bit 1. * @KVM_PGTABLE_PROT_SW2: Software bit 2. @@ -208,6 +209,7 @@ enum kvm_pgtable_prot { KVM_PGTABLE_PROT_R = BIT(2), KVM_PGTABLE_PROT_DEVICE = BIT(3), + KVM_PGTABLE_PROT_NORMAL_NC = BIT(4), KVM_PGTABLE_PROT_SW0 = BIT(55), KVM_PGTABLE_PROT_SW1 = BIT(56), diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index d82305ab420f..449ca2ff1df6 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -173,6 +173,7 @@ * Memory types for Stage-2 translation */ #define MT_S2_NORMAL 0xf +#define MT_S2_NORMAL_NC 0x5 #define MT_S2_DEVICE_nGnRE 0x1 /* @@ -180,6 +181,7 @@ * Stage-2 enforces Normal-WB and Device-nGnRE */ #define MT_S2_FWB_NORMAL 6 +#define MT_S2_FWB_NORMAL_NC 5 #define MT_S2_FWB_DEVICE_nGnRE 1 #ifdef CONFIG_ARM64_4K_PAGES diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index c651df904fe3..e2982a8922c3 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -717,15 +717,29 @@ void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu, static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot prot, kvm_pte_t *ptep) { - bool device = prot & KVM_PGTABLE_PROT_DEVICE; - kvm_pte_t attr = device ? KVM_S2_MEMATTR(pgt, DEVICE_nGnRE) : - KVM_S2_MEMATTR(pgt, NORMAL); + kvm_pte_t attr; u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS; + switch (prot & (KVM_PGTABLE_PROT_DEVICE | + KVM_PGTABLE_PROT_NORMAL_NC)) { + case KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC: + return -EINVAL; + case KVM_PGTABLE_PROT_DEVICE: + if (prot & KVM_PGTABLE_PROT_X) + return -EINVAL; + attr = KVM_S2_MEMATTR(pgt, DEVICE_nGnRE); + break; + case KVM_PGTABLE_PROT_NORMAL_NC: + if (prot & KVM_PGTABLE_PROT_X) + return -EINVAL; + attr = KVM_S2_MEMATTR(pgt, NORMAL_NC); + break; + default: + attr = KVM_S2_MEMATTR(pgt, NORMAL); + } + if (!(prot & KVM_PGTABLE_PROT_X)) attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN; - else if (device) - return -EINVAL; if (prot & KVM_PGTABLE_PROT_R) attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R; From 5c656fcdd6c60f71fccb07fe7b9d8d7e6c9811ff Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Sat, 24 Feb 2024 20:35:44 +0530 Subject: [PATCH 521/814] mm: Introduce new flag to indicate wc safe The VM_ALLOW_ANY_UNCACHED flag is implemented for ARM64, allowing KVM stage 2 device mapping attributes to use NormalNC rather than DEVICE_nGnRE, which allows guest mappings supporting write-combining attributes (WC). ARM does not architecturally guarantee this is safe, and indeed some MMIO regions like the GICv2 VCPU interface can trigger uncontained faults if NormalNC is used. Even worse, the expectation is that there are platforms where even DEVICE_nGnRE can allow uncontained faults in corner cases. Unfortunately existing ARM IP requires platform integration to take responsibility to prevent this. To safely use VFIO in KVM the platform must guarantee full safety in the guest where no action taken against a MMIO mapping can trigger an uncontained failure. The assumption is that most VFIO PCI platforms support this for both mapping types, at least in common flows, based on some expectations of how PCI IP is integrated. This can be enabled more broadly, for instance into vfio-platform drivers, but only after the platform vendor completes auditing for safety. The VMA flag VM_ALLOW_ANY_UNCACHED was found to be the simplest and cleanest way to communicate the information from VFIO to KVM that mapping the region in S2 as NormalNC is safe. KVM consumes it to activate the code that does the S2 mapping as NormalNC. Suggested-by: Catalin Marinas Reviewed-by: Jason Gunthorpe Reviewed-by: Marc Zyngier Acked-by: David Hildenbrand Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240224150546.368-3-ankita@nvidia.com Signed-off-by: Oliver Upton --- include/linux/mm.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index f5a97dec5169..59576e56c58b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -391,6 +391,20 @@ extern unsigned int kobjsize(const void *objp); # define VM_UFFD_MINOR VM_NONE #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */ +/* + * This flag is used to connect VFIO to arch specific KVM code. It + * indicates that the memory under this VMA is safe for use with any + * non-cachable memory type inside KVM. Some VFIO devices, on some + * platforms, are thought to be unsafe and can cause machine crashes + * if KVM does not lock down the memory type. + */ +#ifdef CONFIG_64BIT +#define VM_ALLOW_ANY_UNCACHED_BIT 39 +#define VM_ALLOW_ANY_UNCACHED BIT(VM_ALLOW_ANY_UNCACHED_BIT) +#else +#define VM_ALLOW_ANY_UNCACHED VM_NONE +#endif + /* Bits set in the VMA until the stack is in its final location */ #define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY) From 8c47ce3e1d2c285349edf426b98e8460ce3e2f33 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Sat, 24 Feb 2024 20:35:45 +0530 Subject: [PATCH 522/814] KVM: arm64: Set io memory s2 pte as normalnc for vfio pci device To provide VM with the ability to get device IO memory with NormalNC property, map device MMIO in KVM for ARM64 at stage2 as NormalNC. Having NormalNC S2 default puts guests in control (based on [1], "Combining stage 1 and stage 2 memory type attributes") of device MMIO regions memory mappings. The rules are summarized below: ([(S1) - stage1], [(S2) - stage 2]) S1 | S2 | Result NORMAL-WB | NORMAL-NC | NORMAL-NC NORMAL-WT | NORMAL-NC | NORMAL-NC NORMAL-NC | NORMAL-NC | NORMAL-NC DEVICE | NORMAL-NC | DEVICE Still this cannot be generalized to non PCI devices such as GICv2. There is insufficient information and uncertainity in the behavior of non PCI driver. A driver must indicate support using the new flag VM_ALLOW_ANY_UNCACHED. Adapt KVM to make use of the flag VM_ALLOW_ANY_UNCACHED as indicator to activate the S2 setting to NormalNc. [1] section D8.5.5 of DDI0487J_a_a-profile_architecture_reference_manual.pdf Suggested-by: Catalin Marinas Acked-by: Jason Gunthorpe Reviewed-by: Catalin Marinas Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240224150546.368-4-ankita@nvidia.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/mmu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index d14504821b79..1742fdccb432 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1381,7 +1381,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, int ret = 0; bool write_fault, writable, force_pte = false; bool exec_fault, mte_allowed; - bool device = false; + bool device = false, vfio_allow_any_uc = false; unsigned long mmu_seq; struct kvm *kvm = vcpu->kvm; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; @@ -1472,6 +1472,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, gfn = fault_ipa >> PAGE_SHIFT; mte_allowed = kvm_vma_mte_allowed(vma); + vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED; + /* Don't use the VMA after the unlock -- it may have vanished */ vma = NULL; @@ -1557,10 +1559,14 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (exec_fault) prot |= KVM_PGTABLE_PROT_X; - if (device) - prot |= KVM_PGTABLE_PROT_DEVICE; - else if (cpus_have_final_cap(ARM64_HAS_CACHE_DIC)) + if (device) { + if (vfio_allow_any_uc) + prot |= KVM_PGTABLE_PROT_NORMAL_NC; + else + prot |= KVM_PGTABLE_PROT_DEVICE; + } else if (cpus_have_final_cap(ARM64_HAS_CACHE_DIC)) { prot |= KVM_PGTABLE_PROT_X; + } /* * Under the premise of getting a FSC_PERM fault, we just need to relax From a39d3a966a090989b89c0287a67cd98c85ae2f52 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Sat, 24 Feb 2024 20:35:46 +0530 Subject: [PATCH 523/814] vfio: Convey kvm that the vfio-pci device is wc safe The VM_ALLOW_ANY_UNCACHED flag is implemented for ARM64, allowing KVM stage 2 device mapping attributes to use Normal-NC rather than DEVICE_nGnRE, which allows guest mappings supporting write-combining attributes (WC). ARM does not architecturally guarantee this is safe, and indeed some MMIO regions like the GICv2 VCPU interface can trigger uncontained faults if Normal-NC is used. To safely use VFIO in KVM the platform must guarantee full safety in the guest where no action taken against a MMIO mapping can trigger an uncontained failure. The expectation is that most VFIO PCI platforms support this for both mapping types, at least in common flows, based on some expectations of how PCI IP is integrated. So make vfio-pci set the VM_ALLOW_ANY_UNCACHED flag. Suggested-by: Catalin Marinas Acked-by: Jason Gunthorpe Acked-by: Catalin Marinas Acked-by: Alex Williamson Reviewed-by: David Hildenbrand Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Link: https://lore.kernel.org/r/20240224150546.368-5-ankita@nvidia.com Signed-off-by: Oliver Upton --- drivers/vfio/pci/vfio_pci_core.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 1cbc990d42e0..df6f99bdf70d 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -1862,8 +1862,25 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma /* * See remap_pfn_range(), called from vfio_pci_fault() but we can't * change vm_flags within the fault handler. Set them now. + * + * VM_ALLOW_ANY_UNCACHED: The VMA flag is implemented for ARM64, + * allowing KVM stage 2 device mapping attributes to use Normal-NC + * rather than DEVICE_nGnRE, which allows guest mappings + * supporting write-combining attributes (WC). ARM does not + * architecturally guarantee this is safe, and indeed some MMIO + * regions like the GICv2 VCPU interface can trigger uncontained + * faults if Normal-NC is used. + * + * To safely use VFIO in KVM the platform must guarantee full + * safety in the guest where no action taken against a MMIO + * mapping can trigger an uncontained failure. The assumption is + * that most VFIO PCI platforms support this for both mapping types, + * at least in common flows, based on some expectations of how + * PCI IP is integrated. Hence VM_ALLOW_ANY_UNCACHED is set in + * the VMA flags. */ - vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); + vm_flags_set(vma, VM_ALLOW_ANY_UNCACHED | VM_IO | VM_PFNMAP | + VM_DONTEXPAND | VM_DONTDUMP); vma->vm_ops = &vfio_pci_mmap_ops; return 0; From 2c5af1c8460376751d57c50af88a053a3b869926 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Jan 2024 17:58:31 +0800 Subject: [PATCH 524/814] selftests/kvm: Fix issues with $(SPLIT_TESTS) The introduction of $(SPLIT_TESTS) also introduced a warning when building selftests on architectures that include get-reg-lists: make: Entering directory '/root/kvm/tools/testing/selftests/kvm' Makefile:272: warning: overriding recipe for target '/root/kvm/tools/testing/selftests/kvm/get-reg-list' Makefile:267: warning: ignoring old recipe for target '/root/kvm/tools/testing/selftests/kvm/get-reg-list' make: Leaving directory '/root/kvm/tools/testing/selftests/kvm' In addition, the rule for $(SPLIT_TESTS_TARGETS) includes _all_ the $(SPLIT_TESTS_OBJS), which only works because there is just one. So fix both by adjusting the rules: - remove $(SPLIT_TESTS_TARGETS) from the $(TEST_GEN_PROGS) rules, and rename it to $(SPLIT_TEST_GEN_PROGS) - fix $(SPLIT_TESTS_OBJS) so that it plays well with $(OUTPUT), rename it to $(SPLIT_TEST_GEN_OBJ), and list the object file explicitly in the $(SPLIT_TEST_GEN_PROGS) link rule Fixes: 17da79e009c3 ("KVM: arm64: selftests: Split get-reg-list test code", 2023-08-09) Signed-off-by: Paolo Bonzini Tested-by: Andrew Jones Reviewed-by: Marc Zyngier Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 492e937fab00..157309da38e2 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -260,32 +260,36 @@ 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)) +SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS)) +SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(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)) +TEST_DEP_FILES += $(patsubst %.o, %.d, $(SPLIT_TEST_GEN_OBJ)) -include $(TEST_DEP_FILES) -$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o +x := $(shell mkdir -p $(sort $(OUTPUT)/$(ARCH_DIR) $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)))) + +$(filter-out $(SPLIT_TEST_GEN_PROGS), $(TEST_GEN_PROGS)) \ +$(TEST_GEN_PROGS_EXTENDED): %: %.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBKVM_OBJS) $(LDLIBS) -o $@ $(TEST_GEN_OBJ): $(OUTPUT)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ -$(SPLIT_TESTS_TARGETS): %: %.o $(SPLIT_TESTS_OBJS) +$(SPLIT_TEST_GEN_PROGS): $(OUTPUT)/%: $(OUTPUT)/%.o $(OUTPUT)/$(ARCH_DIR)/%.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@ +$(SPLIT_TEST_GEN_OBJ): $(OUTPUT)/$(ARCH_DIR)/%.o: $(ARCH_DIR)/%.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ EXTRA_CLEAN += $(GEN_HDRS) \ $(LIBKVM_OBJS) \ - $(SPLIT_TESTS_OBJS) \ + $(SPLIT_TEST_GEN_OBJ) \ $(TEST_DEP_FILES) \ $(TEST_GEN_OBJ) \ cscope.* -x := $(shell mkdir -p $(sort $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)))) $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c $(GEN_HDRS) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ @@ -299,7 +303,7 @@ $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@ x := $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS)))) -$(SPLIT_TESTS_OBJS): $(GEN_HDRS) +$(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS) $(TEST_GEN_PROGS): $(LIBKVM_OBJS) $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS) $(TEST_GEN_OBJ): $(GEN_HDRS) From f0617e4ac2b2fb69369486e09d0ce7653cd94985 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:32 +0800 Subject: [PATCH 525/814] KVM: arm64: selftests: Data type cleanup for arch_timer test Change signed type to unsigned in test_args struct which only make sense for unsigned value. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Reviewed-by: Marc Zyngier Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/aarch64/arch_timer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 2cb8dd1f8275..27191217f117 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -42,10 +42,10 @@ #define TIMER_TEST_MIGRATION_FREQ_MS 2 struct test_args { - int nr_vcpus; - int nr_iter; - int timer_period_ms; - int migration_freq_ms; + uint32_t nr_vcpus; + uint32_t nr_iter; + uint32_t timer_period_ms; + uint32_t migration_freq_ms; struct kvm_arm_counter_offset offset; }; @@ -57,7 +57,7 @@ static struct test_args test_args = { .offset = { .reserved = 1 }, }; -#define msecs_to_usecs(msec) ((msec) * 1000LL) +#define msecs_to_usecs(msec) ((msec) * 1000ULL) #define GICD_BASE_GPA 0x8000000ULL #define GICR_BASE_GPA 0x80A0000ULL @@ -72,7 +72,7 @@ enum guest_stage { /* Shared variables between host and guest */ struct test_vcpu_shared_data { - int nr_iter; + uint32_t nr_iter; enum guest_stage guest_stage; uint64_t xcnt; }; From d1dafd065a23e47a559f30573bffa600e527ff2a Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:33 +0800 Subject: [PATCH 526/814] KVM: arm64: selftests: Enable tuning of error margin in arch_timer test There are intermittent failures occurred when stressing the arch-timer test in a Qemu VM: Guest assert failed, vcpu 0; stage; 4; iter: 3 ==== Test Assertion Failure ==== aarch64/arch_timer.c:196: config_iter + 1 == irq_iter pid=4048 tid=4049 errno=4 - Interrupted system call 1 0x000000000040253b: test_vcpu_run at arch_timer.c:248 2 0x0000ffffb60dd5c7: ?? ??:0 3 0x0000ffffb6145d1b: ?? ??:0 0x3 != 0x2 (config_iter + 1 != irq_iter)e Further test and debug show that the timeout for an interrupt to arrive do have random high fluctuation, espectially when testing in an virtual environment. To alleviate this issue, just expose the timeout value as user configurable and print some hint message to increase the value when hitting the failure.. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Reviewed-by: Marc Zyngier Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/arch_timer.c | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 27191217f117..f794fd1152f5 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -6,16 +6,18 @@ * CVAL and TVAL registers. This consitutes the four stages in the test. * The guest's main thread configures the timer interrupt for a stage * and waits for it to fire, with a timeout equal to the timer period. - * It asserts that the timeout doesn't exceed the timer period. + * It asserts that the timeout doesn't exceed the timer period plus + * a user configurable error margin(default to 100us). * * On the other hand, upon receipt of an interrupt, the guest's interrupt * handler validates the interrupt by checking if the architectural state * is in compliance with the specifications. * * The test provides command-line options to configure the timer's - * period (-p), number of vCPUs (-n), and iterations per stage (-i). - * To stress-test the timer stack even more, an option to migrate the - * vCPUs across pCPUs (-m), at a particular rate, is also provided. + * period (-p), number of vCPUs (-n), iterations per stage (-i) and timer + * interrupt arrival error margin (-e). To stress-test the timer stack + * even more, an option to migrate the vCPUs across pCPUs (-m), at a + * particular rate, is also provided. * * Copyright (c) 2021, Google LLC. */ @@ -46,6 +48,7 @@ struct test_args { uint32_t nr_iter; uint32_t timer_period_ms; uint32_t migration_freq_ms; + uint32_t timer_err_margin_us; struct kvm_arm_counter_offset offset; }; @@ -54,6 +57,7 @@ static struct test_args test_args = { .nr_iter = NR_TEST_ITERS_DEF, .timer_period_ms = TIMER_TEST_PERIOD_MS_DEF, .migration_freq_ms = TIMER_TEST_MIGRATION_FREQ_MS, + .timer_err_margin_us = TIMER_TEST_ERR_MARGIN_US, .offset = { .reserved = 1 }, }; @@ -190,10 +194,14 @@ static void guest_run_stage(struct test_vcpu_shared_data *shared_data, /* Setup a timeout for the interrupt to arrive */ udelay(msecs_to_usecs(test_args.timer_period_ms) + - TIMER_TEST_ERR_MARGIN_US); + test_args.timer_err_margin_us); irq_iter = READ_ONCE(shared_data->nr_iter); - GUEST_ASSERT_EQ(config_iter + 1, irq_iter); + __GUEST_ASSERT(config_iter + 1 == irq_iter, + "config_iter + 1 = 0x%lx, irq_iter = 0x%lx.\n" + " Guest timer interrupt was not trigged within the specified\n" + " interval, try to increase the error margin by [-e] option.\n", + config_iter + 1, irq_iter); } } @@ -408,8 +416,9 @@ static void test_vm_cleanup(struct kvm_vm *vm) static void test_print_help(char *name) { - pr_info("Usage: %s [-h] [-n nr_vcpus] [-i iterations] [-p timer_period_ms]\n", - name); + pr_info("Usage: %s [-h] [-n nr_vcpus] [-i iterations] [-p timer_period_ms]\n" + "\t\t [-m migration_freq_ms] [-o counter_offset]\n" + "\t\t [-e timer_err_margin_us]\n", name); pr_info("\t-n: Number of vCPUs to configure (default: %u; max: %u)\n", NR_VCPUS_DEF, KVM_MAX_VCPUS); pr_info("\t-i: Number of iterations per stage (default: %u)\n", @@ -419,6 +428,8 @@ static void test_print_help(char *name) pr_info("\t-m: Frequency (in ms) of vCPUs to migrate to different pCPU. 0 to turn off (default: %u)\n", TIMER_TEST_MIGRATION_FREQ_MS); pr_info("\t-o: Counter offset (in counter cycles, default: 0)\n"); + pr_info("\t-e: Interrupt arrival error margin (in us) of the guest timer (default: %u)\n", + TIMER_TEST_ERR_MARGIN_US); pr_info("\t-h: print this help screen\n"); } @@ -426,7 +437,7 @@ static bool parse_args(int argc, char *argv[]) { int opt; - while ((opt = getopt(argc, argv, "hn:i:p:m:o:")) != -1) { + while ((opt = getopt(argc, argv, "hn:i:p:m:o:e:")) != -1) { switch (opt) { case 'n': test_args.nr_vcpus = atoi_positive("Number of vCPUs", optarg); @@ -445,6 +456,9 @@ static bool parse_args(int argc, char *argv[]) case 'm': test_args.migration_freq_ms = atoi_non_negative("Frequency", optarg); break; + case 'e': + test_args.timer_err_margin_us = atoi_non_negative("Error Margin", optarg); + break; case 'o': test_args.offset.counter_offset = strtol(optarg, NULL, 0); test_args.offset.reserved = 0; From c20dd9e0695fc1e4da4ff01a111b0392862cfed6 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:34 +0800 Subject: [PATCH 527/814] KVM: arm64: selftests: Split arch_timer test code Split the arch-neutral test code out of aarch64/arch_timer.c and put them into a common arch_timer.c. This is a preparation to share timer test codes in riscv. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 3 +- .../selftests/kvm/aarch64/arch_timer.c | 285 +----------------- tools/testing/selftests/kvm/arch_timer.c | 257 ++++++++++++++++ .../testing/selftests/kvm/include/test_util.h | 2 + .../selftests/kvm/include/timer_test.h | 44 +++ 5 files changed, 311 insertions(+), 280 deletions(-) create mode 100644 tools/testing/selftests/kvm/arch_timer.c create mode 100644 tools/testing/selftests/kvm/include/timer_test.h diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 157309da38e2..78960fe74480 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -143,7 +143,6 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test 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/hypercalls TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test @@ -155,6 +154,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access TEST_GEN_PROGS_aarch64 += access_tracking_perf_test +TEST_GEN_PROGS_aarch64 += arch_timer TEST_GEN_PROGS_aarch64 += demand_paging_test TEST_GEN_PROGS_aarch64 += dirty_log_test TEST_GEN_PROGS_aarch64 += dirty_log_perf_test @@ -194,6 +194,7 @@ TEST_GEN_PROGS_riscv += kvm_page_table_test TEST_GEN_PROGS_riscv += set_memory_region_test TEST_GEN_PROGS_riscv += steal_time +SPLIT_TESTS += arch_timer SPLIT_TESTS += get-reg-list TEST_PROGS += $(TEST_PROGS_$(ARCH_DIR)) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index f794fd1152f5..b9ce8c6455db 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -1,68 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * arch_timer.c - Tests the aarch64 timer IRQ functionality - * * The test validates both the virtual and physical timer IRQs using - * CVAL and TVAL registers. This consitutes the four stages in the test. - * The guest's main thread configures the timer interrupt for a stage - * and waits for it to fire, with a timeout equal to the timer period. - * It asserts that the timeout doesn't exceed the timer period plus - * a user configurable error margin(default to 100us). - * - * On the other hand, upon receipt of an interrupt, the guest's interrupt - * handler validates the interrupt by checking if the architectural state - * is in compliance with the specifications. - * - * The test provides command-line options to configure the timer's - * period (-p), number of vCPUs (-n), iterations per stage (-i) and timer - * interrupt arrival error margin (-e). To stress-test the timer stack - * even more, an option to migrate the vCPUs across pCPUs (-m), at a - * particular rate, is also provided. + * CVAL and TVAL registers. * * Copyright (c) 2021, Google LLC. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -#include "kvm_util.h" -#include "processor.h" -#include "delay.h" #include "arch_timer.h" +#include "delay.h" #include "gic.h" +#include "processor.h" +#include "timer_test.h" #include "vgic.h" -#define NR_VCPUS_DEF 4 -#define NR_TEST_ITERS_DEF 5 -#define TIMER_TEST_PERIOD_MS_DEF 10 -#define TIMER_TEST_ERR_MARGIN_US 100 -#define TIMER_TEST_MIGRATION_FREQ_MS 2 - -struct test_args { - uint32_t nr_vcpus; - uint32_t nr_iter; - uint32_t timer_period_ms; - uint32_t migration_freq_ms; - uint32_t timer_err_margin_us; - struct kvm_arm_counter_offset offset; -}; - -static struct test_args test_args = { - .nr_vcpus = NR_VCPUS_DEF, - .nr_iter = NR_TEST_ITERS_DEF, - .timer_period_ms = TIMER_TEST_PERIOD_MS_DEF, - .migration_freq_ms = TIMER_TEST_MIGRATION_FREQ_MS, - .timer_err_margin_us = TIMER_TEST_ERR_MARGIN_US, - .offset = { .reserved = 1 }, -}; - -#define msecs_to_usecs(msec) ((msec) * 1000ULL) - #define GICD_BASE_GPA 0x8000000ULL #define GICR_BASE_GPA 0x80A0000ULL @@ -74,22 +25,8 @@ enum guest_stage { GUEST_STAGE_MAX, }; -/* Shared variables between host and guest */ -struct test_vcpu_shared_data { - uint32_t nr_iter; - enum guest_stage guest_stage; - uint64_t xcnt; -}; - -static struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; -static pthread_t pt_vcpu_run[KVM_MAX_VCPUS]; -static struct test_vcpu_shared_data vcpu_shared_data[KVM_MAX_VCPUS]; - static int vtimer_irq, ptimer_irq; -static unsigned long *vcpu_done_map; -static pthread_mutex_t vcpu_done_map_lock; - static void guest_configure_timer_action(struct test_vcpu_shared_data *shared_data) { @@ -230,137 +167,6 @@ static void guest_code(void) GUEST_DONE(); } -static void *test_vcpu_run(void *arg) -{ - unsigned int vcpu_idx = (unsigned long)arg; - struct ucall uc; - struct kvm_vcpu *vcpu = vcpus[vcpu_idx]; - struct kvm_vm *vm = vcpu->vm; - struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpu_idx]; - - vcpu_run(vcpu); - - /* Currently, any exit from guest is an indication of completion */ - pthread_mutex_lock(&vcpu_done_map_lock); - __set_bit(vcpu_idx, vcpu_done_map); - pthread_mutex_unlock(&vcpu_done_map_lock); - - switch (get_ucall(vcpu, &uc)) { - case UCALL_SYNC: - case UCALL_DONE: - break; - case UCALL_ABORT: - sync_global_from_guest(vm, *shared_data); - 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"); - } - - return NULL; -} - -static uint32_t test_get_pcpu(void) -{ - uint32_t pcpu; - unsigned int nproc_conf; - cpu_set_t online_cpuset; - - nproc_conf = get_nprocs_conf(); - sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset); - - /* Randomly find an available pCPU to place a vCPU on */ - do { - pcpu = rand() % nproc_conf; - } while (!CPU_ISSET(pcpu, &online_cpuset)); - - return pcpu; -} - -static int test_migrate_vcpu(unsigned int vcpu_idx) -{ - int ret; - cpu_set_t cpuset; - uint32_t new_pcpu = test_get_pcpu(); - - CPU_ZERO(&cpuset); - CPU_SET(new_pcpu, &cpuset); - - pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); - - ret = pthread_setaffinity_np(pt_vcpu_run[vcpu_idx], - sizeof(cpuset), &cpuset); - - /* Allow the error where the vCPU thread is already finished */ - TEST_ASSERT(ret == 0 || ret == ESRCH, - "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d", - vcpu_idx, new_pcpu, ret); - - return ret; -} - -static void *test_vcpu_migration(void *arg) -{ - unsigned int i, n_done; - bool vcpu_done; - - do { - usleep(msecs_to_usecs(test_args.migration_freq_ms)); - - for (n_done = 0, i = 0; i < test_args.nr_vcpus; i++) { - pthread_mutex_lock(&vcpu_done_map_lock); - vcpu_done = test_bit(i, vcpu_done_map); - pthread_mutex_unlock(&vcpu_done_map_lock); - - if (vcpu_done) { - n_done++; - continue; - } - - test_migrate_vcpu(i); - } - } while (test_args.nr_vcpus != n_done); - - return NULL; -} - -static void test_run(struct kvm_vm *vm) -{ - pthread_t pt_vcpu_migration; - unsigned int i; - int ret; - - pthread_mutex_init(&vcpu_done_map_lock, NULL); - vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus); - TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap"); - - for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) { - ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run, - (void *)(unsigned long)i); - TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread", i); - } - - /* Spawn a thread to control the vCPU migrations */ - if (test_args.migration_freq_ms) { - srand(time(NULL)); - - ret = pthread_create(&pt_vcpu_migration, NULL, - test_vcpu_migration, NULL); - TEST_ASSERT(!ret, "Failed to create the migration pthread"); - } - - - for (i = 0; i < test_args.nr_vcpus; i++) - pthread_join(pt_vcpu_run[i], NULL); - - if (test_args.migration_freq_ms) - pthread_join(pt_vcpu_migration, NULL); - - bitmap_free(vcpu_done_map); -} - static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ @@ -377,7 +183,7 @@ static void test_init_timer_irq(struct kvm_vm *vm) static int gic_fd; -static struct kvm_vm *test_vm_create(void) +struct kvm_vm *test_vm_create(void) { struct kvm_vm *vm; unsigned int i; @@ -408,87 +214,8 @@ static struct kvm_vm *test_vm_create(void) return vm; } -static void test_vm_cleanup(struct kvm_vm *vm) +void test_vm_cleanup(struct kvm_vm *vm) { close(gic_fd); kvm_vm_free(vm); } - -static void test_print_help(char *name) -{ - pr_info("Usage: %s [-h] [-n nr_vcpus] [-i iterations] [-p timer_period_ms]\n" - "\t\t [-m migration_freq_ms] [-o counter_offset]\n" - "\t\t [-e timer_err_margin_us]\n", name); - pr_info("\t-n: Number of vCPUs to configure (default: %u; max: %u)\n", - NR_VCPUS_DEF, KVM_MAX_VCPUS); - pr_info("\t-i: Number of iterations per stage (default: %u)\n", - NR_TEST_ITERS_DEF); - pr_info("\t-p: Periodicity (in ms) of the guest timer (default: %u)\n", - TIMER_TEST_PERIOD_MS_DEF); - pr_info("\t-m: Frequency (in ms) of vCPUs to migrate to different pCPU. 0 to turn off (default: %u)\n", - TIMER_TEST_MIGRATION_FREQ_MS); - pr_info("\t-o: Counter offset (in counter cycles, default: 0)\n"); - pr_info("\t-e: Interrupt arrival error margin (in us) of the guest timer (default: %u)\n", - TIMER_TEST_ERR_MARGIN_US); - pr_info("\t-h: print this help screen\n"); -} - -static bool parse_args(int argc, char *argv[]) -{ - int opt; - - while ((opt = getopt(argc, argv, "hn:i:p:m:o:e:")) != -1) { - switch (opt) { - case 'n': - test_args.nr_vcpus = atoi_positive("Number of vCPUs", optarg); - if (test_args.nr_vcpus > KVM_MAX_VCPUS) { - pr_info("Max allowed vCPUs: %u\n", - KVM_MAX_VCPUS); - goto err; - } - break; - case 'i': - test_args.nr_iter = atoi_positive("Number of iterations", optarg); - break; - case 'p': - test_args.timer_period_ms = atoi_positive("Periodicity", optarg); - break; - case 'm': - test_args.migration_freq_ms = atoi_non_negative("Frequency", optarg); - break; - case 'e': - test_args.timer_err_margin_us = atoi_non_negative("Error Margin", optarg); - break; - case 'o': - test_args.offset.counter_offset = strtol(optarg, NULL, 0); - test_args.offset.reserved = 0; - break; - case 'h': - default: - goto err; - } - } - - return true; - -err: - test_print_help(argv[0]); - return false; -} - -int main(int argc, char *argv[]) -{ - struct kvm_vm *vm; - - if (!parse_args(argc, argv)) - exit(KSFT_SKIP); - - __TEST_REQUIRE(!test_args.migration_freq_ms || get_nprocs() >= 2, - "At least two physical CPUs needed for vCPU migration"); - - vm = test_vm_create(); - test_run(vm); - test_vm_cleanup(vm); - - return 0; -} diff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c new file mode 100644 index 000000000000..f7e4cee8cb34 --- /dev/null +++ b/tools/testing/selftests/kvm/arch_timer.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * arch_timer.c - Tests the arch timer IRQ functionality + * + * The guest's main thread configures the timer interrupt and waits + * for it to fire, with a timeout equal to the timer period. + * It asserts that the timeout doesn't exceed the timer period plus + * a user configurable error margin(default to 100us) + * + * On the other hand, upon receipt of an interrupt, the guest's interrupt + * handler validates the interrupt by checking if the architectural state + * is in compliance with the specifications. + * + * The test provides command-line options to configure the timer's + * period (-p), number of vCPUs (-n), iterations per stage (-i) and timer + * interrupt arrival error margin (-e). To stress-test the timer stack + * even more, an option to migrate the vCPUs across pCPUs (-m), at a + * particular rate, is also provided. + * + * Copyright (c) 2021, Google LLC. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "timer_test.h" + +struct test_args test_args = { + .nr_vcpus = NR_VCPUS_DEF, + .nr_iter = NR_TEST_ITERS_DEF, + .timer_period_ms = TIMER_TEST_PERIOD_MS_DEF, + .migration_freq_ms = TIMER_TEST_MIGRATION_FREQ_MS, + .timer_err_margin_us = TIMER_TEST_ERR_MARGIN_US, + .offset = { .reserved = 1 }, +}; + +struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; +struct test_vcpu_shared_data vcpu_shared_data[KVM_MAX_VCPUS]; + +static pthread_t pt_vcpu_run[KVM_MAX_VCPUS]; +static unsigned long *vcpu_done_map; +static pthread_mutex_t vcpu_done_map_lock; + +static void *test_vcpu_run(void *arg) +{ + unsigned int vcpu_idx = (unsigned long)arg; + struct ucall uc; + struct kvm_vcpu *vcpu = vcpus[vcpu_idx]; + struct kvm_vm *vm = vcpu->vm; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpu_idx]; + + vcpu_run(vcpu); + + /* Currently, any exit from guest is an indication of completion */ + pthread_mutex_lock(&vcpu_done_map_lock); + __set_bit(vcpu_idx, vcpu_done_map); + pthread_mutex_unlock(&vcpu_done_map_lock); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + case UCALL_DONE: + break; + case UCALL_ABORT: + sync_global_from_guest(vm, *shared_data); + 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"); + } + + return NULL; +} + +static uint32_t test_get_pcpu(void) +{ + uint32_t pcpu; + unsigned int nproc_conf; + cpu_set_t online_cpuset; + + nproc_conf = get_nprocs_conf(); + sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset); + + /* Randomly find an available pCPU to place a vCPU on */ + do { + pcpu = rand() % nproc_conf; + } while (!CPU_ISSET(pcpu, &online_cpuset)); + + return pcpu; +} + +static int test_migrate_vcpu(unsigned int vcpu_idx) +{ + int ret; + cpu_set_t cpuset; + uint32_t new_pcpu = test_get_pcpu(); + + CPU_ZERO(&cpuset); + CPU_SET(new_pcpu, &cpuset); + + pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); + + ret = pthread_setaffinity_np(pt_vcpu_run[vcpu_idx], + sizeof(cpuset), &cpuset); + + /* Allow the error where the vCPU thread is already finished */ + TEST_ASSERT(ret == 0 || ret == ESRCH, + "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d", + vcpu_idx, new_pcpu, ret); + + return ret; +} + +static void *test_vcpu_migration(void *arg) +{ + unsigned int i, n_done; + bool vcpu_done; + + do { + usleep(msecs_to_usecs(test_args.migration_freq_ms)); + + for (n_done = 0, i = 0; i < test_args.nr_vcpus; i++) { + pthread_mutex_lock(&vcpu_done_map_lock); + vcpu_done = test_bit(i, vcpu_done_map); + pthread_mutex_unlock(&vcpu_done_map_lock); + + if (vcpu_done) { + n_done++; + continue; + } + + test_migrate_vcpu(i); + } + } while (test_args.nr_vcpus != n_done); + + return NULL; +} + +static void test_run(struct kvm_vm *vm) +{ + pthread_t pt_vcpu_migration; + unsigned int i; + int ret; + + pthread_mutex_init(&vcpu_done_map_lock, NULL); + vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus); + TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap"); + + for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) { + ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run, + (void *)(unsigned long)i); + TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread", i); + } + + /* Spawn a thread to control the vCPU migrations */ + if (test_args.migration_freq_ms) { + srand(time(NULL)); + + ret = pthread_create(&pt_vcpu_migration, NULL, + test_vcpu_migration, NULL); + TEST_ASSERT(!ret, "Failed to create the migration pthread"); + } + + + for (i = 0; i < test_args.nr_vcpus; i++) + pthread_join(pt_vcpu_run[i], NULL); + + if (test_args.migration_freq_ms) + pthread_join(pt_vcpu_migration, NULL); + + bitmap_free(vcpu_done_map); +} + +static void test_print_help(char *name) +{ + pr_info("Usage: %s [-h] [-n nr_vcpus] [-i iterations] [-p timer_period_ms]\n" + "\t\t [-m migration_freq_ms] [-o counter_offset]\n" + "\t\t [-e timer_err_margin_us]\n", name); + pr_info("\t-n: Number of vCPUs to configure (default: %u; max: %u)\n", + NR_VCPUS_DEF, KVM_MAX_VCPUS); + pr_info("\t-i: Number of iterations per stage (default: %u)\n", + NR_TEST_ITERS_DEF); + pr_info("\t-p: Periodicity (in ms) of the guest timer (default: %u)\n", + TIMER_TEST_PERIOD_MS_DEF); + pr_info("\t-m: Frequency (in ms) of vCPUs to migrate to different pCPU. 0 to turn off (default: %u)\n", + TIMER_TEST_MIGRATION_FREQ_MS); + pr_info("\t-o: Counter offset (in counter cycles, default: 0)\n"); + pr_info("\t-e: Interrupt arrival error margin (in us) of the guest timer (default: %u)\n", + TIMER_TEST_ERR_MARGIN_US); + pr_info("\t-h: print this help screen\n"); +} + +static bool parse_args(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "hn:i:p:m:o:e:")) != -1) { + switch (opt) { + case 'n': + test_args.nr_vcpus = atoi_positive("Number of vCPUs", optarg); + if (test_args.nr_vcpus > KVM_MAX_VCPUS) { + pr_info("Max allowed vCPUs: %u\n", + KVM_MAX_VCPUS); + goto err; + } + break; + case 'i': + test_args.nr_iter = atoi_positive("Number of iterations", optarg); + break; + case 'p': + test_args.timer_period_ms = atoi_positive("Periodicity", optarg); + break; + case 'm': + test_args.migration_freq_ms = atoi_non_negative("Frequency", optarg); + break; + case 'e': + test_args.timer_err_margin_us = atoi_non_negative("Error Margin", optarg); + break; + case 'o': + test_args.offset.counter_offset = strtol(optarg, NULL, 0); + test_args.offset.reserved = 0; + break; + case 'h': + default: + goto err; + } + } + + return true; + +err: + test_print_help(argv[0]); + return false; +} + +int main(int argc, char *argv[]) +{ + struct kvm_vm *vm; + + if (!parse_args(argc, argv)) + exit(KSFT_SKIP); + + __TEST_REQUIRE(!test_args.migration_freq_ms || get_nprocs() >= 2, + "At least two physical CPUs needed for vCPU migration"); + + vm = test_vm_create(); + test_run(vm); + test_vm_cleanup(vm); + + return 0; +} diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 50a5e31ba8da..8a6e30612c86 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -20,6 +20,8 @@ #include #include "kselftest.h" +#define msecs_to_usecs(msec) ((msec) * 1000ULL) + static inline int _no_printf(const char *format, ...) { return 0; } #ifdef DEBUG diff --git a/tools/testing/selftests/kvm/include/timer_test.h b/tools/testing/selftests/kvm/include/timer_test.h new file mode 100644 index 000000000000..256e2d2137cf --- /dev/null +++ b/tools/testing/selftests/kvm/include/timer_test.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * timer test specific header + * + * Copyright (C) 2018, Google LLC + */ + +#ifndef SELFTEST_KVM_TIMER_TEST_H +#define SELFTEST_KVM_TIMER_TEST_H + +#include "kvm_util.h" + +#define NR_VCPUS_DEF 4 +#define NR_TEST_ITERS_DEF 5 +#define TIMER_TEST_PERIOD_MS_DEF 10 +#define TIMER_TEST_ERR_MARGIN_US 100 +#define TIMER_TEST_MIGRATION_FREQ_MS 2 + +/* Timer test cmdline parameters */ +struct test_args { + uint32_t nr_vcpus; + uint32_t nr_iter; + uint32_t timer_period_ms; + uint32_t migration_freq_ms; + uint32_t timer_err_margin_us; + /* TODO: Change arm specific type to a common one */ + struct kvm_arm_counter_offset offset; +}; + +/* Shared variables between host and guest */ +struct test_vcpu_shared_data { + uint32_t nr_iter; + int guest_stage; + uint64_t xcnt; +}; + +extern struct test_args test_args; +extern struct kvm_vcpu *vcpus[]; +extern struct test_vcpu_shared_data vcpu_shared_data[]; + +struct kvm_vm *test_vm_create(void); +void test_vm_cleanup(struct kvm_vm *vm); + +#endif /* SELFTEST_KVM_TIMER_TEST_H */ From b4b12469c5c3fbd9b9f8e5070e6e47a4337b87c6 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:35 +0800 Subject: [PATCH 528/814] KVM: selftests: Add CONFIG_64BIT definition for the build Since only 64bit KVM selftests were supported on all architectures, add the CONFIG_64BIT definition in kvm/Makefile to ensure only 64bit definitions were available in the corresponding included files. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 78960fe74480..63592045720f 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -218,7 +218,7 @@ else LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include endif CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \ - -Wno-gnu-variable-sized-type-not-at-end -MD -MP \ + -Wno-gnu-variable-sized-type-not-at-end -MD -MP -DCONFIG_64BIT \ -fno-builtin-memcmp -fno-builtin-memcpy -fno-builtin-memset \ -fno-builtin-strnlen \ -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \ From a69459d579df9200bc6f58ff04e1a8a4984016a7 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:36 +0800 Subject: [PATCH 529/814] tools: riscv: Add header file csr.h Borrow the csr definitions and operations from kernel's arch/riscv/include/asm/csr.h to tools/ for riscv. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/arch/riscv/include/asm/csr.h | 541 +++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 tools/arch/riscv/include/asm/csr.h diff --git a/tools/arch/riscv/include/asm/csr.h b/tools/arch/riscv/include/asm/csr.h new file mode 100644 index 000000000000..0dfc09254f99 --- /dev/null +++ b/tools/arch/riscv/include/asm/csr.h @@ -0,0 +1,541 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2015 Regents of the University of California + */ + +#ifndef _ASM_RISCV_CSR_H +#define _ASM_RISCV_CSR_H + +#include + +/* Status register flags */ +#define SR_SIE _AC(0x00000002, UL) /* Supervisor Interrupt Enable */ +#define SR_MIE _AC(0x00000008, UL) /* Machine Interrupt Enable */ +#define SR_SPIE _AC(0x00000020, UL) /* Previous Supervisor IE */ +#define SR_MPIE _AC(0x00000080, UL) /* Previous Machine IE */ +#define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */ +#define SR_MPP _AC(0x00001800, UL) /* Previously Machine */ +#define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */ + +#define SR_FS _AC(0x00006000, UL) /* Floating-point Status */ +#define SR_FS_OFF _AC(0x00000000, UL) +#define SR_FS_INITIAL _AC(0x00002000, UL) +#define SR_FS_CLEAN _AC(0x00004000, UL) +#define SR_FS_DIRTY _AC(0x00006000, UL) + +#define SR_VS _AC(0x00000600, UL) /* Vector Status */ +#define SR_VS_OFF _AC(0x00000000, UL) +#define SR_VS_INITIAL _AC(0x00000200, UL) +#define SR_VS_CLEAN _AC(0x00000400, UL) +#define SR_VS_DIRTY _AC(0x00000600, UL) + +#define SR_XS _AC(0x00018000, UL) /* Extension Status */ +#define SR_XS_OFF _AC(0x00000000, UL) +#define SR_XS_INITIAL _AC(0x00008000, UL) +#define SR_XS_CLEAN _AC(0x00010000, UL) +#define SR_XS_DIRTY _AC(0x00018000, UL) + +#define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ + +#ifndef CONFIG_64BIT +#define SR_SD _AC(0x80000000, UL) /* FS/VS/XS dirty */ +#else +#define SR_SD _AC(0x8000000000000000, UL) /* FS/VS/XS dirty */ +#endif + +#ifdef CONFIG_64BIT +#define SR_UXL _AC(0x300000000, UL) /* XLEN mask for U-mode */ +#define SR_UXL_32 _AC(0x100000000, UL) /* XLEN = 32 for U-mode */ +#define SR_UXL_64 _AC(0x200000000, UL) /* XLEN = 64 for U-mode */ +#endif + +/* SATP flags */ +#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) +#else +#define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL) +#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) +#endif + +/* Exception cause high bit - is an interrupt if set */ +#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1)) + +/* Interrupt causes (minus the high bit) */ +#define IRQ_S_SOFT 1 +#define IRQ_VS_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_VS_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_VS_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_S_GEXT 12 +#define IRQ_PMU_OVF 13 +#define IRQ_LOCAL_MAX (IRQ_PMU_OVF + 1) +#define IRQ_LOCAL_MASK GENMASK((IRQ_LOCAL_MAX - 1), 0) + +/* Exception causes */ +#define EXC_INST_MISALIGNED 0 +#define EXC_INST_ACCESS 1 +#define EXC_INST_ILLEGAL 2 +#define EXC_BREAKPOINT 3 +#define EXC_LOAD_MISALIGNED 4 +#define EXC_LOAD_ACCESS 5 +#define EXC_STORE_MISALIGNED 6 +#define EXC_STORE_ACCESS 7 +#define EXC_SYSCALL 8 +#define EXC_HYPERVISOR_SYSCALL 9 +#define EXC_SUPERVISOR_SYSCALL 10 +#define EXC_INST_PAGE_FAULT 12 +#define EXC_LOAD_PAGE_FAULT 13 +#define EXC_STORE_PAGE_FAULT 15 +#define EXC_INST_GUEST_PAGE_FAULT 20 +#define EXC_LOAD_GUEST_PAGE_FAULT 21 +#define EXC_VIRTUAL_INST_FAULT 22 +#define EXC_STORE_GUEST_PAGE_FAULT 23 + +/* PMP configuration */ +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_A_TOR 0x08 +#define PMP_A_NA4 0x10 +#define PMP_A_NAPOT 0x18 +#define PMP_L 0x80 + +/* HSTATUS flags */ +#ifdef CONFIG_64BIT +#define HSTATUS_VSXL _AC(0x300000000, UL) +#define HSTATUS_VSXL_SHIFT 32 +#endif +#define HSTATUS_VTSR _AC(0x00400000, UL) +#define HSTATUS_VTW _AC(0x00200000, UL) +#define HSTATUS_VTVM _AC(0x00100000, UL) +#define HSTATUS_VGEIN _AC(0x0003f000, UL) +#define HSTATUS_VGEIN_SHIFT 12 +#define HSTATUS_HU _AC(0x00000200, UL) +#define HSTATUS_SPVP _AC(0x00000100, UL) +#define HSTATUS_SPV _AC(0x00000080, UL) +#define HSTATUS_GVA _AC(0x00000040, UL) +#define HSTATUS_VSBE _AC(0x00000020, UL) + +/* HGATP flags */ +#define HGATP_MODE_OFF _AC(0, UL) +#define HGATP_MODE_SV32X4 _AC(1, UL) +#define HGATP_MODE_SV39X4 _AC(8, UL) +#define HGATP_MODE_SV48X4 _AC(9, UL) +#define HGATP_MODE_SV57X4 _AC(10, UL) + +#define HGATP32_MODE_SHIFT 31 +#define HGATP32_VMID_SHIFT 22 +#define HGATP32_VMID GENMASK(28, 22) +#define HGATP32_PPN GENMASK(21, 0) + +#define HGATP64_MODE_SHIFT 60 +#define HGATP64_VMID_SHIFT 44 +#define HGATP64_VMID GENMASK(57, 44) +#define HGATP64_PPN GENMASK(43, 0) + +#define HGATP_PAGE_SHIFT 12 + +#ifdef CONFIG_64BIT +#define HGATP_PPN HGATP64_PPN +#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT +#define HGATP_VMID HGATP64_VMID +#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT +#else +#define HGATP_PPN HGATP32_PPN +#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT +#define HGATP_VMID HGATP32_VMID +#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT +#endif + +/* VSIP & HVIP relation */ +#define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT) +#define VSIP_VALID_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \ + (_AC(1, UL) << IRQ_S_TIMER) | \ + (_AC(1, UL) << IRQ_S_EXT)) + +/* AIA CSR bits */ +#define TOPI_IID_SHIFT 16 +#define TOPI_IID_MASK GENMASK(11, 0) +#define TOPI_IPRIO_MASK GENMASK(7, 0) +#define TOPI_IPRIO_BITS 8 + +#define TOPEI_ID_SHIFT 16 +#define TOPEI_ID_MASK GENMASK(10, 0) +#define TOPEI_PRIO_MASK GENMASK(10, 0) + +#define ISELECT_IPRIO0 0x30 +#define ISELECT_IPRIO15 0x3f +#define ISELECT_MASK GENMASK(8, 0) + +#define HVICTL_VTI BIT(30) +#define HVICTL_IID GENMASK(27, 16) +#define HVICTL_IID_SHIFT 16 +#define HVICTL_DPR BIT(9) +#define HVICTL_IPRIOM BIT(8) +#define HVICTL_IPRIO GENMASK(7, 0) + +/* xENVCFG flags */ +#define ENVCFG_STCE (_AC(1, ULL) << 63) +#define ENVCFG_PBMTE (_AC(1, ULL) << 62) +#define ENVCFG_CBZE (_AC(1, UL) << 7) +#define ENVCFG_CBCFE (_AC(1, UL) << 6) +#define ENVCFG_CBIE_SHIFT 4 +#define ENVCFG_CBIE (_AC(0x3, UL) << ENVCFG_CBIE_SHIFT) +#define ENVCFG_CBIE_ILL _AC(0x0, UL) +#define ENVCFG_CBIE_FLUSH _AC(0x1, UL) +#define ENVCFG_CBIE_INV _AC(0x3, UL) +#define ENVCFG_FIOM _AC(0x1, UL) + +/* Smstateen bits */ +#define SMSTATEEN0_AIA_IMSIC_SHIFT 58 +#define SMSTATEEN0_AIA_IMSIC (_ULL(1) << SMSTATEEN0_AIA_IMSIC_SHIFT) +#define SMSTATEEN0_AIA_SHIFT 59 +#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT) +#define SMSTATEEN0_AIA_ISEL_SHIFT 60 +#define SMSTATEEN0_AIA_ISEL (_ULL(1) << SMSTATEEN0_AIA_ISEL_SHIFT) +#define SMSTATEEN0_HSENVCFG_SHIFT 62 +#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT) +#define SMSTATEEN0_SSTATEEN0_SHIFT 63 +#define SMSTATEEN0_SSTATEEN0 (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT) + +/* symbolic CSR names: */ +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f + +#define CSR_SSCOUNTOVF 0xda0 + +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SENVCFG 0x10a +#define CSR_SSTATEEN0 0x10c +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_SATP 0x180 + +#define CSR_STIMECMP 0x14D +#define CSR_STIMECMPH 0x15D + +/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_SISELECT 0x150 +#define CSR_SIREG 0x151 + +/* Supervisor-Level Interrupts (AIA) */ +#define CSR_STOPEI 0x15c +#define CSR_STOPI 0xdb0 + +/* Supervisor-Level High-Half CSRs (AIA) */ +#define CSR_SIEH 0x114 +#define CSR_SIPH 0x154 + +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 +#define CSR_VSTIMECMP 0x24D +#define CSR_VSTIMECMPH 0x25D + +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 +#define CSR_HENVCFG 0x60a +#define CSR_HTIMEDELTAH 0x615 +#define CSR_HENVCFGH 0x61a +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64a +#define CSR_HGATP 0x680 +#define CSR_HGEIP 0xe12 + +/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ +#define CSR_HVIEN 0x608 +#define CSR_HVICTL 0x609 +#define CSR_HVIPRIO1 0x646 +#define CSR_HVIPRIO2 0x647 + +/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */ +#define CSR_VSISELECT 0x250 +#define CSR_VSIREG 0x251 + +/* VS-Level Interrupts (H-extension with AIA) */ +#define CSR_VSTOPEI 0x25c +#define CSR_VSTOPI 0xeb0 + +/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ +#define CSR_HIDELEGH 0x613 +#define CSR_HVIENH 0x618 +#define CSR_HVIPH 0x655 +#define CSR_HVIPRIO1H 0x656 +#define CSR_HVIPRIO2H 0x657 +#define CSR_VSIEH 0x214 +#define CSR_VSIPH 0x254 + +/* Hypervisor stateen CSRs */ +#define CSR_HSTATEEN0 0x60c +#define CSR_HSTATEEN0H 0x61c + +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MENVCFG 0x30a +#define CSR_MENVCFGH 0x31a +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPADDR0 0x3b0 +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 + +/* Machine-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_MISELECT 0x350 +#define CSR_MIREG 0x351 + +/* Machine-Level Interrupts (AIA) */ +#define CSR_MTOPEI 0x35c +#define CSR_MTOPI 0xfb0 + +/* Virtual Interrupts for Supervisor Level (AIA) */ +#define CSR_MVIEN 0x308 +#define CSR_MVIP 0x309 + +/* Machine-Level High-Half CSRs (AIA) */ +#define CSR_MIDELEGH 0x313 +#define CSR_MIEH 0x314 +#define CSR_MVIENH 0x318 +#define CSR_MVIPH 0x319 +#define CSR_MIPH 0x354 + +#define CSR_VSTART 0x8 +#define CSR_VCSR 0xf +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 +#define CSR_VLENB 0xc22 + +#ifdef CONFIG_RISCV_M_MODE +# define CSR_STATUS CSR_MSTATUS +# define CSR_IE CSR_MIE +# define CSR_TVEC CSR_MTVEC +# define CSR_SCRATCH CSR_MSCRATCH +# define CSR_EPC CSR_MEPC +# define CSR_CAUSE CSR_MCAUSE +# define CSR_TVAL CSR_MTVAL +# define CSR_IP CSR_MIP + +# define CSR_IEH CSR_MIEH +# define CSR_ISELECT CSR_MISELECT +# define CSR_IREG CSR_MIREG +# define CSR_IPH CSR_MIPH +# define CSR_TOPEI CSR_MTOPEI +# define CSR_TOPI CSR_MTOPI + +# define SR_IE SR_MIE +# define SR_PIE SR_MPIE +# define SR_PP SR_MPP + +# define RV_IRQ_SOFT IRQ_M_SOFT +# define RV_IRQ_TIMER IRQ_M_TIMER +# define RV_IRQ_EXT IRQ_M_EXT +#else /* CONFIG_RISCV_M_MODE */ +# define CSR_STATUS CSR_SSTATUS +# define CSR_IE CSR_SIE +# define CSR_TVEC CSR_STVEC +# define CSR_SCRATCH CSR_SSCRATCH +# define CSR_EPC CSR_SEPC +# define CSR_CAUSE CSR_SCAUSE +# define CSR_TVAL CSR_STVAL +# define CSR_IP CSR_SIP + +# define CSR_IEH CSR_SIEH +# define CSR_ISELECT CSR_SISELECT +# define CSR_IREG CSR_SIREG +# define CSR_IPH CSR_SIPH +# define CSR_TOPEI CSR_STOPEI +# define CSR_TOPI CSR_STOPI + +# define SR_IE SR_SIE +# define SR_PIE SR_SPIE +# define SR_PP SR_SPP + +# define RV_IRQ_SOFT IRQ_S_SOFT +# define RV_IRQ_TIMER IRQ_S_TIMER +# define RV_IRQ_EXT IRQ_S_EXT +# define RV_IRQ_PMU IRQ_PMU_OVF +# define SIP_LCOFIP (_AC(0x1, UL) << IRQ_PMU_OVF) + +#endif /* !CONFIG_RISCV_M_MODE */ + +/* IE/IP (Supervisor/Machine Interrupt Enable/Pending) flags */ +#define IE_SIE (_AC(0x1, UL) << RV_IRQ_SOFT) +#define IE_TIE (_AC(0x1, UL) << RV_IRQ_TIMER) +#define IE_EIE (_AC(0x1, UL) << RV_IRQ_EXT) + +#ifdef __ASSEMBLY__ +#define __ASM_STR(x) x +#else +#define __ASM_STR(x) #x +#endif + +#ifndef __ASSEMBLY__ + +#define csr_swap(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\ + : "=r" (__v) : "rK" (__v) \ + : "memory"); \ + __v; \ +}) + +#define csr_read(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ + : "=r" (__v) : \ + : "memory"); \ + __v; \ +}) + +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) + +#define csr_read_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\ + : "=r" (__v) : "rK" (__v) \ + : "memory"); \ + __v; \ +}) + +#define csr_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) + +#define csr_read_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\ + : "=r" (__v) : "rK" (__v) \ + : "memory"); \ + __v; \ +}) + +#define csr_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_CSR_H */ From 1d50c77208933fd1c18be8359633913d9c482e5a Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:37 +0800 Subject: [PATCH 530/814] tools: riscv: Add header file vdso/processor.h Borrow the cpu_relax() definitions from kernel's arch/riscv/include/asm/vdso/processor.h to tools/ for riscv. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/arch/riscv/include/asm/vdso/processor.h | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tools/arch/riscv/include/asm/vdso/processor.h diff --git a/tools/arch/riscv/include/asm/vdso/processor.h b/tools/arch/riscv/include/asm/vdso/processor.h new file mode 100644 index 000000000000..662aca039848 --- /dev/null +++ b/tools/arch/riscv/include/asm/vdso/processor.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +#include + +static inline void cpu_relax(void) +{ +#ifdef __riscv_muldiv + int dummy; + /* In lieu of a halt instruction, induce a long-latency stall. */ + __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy)); +#endif + +#ifdef CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE + /* + * Reduce instruction retirement. + * This assumes the PC changes. + */ + __asm__ __volatile__ ("pause"); +#else + /* Encoding of the pause instruction */ + __asm__ __volatile__ (".4byte 0x100000F"); +#endif + barrier(); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ From feb2c8fae3b8703408f01a8db822dd05b1a576ee Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:38 +0800 Subject: [PATCH 531/814] KVM: riscv: selftests: Switch to use macro from csr.h Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/include/riscv/processor.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index a0f9efe5a2a8..b6b95e747688 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -7,8 +7,9 @@ #ifndef SELFTEST_KVM_PROCESSOR_H #define SELFTEST_KVM_PROCESSOR_H -#include "kvm_util.h" #include +#include +#include "kvm_util.h" static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype, uint64_t idx, uint64_t size) @@ -101,13 +102,6 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype, #define PGTBL_PAGE_SIZE PGTBL_L0_BLOCK_SIZE #define PGTBL_PAGE_SIZE_SHIFT PGTBL_L0_BLOCK_SHIFT -#define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL) -#define SATP_MODE_39 _AC(0x8000000000000000, UL) -#define SATP_MODE_48 _AC(0x9000000000000000, UL) -#define SATP_ASID_BITS 16 -#define SATP_ASID_SHIFT 44 -#define SATP_ASID_MASK _AC(0xFFFF, UL) - /* SBI return error codes */ #define SBI_SUCCESS 0 #define SBI_ERR_FAILURE -1 From 1447c13051c7ed6f43a73eeee8e26280c4016e5d Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 24 Feb 2024 22:29:38 +0100 Subject: [PATCH 532/814] dt-bindings: lcdif: Do not require power-domains for i.MX6ULL i.MX6UL(L) uses "fsl,imx6sx-lcdif" as fallback compatible string, but has only very lightweight DISPLAY power domain. Its DISPLAY power domain is not supported by the binding / Linux kernel at the moment. Since the current setup is working, let's remove the power-domain from being required for that platform to fix the warning printed by CHECK_DTBS=y. Fixes: f62678a77d58 ("dt-bindings: mxsfb: Document i.MX8M/i.MX6SX/i.MX6SL power-domains property") Acked-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20240224213240.1854709-7-sre@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/display/fsl,lcdif.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/fsl,lcdif.yaml b/Documentation/devicetree/bindings/display/fsl,lcdif.yaml index 1c2be8d6f633..0681fc49aa1b 100644 --- a/Documentation/devicetree/bindings/display/fsl,lcdif.yaml +++ b/Documentation/devicetree/bindings/display/fsl,lcdif.yaml @@ -120,13 +120,19 @@ allOf: maxItems: 1 clock-names: maxItems: 1 + - if: + properties: + compatible: + const: fsl,imx6sx-lcdif + then: + required: + - power-domains - if: properties: compatible: contains: enum: - fsl,imx6sl-lcdif - - fsl,imx6sx-lcdif - fsl,imx8mm-lcdif - fsl,imx8mn-lcdif - fsl,imx8mp-lcdif From 812d432373f629eb8d6cb696ea6804fca1534efa Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 6 Dec 2023 11:20:54 +0800 Subject: [PATCH 533/814] KVM: x86/pmu: Explicitly check NMI from guest to reducee false positives Explicitly check that the source of external interrupt is indeed an NMI in kvm_arch_pmi_in_guest(), which reduces perf-kvm false positive samples (host samples labelled as guest samples) generated by perf/core NMI mode if an NMI arrives after VM-Exit, but before kvm_after_interrupt(): # test: perf-record + cpu-cycles:HP (which collects host-only precise samples) # Symbol Overhead sys usr guest sys guest usr # ....................................... ........ ........ ........ ......... ......... # # Before: [g] entry_SYSCALL_64 24.63% 0.00% 0.00% 24.63% 0.00% [g] syscall_return_via_sysret 23.23% 0.00% 0.00% 23.23% 0.00% [g] files_lookup_fd_raw 6.35% 0.00% 0.00% 6.35% 0.00% # After: [k] perf_adjust_freq_unthr_context 57.23% 57.23% 0.00% 0.00% 0.00% [k] __vmx_vcpu_run 4.09% 4.09% 0.00% 0.00% 0.00% [k] vmx_update_host_rsp 3.17% 3.17% 0.00% 0.00% 0.00% In the above case, perf records the samples labelled '[g]', the RIPs behind the weird samples are actually being queried by perf_instruction_pointer() after determining whether it's in GUEST state or not, and here's the issue: If VM-Exit is caused by a non-NMI interrupt (such as hrtimer_interrupt) and at least one PMU counter is enabled on host, the kvm_arch_pmi_in_guest() will remain true (KVM_HANDLING_IRQ is set) until kvm_before_interrupt(). During this window, if a PMI occurs on host (since the KVM instructions on host are being executed), the control flow, with the help of the host NMI context, will be transferred to perf/core to generate performance samples, thus perf_instruction_pointer() and perf_guest_get_ip() is called. Since kvm_arch_pmi_in_guest() only checks if there is an interrupt, it may cause perf/core to mistakenly assume that the source RIP of the host NMI belongs to the guest world and use perf_guest_get_ip() to get the RIP of a vCPU that has already exited by a non-NMI interrupt. Error samples are recorded and presented to the end-user via perf-report. Such false positive samples could be eliminated by explicitly determining if the exit reason is KVM_HANDLING_NMI. Note that when VM-exit is indeed triggered by PMI and before HANDLING_NMI is cleared, it's also still possible that another PMI is generated on host. Also for perf/core timer mode, the false positives are still possible since those non-NMI sources of interrupts are not always being used by perf/core. For events that are host-only, perf/core can and should eliminate false positives by checking event->attr.exclude_guest, i.e. events that are configured to exclude KVM guests should never fire in the guest. Events that are configured to count host and guest are trickier, perhaps impossible to handle with 100% accuracy? And regardless of what accuracy is provided by perf/core, improving KVM's accuracy is cheap and easy, with no real downsides. Fixes: dd60d217062f ("KVM: x86: Fix perf timer mode IP reporting") Signed-off-by: Like Xu Reviewed-by: Maxim Levitsky Link: https://lore.kernel.org/r/20231206032054.55070-1-likexu@tencent.com [sean: massage changelog, squash !!in_nmi() fixup from Like] Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 10 +++++++++- arch/x86/kvm/x86.h | 6 ------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index ad5319a503f0..672ea5e97478 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1880,8 +1880,16 @@ static inline int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, } #endif /* CONFIG_HYPERV */ +enum kvm_intr_type { + /* Values are arbitrary, but must be non-zero. */ + KVM_HANDLING_IRQ = 1, + KVM_HANDLING_NMI, +}; + +/* Enable perf NMI and timer modes to work, and minimise false positives. */ #define kvm_arch_pmi_in_guest(vcpu) \ - ((vcpu) && (vcpu)->arch.handling_intr_from_guest) + ((vcpu) && (vcpu)->arch.handling_intr_from_guest && \ + (!!in_nmi() == ((vcpu)->arch.handling_intr_from_guest == KVM_HANDLING_NMI))) void __init kvm_mmu_x86_module_init(void); int kvm_mmu_vendor_module_init(void); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 2f7e19166658..4dc38092d599 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -431,12 +431,6 @@ static inline bool kvm_notify_vmexit_enabled(struct kvm *kvm) return kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_ENABLED; } -enum kvm_intr_type { - /* Values are arbitrary, but must be non-zero. */ - KVM_HANDLING_IRQ = 1, - KVM_HANDLING_NMI, -}; - static __always_inline void kvm_before_interrupt(struct kvm_vcpu *vcpu, enum kvm_intr_type intr) { From e10086285659bb7ecc5819e5c7e47f5bdc02668d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:37 +0100 Subject: [PATCH 534/814] KVM: selftests: x86: sync_regs_test: Use vcpu_run() where appropriate In the spots where we are expecting a successful run, we should use vcpu_run() instead of _vcpu_run() to make sure that the run did not fail. Suggested-by: Sean Christopherson Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-2-thuth@redhat.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/sync_regs_test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 00965ba33f73..8c3898cf79b3 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) /* Request and verify all valid register sets. */ /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ run->kvm_valid_regs = TEST_SYNC_FIELDS; - rv = _vcpu_run(vcpu); + vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); vcpu_regs_get(vcpu, ®s); @@ -278,7 +278,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS; - rv = _vcpu_run(vcpu); + vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); TEST_ASSERT(run->s.regs.regs.rbx == 0xBAD1DEA + 1, "rbx sync regs value incorrect 0x%llx.", @@ -302,7 +302,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xDEADBEEF; - rv = _vcpu_run(vcpu); + vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); TEST_ASSERT(run->s.regs.regs.rbx != 0xDEADBEEF, "rbx sync regs value incorrect 0x%llx.", @@ -317,7 +317,7 @@ int main(int argc, char *argv[]) run->s.regs.regs.rbx = 0xAAAA; regs.rbx = 0xBAC0; vcpu_regs_set(vcpu, ®s); - rv = _vcpu_run(vcpu); + vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA, "rbx sync regs value incorrect 0x%llx.", @@ -334,7 +334,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = 0; run->kvm_dirty_regs = TEST_SYNC_FIELDS; run->s.regs.regs.rbx = 0xBBBB; - rv = _vcpu_run(vcpu); + vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB, "rbx sync regs value incorrect 0x%llx.", From 221d65449453846bbf6801d0ecf7dfdf4f413ad9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:38 +0100 Subject: [PATCH 535/814] KVM: selftests: x86: sync_regs_test: Get regs structure before modifying it The regs structure just accidentally contains the right values from the previous test in the spot where we want to change rbx. It's cleaner if we properly initialize the structure here before using it. Suggested-by: Sean Christopherson Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-3-thuth@redhat.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/sync_regs_test.c | 1 + 1 file changed, 1 insertion(+) 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 8c3898cf79b3..1cd19dfa0046 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -315,6 +315,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = 0; run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xAAAA; + vcpu_regs_get(vcpu, ®s); regs.rbx = 0xBAC0; vcpu_regs_set(vcpu, ®s); vcpu_run(vcpu); From c121b588a5e46e14bc601e717461b908a1d80185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simone=20Wei=C3=9F?= Date: Sat, 17 Feb 2024 19:14:09 +0000 Subject: [PATCH 536/814] scsi: bfa: Remove additional unnecessary struct declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit c3b0d087763f ("scsi: bfa: Remove unnecessary struct declarations") removed duplicate struct declarations for struct bfa_fcs_s and struct bfa_fcs_fabric_s. However, there are further duplications: - struct bfad_vf_s is declared in line 165 remove the duplication in line 834. - struct bfad_rport_s is declared in line 394 remove the duplication in line 836. Remove them. Signed-off-by: Simone Weiß Link: https://lore.kernel.org/r/20240217191409.6260-1-simone.p.weiss@posteo.com Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index c1baf5cd0d3e..4d8bd9f932f6 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -831,9 +831,7 @@ void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, */ struct bfad_port_s; -struct bfad_vf_s; struct bfad_vport_s; -struct bfad_rport_s; /* * lport callbacks From b69600231f751304db914c63b937f7098ed2895c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2024 13:44:06 +0100 Subject: [PATCH 537/814] scsi: bfa: Fix function pointer type mismatch for hcb_qe->cbfn Some callback functions used here take a boolean argument, others take a status argument. This breaks KCFI type checking, so clang now warns about the function pointer cast: drivers/scsi/bfa/bfad_bsg.c:2138:29: error: cast from 'void (*)(void *, enum bfa_status)' to 'bfa_cb_cbfn_t' (aka 'void (*)(void *, enum bfa_boolean)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] Assuming the code is actually correct here and the callers always match the argument types of the callee, rework this to replace the explicit cast with a union of the two pointer types. This does not change the behavior of the code, so if something is actually broken here, a larger rework may be necessary. Fixes: 37ea0558b87a ("[SCSI] bfa: Added support to collect and reset fcport stats") Fixes: 3ec4f2c8bff2 ("[SCSI] bfa: Added support to configure QOS and collect stats.") Reviewed-by: Kees Cook Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240222124433.2046570-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa.h | 9 ++++++++- drivers/scsi/bfa/bfa_core.c | 4 +--- drivers/scsi/bfa/bfa_ioc.h | 8 ++++++-- drivers/scsi/bfa/bfad_bsg.c | 11 ++++------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h index 7bd2ba1ad4d1..f30fe324e6ec 100644 --- a/drivers/scsi/bfa/bfa.h +++ b/drivers/scsi/bfa/bfa.h @@ -20,7 +20,6 @@ struct bfa_s; typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); -typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status); /* * Interrupt message handlers @@ -437,4 +436,12 @@ struct bfa_cb_pending_q_s { (__qe)->data = (__data); \ } while (0) +#define bfa_pending_q_init_status(__qe, __cbfn, __cbarg, __data) do { \ + bfa_q_qe_init(&((__qe)->hcb_qe.qe)); \ + (__qe)->hcb_qe.cbfn_status = (__cbfn); \ + (__qe)->hcb_qe.cbarg = (__cbarg); \ + (__qe)->hcb_qe.pre_rmv = BFA_TRUE; \ + (__qe)->data = (__data); \ +} while (0) + #endif /* __BFA_H__ */ diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 6846ca8f7313..3438d0b8ba06 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -1907,15 +1907,13 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) struct list_head *qe; struct list_head *qen; struct bfa_cb_qe_s *hcb_qe; - bfa_cb_cbfn_status_t cbfn; list_for_each_safe(qe, qen, comp_q) { hcb_qe = (struct bfa_cb_qe_s *) qe; if (hcb_qe->pre_rmv) { /* qe is invalid after return, dequeue before cbfn() */ list_del(qe); - cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn); - cbfn(hcb_qe->cbarg, hcb_qe->fw_status); + hcb_qe->cbfn_status(hcb_qe->cbarg, hcb_qe->fw_status); } else hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE); } diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 933a1c3890ff..5e568d6d7b26 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -361,14 +361,18 @@ struct bfa_reqq_wait_s { void *cbarg; }; -typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); +typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); +typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status); /* * Generic BFA callback element. */ struct bfa_cb_qe_s { struct list_head qe; - bfa_cb_cbfn_t cbfn; + union { + bfa_cb_cbfn_status_t cbfn_status; + bfa_cb_cbfn_t cbfn; + }; bfa_boolean_t once; bfa_boolean_t pre_rmv; /* set for stack based qe(s) */ bfa_status_t fw_status; /* to access fw status in comp proc */ diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index d4ceca2d435e..54bd11e6d593 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2135,8 +2135,7 @@ bfad_iocmd_fcport_get_stats(struct bfad_s *bfad, void *cmd) struct bfa_cb_pending_q_s cb_qe; init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, &iocmd->stats); + bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, &iocmd->stats); spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -2159,7 +2158,7 @@ bfad_iocmd_fcport_reset_stats(struct bfad_s *bfad, void *cmd) struct bfa_cb_pending_q_s cb_qe; init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, &fcomp, NULL); + bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, NULL); spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); @@ -2443,8 +2442,7 @@ bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd) struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, &iocmd->stats); + bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, &iocmd->stats); spin_lock_irqsave(&bfad->bfad_lock, flags); WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); @@ -2474,8 +2472,7 @@ bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd) struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, NULL); + bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, NULL); spin_lock_irqsave(&bfad->bfad_lock, flags); WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); From 37126399da15e1d53da93c0282aca539bccc891b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2024 13:44:07 +0100 Subject: [PATCH 538/814] scsi: bfa: Fix function pointer type mismatch for state machines The bfa driver is full of state machines and a generic abstraction layer for them. This relies on casting function pointers, but that is no longer allowed when CONFIG_CFI_CLANG is enabled and causes a huge number of warnings like: drivers/scsi/bfa/bfad.c:169:3: error: cast from 'void (*)(struct bfad_s *, enum bfad_sm_event)' to 'bfa_sm_t' (aka 'void (*)(void *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] bfa_sm_set_state(bfad, bfad_sm_created); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rework the mechanism to no longer require the function pointer casts, by having separate types for each individual state machine. This in turn requires moving the enum definitions for each state machine into the header files in order to define the typedef. Reviewed-by: Kees Cook Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240222124433.2046570-2-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa.h | 21 ++- drivers/scsi/bfa/bfa_cs.h | 21 +-- drivers/scsi/bfa/bfa_fcpim.c | 51 ----- drivers/scsi/bfa/bfa_fcpim.h | 66 ++++++- drivers/scsi/bfa/bfa_fcs.h | 310 +++++++++++++++++++++---------- drivers/scsi/bfa/bfa_fcs_fcpim.c | 23 ++- drivers/scsi/bfa/bfa_fcs_lport.c | 112 ++--------- drivers/scsi/bfa/bfa_fcs_rport.c | 34 ++-- drivers/scsi/bfa/bfa_ioc.c | 85 ++++----- drivers/scsi/bfa/bfa_ioc.h | 76 ++++++-- drivers/scsi/bfa/bfa_svc.c | 72 +++---- drivers/scsi/bfa/bfa_svc.h | 115 +++++++++--- drivers/scsi/bfa/bfad_drv.h | 31 ++-- 13 files changed, 582 insertions(+), 435 deletions(-) diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h index f30fe324e6ec..4cb9249e583c 100644 --- a/drivers/scsi/bfa/bfa.h +++ b/drivers/scsi/bfa/bfa.h @@ -215,8 +215,27 @@ struct bfa_faa_args_s { bfa_boolean_t busy; }; +/* + * IOCFC state machine definitions/declarations + */ +enum iocfc_event { + IOCFC_E_INIT = 1, /* IOCFC init request */ + IOCFC_E_START = 2, /* IOCFC mod start request */ + IOCFC_E_STOP = 3, /* IOCFC stop request */ + IOCFC_E_ENABLE = 4, /* IOCFC enable request */ + IOCFC_E_DISABLE = 5, /* IOCFC disable request */ + IOCFC_E_IOC_ENABLED = 6, /* IOC enabled message */ + IOCFC_E_IOC_DISABLED = 7, /* IOC disabled message */ + IOCFC_E_IOC_FAILED = 8, /* failure notice by IOC sm */ + IOCFC_E_DCONF_DONE = 9, /* dconf read/write done */ + IOCFC_E_CFG_DONE = 10, /* IOCFC config complete */ +}; + +struct bfa_iocfc_s; +typedef void (*bfa_iocfs_fsm_t)(struct bfa_iocfc_s *, enum iocfc_event); + struct bfa_iocfc_s { - bfa_fsm_t fsm; + bfa_iocfs_fsm_t fsm; struct bfa_s *bfa; struct bfa_iocfc_cfg_s cfg; u32 req_cq_pi[BFI_IOC_MAX_CQS]; diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h index 6b606bf589b4..6650b1dbb1ed 100644 --- a/drivers/scsi/bfa/bfa_cs.h +++ b/drivers/scsi/bfa/bfa_cs.h @@ -187,10 +187,10 @@ typedef void (*bfa_sm_t)(void *sm, int event); #define bfa_sm_state_decl(oc, st, otype, etype) \ static void oc ## _sm_ ## st(otype * fsm, etype event) -#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state)) +#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (_state)) #define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event))) #define bfa_sm_get_state(_sm) ((_sm)->sm) -#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state)) +#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (_state)) /* * For converting from state machine function to state encoding. @@ -200,7 +200,7 @@ struct bfa_sm_table_s { int state; /* state machine encoding */ char *name; /* state name for display */ }; -#define BFA_SM(_sm) ((bfa_sm_t)(_sm)) +#define BFA_SM(_sm) (_sm) /* * State machine with entry actions. @@ -218,24 +218,13 @@ typedef void (*bfa_fsm_t)(void *fsm, int event); static void oc ## _sm_ ## st ## _entry(otype * fsm) #define bfa_fsm_set_state(_fsm, _state) do { \ - (_fsm)->fsm = (bfa_fsm_t)(_state); \ + (_fsm)->fsm = (_state); \ _state ## _entry(_fsm); \ } while (0) #define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) #define bfa_fsm_get_state(_fsm) ((_fsm)->fsm) -#define bfa_fsm_cmp_state(_fsm, _state) \ - ((_fsm)->fsm == (bfa_fsm_t)(_state)) - -static inline int -bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm) -{ - int i = 0; - - while (smt[i].sm && smt[i].sm != sm) - i++; - return smt[i].state; -} +#define bfa_fsm_cmp_state(_fsm, _state) ((_fsm)->fsm == (_state)) /* * @ Generic wait counter. diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 7ad22288071b..28ae4dc14dc9 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -64,21 +64,6 @@ enum bfa_ioim_lm_ua_status { BFA_IOIM_LM_UA_SET = 1, }; -/* - * itnim state machine event - */ -enum bfa_itnim_event { - BFA_ITNIM_SM_CREATE = 1, /* itnim is created */ - BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */ - BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */ - BFA_ITNIM_SM_FWRSP = 4, /* firmware response */ - BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */ - BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */ - BFA_ITNIM_SM_SLER = 7, /* second level error recovery */ - BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */ - BFA_ITNIM_SM_QRESUME = 9, /* queue space available */ -}; - /* * BFA IOIM related definitions */ @@ -98,30 +83,6 @@ enum bfa_itnim_event { (__fcpim)->profile_start(__ioim); \ } while (0) -/* - * IO state machine events - */ -enum bfa_ioim_event { - BFA_IOIM_SM_START = 1, /* io start request from host */ - BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */ - BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */ - BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */ - BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */ - BFA_IOIM_SM_FREE = 6, /* io resource is freed */ - BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */ - BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */ - BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */ - BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */ - BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */ - BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */ - BFA_IOIM_SM_HCB = 13, /* bfa callback complete */ - BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */ - BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */ - BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ - BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ - BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ -}; - /* * BFA TSKIM related definitions @@ -141,18 +102,6 @@ enum bfa_ioim_event { } while (0) -enum bfa_tskim_event { - BFA_TSKIM_SM_START = 1, /* TM command start */ - BFA_TSKIM_SM_DONE = 2, /* TM completion */ - BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */ - BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */ - BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */ - BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ - BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ - BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ - BFA_TSKIM_SM_UTAG = 10, /* TM completion unknown tag */ -}; - /* * forward declaration for BFA ITNIM functions */ diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index 8bf09433549b..4499f84c2d81 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -154,12 +154,39 @@ struct bfa_fcp_mod_s { int throttle_update_required; }; +/* + * IO state machine events + */ +enum bfa_ioim_event { + BFA_IOIM_SM_START = 1, /* io start request from host */ + BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */ + BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */ + BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */ + BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */ + BFA_IOIM_SM_FREE = 6, /* io resource is freed */ + BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */ + BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */ + BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */ + BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */ + BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */ + BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */ + BFA_IOIM_SM_HCB = 13, /* bfa callback complete */ + BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */ + BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */ + BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ + BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ + BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ +}; + +struct bfa_ioim_s; +typedef void (*bfa_ioim_sm_t)(struct bfa_ioim_s *, enum bfa_ioim_event); + /* * BFA IO (initiator mode) */ struct bfa_ioim_s { struct list_head qe; /* queue elememt */ - bfa_sm_t sm; /* BFA ioim state machine */ + bfa_ioim_sm_t sm; /* BFA ioim state machine */ struct bfa_s *bfa; /* BFA module */ struct bfa_fcpim_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ @@ -186,12 +213,27 @@ struct bfa_ioim_sp_s { struct bfa_tskim_s *tskim; /* Relevant TM cmd */ }; +enum bfa_tskim_event { + BFA_TSKIM_SM_START = 1, /* TM command start */ + BFA_TSKIM_SM_DONE = 2, /* TM completion */ + BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */ + BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */ + BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */ + BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ + BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ + BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ + BFA_TSKIM_SM_UTAG = 10, /* TM completion unknown tag */ +}; + +struct bfa_tskim_s; +typedef void (*bfa_tskim_sm_t)(struct bfa_tskim_s *, enum bfa_tskim_event); + /* * BFA Task management command (initiator mode) */ struct bfa_tskim_s { struct list_head qe; - bfa_sm_t sm; + bfa_tskim_sm_t sm; struct bfa_s *bfa; /* BFA module */ struct bfa_fcpim_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ @@ -208,12 +250,30 @@ struct bfa_tskim_s { enum bfi_tskim_status tsk_status; /* TM status */ }; +/* + * itnim state machine event + */ +enum bfa_itnim_event { + BFA_ITNIM_SM_CREATE = 1, /* itnim is created */ + BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */ + BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */ + BFA_ITNIM_SM_FWRSP = 4, /* firmware response */ + BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */ + BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */ + BFA_ITNIM_SM_SLER = 7, /* second level error recovery */ + BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */ + BFA_ITNIM_SM_QRESUME = 9, /* queue space available */ +}; + +struct bfa_itnim_s; +typedef void (*bfa_itnim_sm_t)(struct bfa_itnim_s *, enum bfa_itnim_event); + /* * BFA i-t-n (initiator mode) */ struct bfa_itnim_s { struct list_head qe; /* queue element */ - bfa_sm_t sm; /* i-t-n im BFA state machine */ + bfa_itnim_sm_t sm; /* i-t-n im BFA state machine */ struct bfa_s *bfa; /* bfa instance */ struct bfa_rport_s *rport; /* bfa rport */ void *ditn; /* driver i-t-n structure */ diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 4d8bd9f932f6..9788354b90da 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -19,22 +19,6 @@ #define BFA_FCS_OS_STR_LEN 64 -/* - * lps_pvt BFA LPS private functions - */ - -enum bfa_lps_event { - BFA_LPS_SM_LOGIN = 1, /* login request from user */ - BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ - BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ - BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ - BFA_LPS_SM_DELETE = 5, /* lps delete from user */ - BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ - BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ - BFA_LPS_SM_SET_N2N_PID = 8, /* Set assigned PID for n2n */ -}; - - /* * !!! Only append to the enums defined here to avoid any versioning * !!! needed between trace utility and driver version @@ -59,8 +43,30 @@ struct bfa_fcs_s; #define BFA_FCS_PID_IS_WKA(pid) ((bfa_ntoh3b(pid) > 0xFFF000) ? 1 : 0) #define BFA_FCS_MAX_RPORT_LOGINS 1024 +/* + * VPort NS State Machine events + */ +enum vport_ns_event { + NSSM_EVENT_PORT_ONLINE = 1, + NSSM_EVENT_PORT_OFFLINE = 2, + NSSM_EVENT_PLOGI_SENT = 3, + NSSM_EVENT_RSP_OK = 4, + NSSM_EVENT_RSP_ERROR = 5, + NSSM_EVENT_TIMEOUT = 6, + NSSM_EVENT_NS_QUERY = 7, + NSSM_EVENT_RSPNID_SENT = 8, + NSSM_EVENT_RFTID_SENT = 9, + NSSM_EVENT_RFFID_SENT = 10, + NSSM_EVENT_GIDFT_SENT = 11, + NSSM_EVENT_RNNID_SENT = 12, + NSSM_EVENT_RSNN_NN_SENT = 13, +}; + +struct bfa_fcs_lport_ns_s; +typedef void (*bfa_fcs_lport_ns_sm_t)(struct bfa_fcs_lport_ns_s *fsm, enum vport_ns_event); + struct bfa_fcs_lport_ns_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_ns_sm_t sm; /* state machine */ struct bfa_timer_s timer; struct bfa_fcs_lport_s *port; /* parent port */ struct bfa_fcxp_s *fcxp; @@ -69,9 +75,23 @@ struct bfa_fcs_lport_ns_s { u8 num_rsnn_nn_retries; }; +/* + * VPort SCN State Machine events + */ +enum port_scn_event { + SCNSM_EVENT_PORT_ONLINE = 1, + SCNSM_EVENT_PORT_OFFLINE = 2, + SCNSM_EVENT_RSP_OK = 3, + SCNSM_EVENT_RSP_ERROR = 4, + SCNSM_EVENT_TIMEOUT = 5, + SCNSM_EVENT_SCR_SENT = 6, +}; + +struct bfa_fcs_lport_scn_s; +typedef void (*bfa_fcs_lport_scn_sm_t)(struct bfa_fcs_lport_scn_s *fsm, enum port_scn_event); struct bfa_fcs_lport_scn_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_scn_sm_t sm; /* state machine */ struct bfa_timer_s timer; struct bfa_fcs_lport_s *port; /* parent port */ struct bfa_fcxp_s *fcxp; @@ -79,8 +99,25 @@ struct bfa_fcs_lport_scn_s { }; +/* + * FDMI State Machine events + */ +enum port_fdmi_event { + FDMISM_EVENT_PORT_ONLINE = 1, + FDMISM_EVENT_PORT_OFFLINE = 2, + FDMISM_EVENT_RSP_OK = 4, + FDMISM_EVENT_RSP_ERROR = 5, + FDMISM_EVENT_TIMEOUT = 6, + FDMISM_EVENT_RHBA_SENT = 7, + FDMISM_EVENT_RPRT_SENT = 8, + FDMISM_EVENT_RPA_SENT = 9, +}; + +struct bfa_fcs_lport_fdmi_s; +typedef void (*bfa_fcs_lport_fdmi_sm_t)(struct bfa_fcs_lport_fdmi_s *fsm, enum port_fdmi_event); + struct bfa_fcs_lport_fdmi_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_fdmi_sm_t sm; /* state machine */ struct bfa_timer_s timer; struct bfa_fcs_lport_ms_s *ms; /* parent ms */ struct bfa_fcxp_s *fcxp; @@ -88,10 +125,24 @@ struct bfa_fcs_lport_fdmi_s { u8 retry_cnt; /* retry count */ u8 rsvd[3]; }; +/* + * MS State Machine events + */ +enum port_ms_event { + MSSM_EVENT_PORT_ONLINE = 1, + MSSM_EVENT_PORT_OFFLINE = 2, + MSSM_EVENT_RSP_OK = 3, + MSSM_EVENT_RSP_ERROR = 4, + MSSM_EVENT_TIMEOUT = 5, + MSSM_EVENT_FCXP_SENT = 6, + MSSM_EVENT_PORT_FABRIC_RSCN = 7 +}; +struct bfa_fcs_lport_ms_s; +typedef void (*bfa_fcs_lport_ms_sm_t)(struct bfa_fcs_lport_ms_s *fsm, enum port_ms_event); struct bfa_fcs_lport_ms_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_ms_sm_t sm; /* state machine */ struct bfa_timer_s timer; struct bfa_fcs_lport_s *port; /* parent port */ struct bfa_fcxp_s *fcxp; @@ -131,10 +182,25 @@ union bfa_fcs_lport_topo_u { struct bfa_fcs_lport_n2n_s pn2n; }; +/* + * fcs_port_sm FCS logical port state machine + */ + +enum bfa_fcs_lport_event { + BFA_FCS_PORT_SM_CREATE = 1, + BFA_FCS_PORT_SM_ONLINE = 2, + BFA_FCS_PORT_SM_OFFLINE = 3, + BFA_FCS_PORT_SM_DELETE = 4, + BFA_FCS_PORT_SM_DELRPORT = 5, + BFA_FCS_PORT_SM_STOP = 6, +}; + +struct bfa_fcs_lport_s; +typedef void (*bfa_fcs_lport_sm_t)(struct bfa_fcs_lport_s *fsm, enum bfa_fcs_lport_event); struct bfa_fcs_lport_s { struct list_head qe; /* used by port/vport */ - bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_sm_t sm; /* state machine */ struct bfa_fcs_fabric_s *fabric; /* parent fabric */ struct bfa_lport_cfg_s port_cfg; /* port configuration */ struct bfa_timer_s link_timer; /* timer for link offline */ @@ -171,10 +237,37 @@ enum bfa_fcs_fabric_type { BFA_FCS_FABRIC_LOOP = 3, }; +/* + * Fabric state machine events + */ +enum bfa_fcs_fabric_event { + BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */ + BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */ + BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */ + BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */ + BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */ + BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */ + BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */ + BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */ + BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */ + BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */ + BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */ + BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */ + BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */ + BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ + BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ + BFA_FCS_FABRIC_SM_START = 16, /* from driver */ + BFA_FCS_FABRIC_SM_STOP = 17, /* Stop from driver */ + BFA_FCS_FABRIC_SM_STOPCOMP = 18, /* Stop completion */ + BFA_FCS_FABRIC_SM_LOGOCOMP = 19, /* FLOGO completion */ +}; + +struct bfa_fcs_fabric_s; +typedef void (*bfa_fcs_fabric_sm_t)(struct bfa_fcs_fabric_s *fsm, enum bfa_fcs_fabric_event); struct bfa_fcs_fabric_s { struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ + bfa_fcs_fabric_sm_t sm; /* state machine */ struct bfa_fcs_s *fcs; /* FCS instance */ struct bfa_fcs_lport_s bport; /* base logical port */ enum bfa_fcs_fabric_type fab_type; /* fabric type */ @@ -344,9 +437,33 @@ void bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, struct fchs_s *rx_frame, u32 len); void bfa_fcs_lport_lip_scn_online(bfa_fcs_lport_t *port); +/* + * VPort State Machine events + */ +enum bfa_fcs_vport_event { + BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */ + BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */ + BFA_FCS_VPORT_SM_START = 3, /* vport start request */ + BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */ + BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */ + BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */ + BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */ + BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */ + BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */ + BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */ + BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ + BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ + BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ + BFA_FCS_VPORT_SM_STOPCOMP = 14, /* vport delete completion */ + BFA_FCS_VPORT_SM_FABRIC_MAX = 15, /* max vports on fabric */ +}; + +struct bfa_fcs_vport_s; +typedef void (*bfa_fcs_vport_sm_t)(struct bfa_fcs_vport_s *fsm, enum bfa_fcs_vport_event); + struct bfa_fcs_vport_s { struct list_head qe; /* queue elem */ - bfa_sm_t sm; /* state machine */ + bfa_fcs_vport_sm_t sm; /* state machine */ bfa_fcs_lport_t lport; /* logical port */ struct bfa_timer_s timer; struct bfad_vport_s *vport_drv; /* Driver private */ @@ -397,9 +514,26 @@ struct bfa_fcs_itnim_s; struct bfa_fcs_tin_s; struct bfa_fcs_iprp_s; +/* + * fcs_rport_ftrs_sm FCS rport state machine events + */ + +enum rpf_event { + RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */ + RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */ + RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */ + RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */ + RPFSM_EVENT_RPSC_COMP = 5, + RPFSM_EVENT_RPSC_FAIL = 6, + RPFSM_EVENT_RPSC_ERROR = 7, +}; + +struct bfa_fcs_rpf_s; +typedef void (*bfa_fcs_rpf_sm_t)(struct bfa_fcs_rpf_s *, enum rpf_event); + /* Rport Features (RPF) */ struct bfa_fcs_rpf_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_rpf_sm_t sm; /* state machine */ struct bfa_fcs_rport_s *rport; /* parent rport */ struct bfa_timer_s timer; /* general purpose timer */ struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ @@ -414,6 +548,36 @@ struct bfa_fcs_rpf_s { */ }; +/* + * fcs_rport_sm FCS rport state machine events + */ +enum rport_event { + RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */ + RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */ + RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */ + RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */ + RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ + RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ + RPSM_EVENT_DELETE = 7, /* RPORT delete request */ + RPSM_EVENT_FAB_SCN = 8, /* state change notification */ + RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */ + RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ + RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ + RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */ + RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ + RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ + RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ + RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ + RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ + RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continuously */ + RPSM_EVENT_SCN_OFFLINE = 19, /* loop scn offline */ + RPSM_EVENT_SCN_ONLINE = 20, /* loop scn online */ + RPSM_EVENT_FC4_FCS_ONLINE = 21, /* FC-4 FCS online complete */ +}; + +struct bfa_fcs_rport_s; +typedef void (*bfa_fcs_rport_sm_t)(struct bfa_fcs_rport_s *, enum rport_event); + struct bfa_fcs_rport_s { struct list_head qe; /* used by port/vport */ struct bfa_fcs_lport_s *port; /* parent FCS port */ @@ -430,7 +594,7 @@ struct bfa_fcs_rport_s { wwn_t pwwn; /* port wwn of rport */ wwn_t nwwn; /* node wwn of rport */ struct bfa_rport_symname_s psym_name; /* port symbolic name */ - bfa_sm_t sm; /* state machine */ + bfa_fcs_rport_sm_t sm; /* state machine */ struct bfa_timer_s timer; /* general purpose timer */ struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */ struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */ @@ -487,13 +651,35 @@ void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport); void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport); void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport); +/* + * fcs_itnim_sm FCS itnim state machine events + */ +enum bfa_fcs_itnim_event { + BFA_FCS_ITNIM_SM_FCS_ONLINE = 1, /* rport online event */ + BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */ + BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */ + BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */ + BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */ + BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */ + BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ + BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ + BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ + BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ + BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ + BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ + BFA_FCS_ITNIM_SM_HAL_ONLINE = 13, /* bfa rport online event */ +}; + +struct bfa_fcs_itnim_s; +typedef void (*bfa_fcs_itnim_sm_t)(struct bfa_fcs_itnim_s *, enum bfa_fcs_itnim_event); + /* * forward declarations */ struct bfad_itnim_s; struct bfa_fcs_itnim_s { - bfa_sm_t sm; /* state machine */ + bfa_fcs_itnim_sm_t sm; /* state machine */ struct bfa_fcs_rport_s *rport; /* parent remote rport */ struct bfad_itnim_s *itnim_drv; /* driver peer instance */ struct bfa_fcs_s *fcs; /* fcs instance */ @@ -702,78 +888,6 @@ struct bfa_fcs_s { * fcs_fabric_sm fabric state machine functions */ -/* - * Fabric state machine events - */ -enum bfa_fcs_fabric_event { - BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */ - BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */ - BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */ - BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */ - BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */ - BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */ - BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */ - BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */ - BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */ - BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */ - BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */ - BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */ - BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */ - BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ - BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ - BFA_FCS_FABRIC_SM_START = 16, /* from driver */ - BFA_FCS_FABRIC_SM_STOP = 17, /* Stop from driver */ - BFA_FCS_FABRIC_SM_STOPCOMP = 18, /* Stop completion */ - BFA_FCS_FABRIC_SM_LOGOCOMP = 19, /* FLOGO completion */ -}; - -/* - * fcs_rport_sm FCS rport state machine events - */ - -enum rport_event { - RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */ - RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */ - RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */ - RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */ - RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ - RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ - RPSM_EVENT_DELETE = 7, /* RPORT delete request */ - RPSM_EVENT_FAB_SCN = 8, /* state change notification */ - RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */ - RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ - RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ - RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */ - RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ - RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ - RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ - RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ - RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ - RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continuously */ - RPSM_EVENT_SCN_OFFLINE = 19, /* loop scn offline */ - RPSM_EVENT_SCN_ONLINE = 20, /* loop scn online */ - RPSM_EVENT_FC4_FCS_ONLINE = 21, /* FC-4 FCS online complete */ -}; - -/* - * fcs_itnim_sm FCS itnim state machine events - */ -enum bfa_fcs_itnim_event { - BFA_FCS_ITNIM_SM_FCS_ONLINE = 1, /* rport online event */ - BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */ - BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */ - BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */ - BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */ - BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */ - BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ - BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ - BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ - BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ - BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ - BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ - BFA_FCS_ITNIM_SM_HAL_ONLINE = 13, /* bfa rport online event */ -}; - /* * bfa fcs API functions */ diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c index c7de62baeec9..40e65ab28504 100644 --- a/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -16,6 +16,7 @@ #include "bfa_fcs.h" #include "bfa_fcbuild.h" #include "bfad_im.h" +#include "bfa_fcpim.h" BFA_TRC_FILE(FCS, FCPIM); @@ -52,7 +53,23 @@ static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static struct bfa_sm_table_s itnim_sm_table[] = { +struct bfa_fcs_itnim_sm_table_s { + bfa_fcs_itnim_sm_t sm; /* state machine function */ + enum bfa_itnim_state state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static inline enum bfa_itnim_state +bfa_fcs_itnim_sm_to_state(struct bfa_fcs_itnim_sm_table_s *smt, bfa_fcs_itnim_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +static struct bfa_fcs_itnim_sm_table_s itnim_sm_table[] = { {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE}, {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND}, {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT}, @@ -665,7 +682,7 @@ bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) { bfa_trc(itnim->fcs, itnim->rport->pid); - switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) { + switch (bfa_fcs_itnim_sm_to_state(itnim_sm_table, itnim->sm)) { case BFA_ITNIM_ONLINE: case BFA_ITNIM_INITIATIOR: return BFA_STATUS_OK; @@ -765,7 +782,7 @@ bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, if (itnim == NULL) return BFA_STATUS_NO_FCPIM_NEXUS; - attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); + attr->state = bfa_fcs_itnim_sm_to_state(itnim_sm_table, itnim->sm); attr->retry = itnim->seq_rec; attr->rec_support = itnim->rec_support; attr->conf_comp = itnim->conf_comp; diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 008afd817087..966bf6cc6dd9 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -103,19 +103,6 @@ static struct { }, }; -/* - * fcs_port_sm FCS logical port state machine - */ - -enum bfa_fcs_lport_event { - BFA_FCS_PORT_SM_CREATE = 1, - BFA_FCS_PORT_SM_ONLINE = 2, - BFA_FCS_PORT_SM_OFFLINE = 3, - BFA_FCS_PORT_SM_DELETE = 4, - BFA_FCS_PORT_SM_DELRPORT = 5, - BFA_FCS_PORT_SM_STOP = 6, -}; - static void bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port, enum bfa_fcs_lport_event event); static void bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, @@ -1426,20 +1413,6 @@ u32 bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed); * fcs_fdmi_sm FCS FDMI state machine */ -/* - * FDMI State Machine events - */ -enum port_fdmi_event { - FDMISM_EVENT_PORT_ONLINE = 1, - FDMISM_EVENT_PORT_OFFLINE = 2, - FDMISM_EVENT_RSP_OK = 4, - FDMISM_EVENT_RSP_ERROR = 5, - FDMISM_EVENT_TIMEOUT = 6, - FDMISM_EVENT_RHBA_SENT = 7, - FDMISM_EVENT_RPRT_SENT = 8, - FDMISM_EVENT_RPA_SENT = 9, -}; - static void bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, enum port_fdmi_event event); static void bfa_fcs_lport_fdmi_sm_sending_rhba( @@ -2863,19 +2836,6 @@ static void bfa_fcs_lport_ms_gfn_response(void *fcsarg, * fcs_ms_sm FCS MS state machine */ -/* - * MS State Machine events - */ -enum port_ms_event { - MSSM_EVENT_PORT_ONLINE = 1, - MSSM_EVENT_PORT_OFFLINE = 2, - MSSM_EVENT_RSP_OK = 3, - MSSM_EVENT_RSP_ERROR = 4, - MSSM_EVENT_TIMEOUT = 5, - MSSM_EVENT_FCXP_SENT = 6, - MSSM_EVENT_PORT_FABRIC_RSCN = 7 -}; - static void bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms, enum port_ms_event event); static void bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms, @@ -3644,25 +3604,6 @@ static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port); * fcs_ns_sm FCS nameserver interface state machine */ -/* - * VPort NS State Machine events - */ -enum vport_ns_event { - NSSM_EVENT_PORT_ONLINE = 1, - NSSM_EVENT_PORT_OFFLINE = 2, - NSSM_EVENT_PLOGI_SENT = 3, - NSSM_EVENT_RSP_OK = 4, - NSSM_EVENT_RSP_ERROR = 5, - NSSM_EVENT_TIMEOUT = 6, - NSSM_EVENT_NS_QUERY = 7, - NSSM_EVENT_RSPNID_SENT = 8, - NSSM_EVENT_RFTID_SENT = 9, - NSSM_EVENT_RFFID_SENT = 10, - NSSM_EVENT_GIDFT_SENT = 11, - NSSM_EVENT_RNNID_SENT = 12, - NSSM_EVENT_RSNN_NN_SENT = 13, -}; - static void bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns, enum vport_ns_event event); static void bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns, @@ -5239,18 +5180,6 @@ static void bfa_fcs_lport_scn_timeout(void *arg); * fcs_scm_sm FCS SCN state machine */ -/* - * VPort SCN State Machine events - */ -enum port_scn_event { - SCNSM_EVENT_PORT_ONLINE = 1, - SCNSM_EVENT_PORT_OFFLINE = 2, - SCNSM_EVENT_RSP_OK = 3, - SCNSM_EVENT_RSP_ERROR = 4, - SCNSM_EVENT_TIMEOUT = 5, - SCNSM_EVENT_SCR_SENT = 6, -}; - static void bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn, enum port_scn_event event); static void bfa_fcs_lport_scn_sm_sending_scr( @@ -5989,27 +5918,6 @@ static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport); * fcs_vport_sm FCS virtual port state machine */ -/* - * VPort State Machine events - */ -enum bfa_fcs_vport_event { - BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */ - BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */ - BFA_FCS_VPORT_SM_START = 3, /* vport start request */ - BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */ - BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */ - BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */ - BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */ - BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */ - BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */ - BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */ - BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ - BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ - BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ - BFA_FCS_VPORT_SM_STOPCOMP = 14, /* vport delete completion */ - BFA_FCS_VPORT_SM_FABRIC_MAX = 15, /* max vports on fabric */ -}; - static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, @@ -6037,7 +5945,23 @@ static void bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, static void bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); -static struct bfa_sm_table_s vport_sm_table[] = { +struct bfa_fcs_vport_sm_table_s { + bfa_fcs_vport_sm_t sm; /* state machine function */ + enum bfa_vport_state state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static inline enum bfa_vport_state +bfa_vport_sm_to_state(struct bfa_fcs_vport_sm_table_s *smt, bfa_fcs_vport_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +static struct bfa_fcs_vport_sm_table_s vport_sm_table[] = { {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, {BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED}, {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, @@ -6864,7 +6788,7 @@ bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, memset(attr, 0, sizeof(struct bfa_vport_attr_s)); bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr); - attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm); + attr->vport_state = bfa_vport_sm_to_state(vport_sm_table, vport->sm); } diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index c21aa37b8adb..ce52a9c88ae6 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -136,7 +136,23 @@ static void bfa_fcs_rport_sm_fc4_off_delete(struct bfa_fcs_rport_s *rport, static void bfa_fcs_rport_sm_delete_pending(struct bfa_fcs_rport_s *rport, enum rport_event event); -static struct bfa_sm_table_s rport_sm_table[] = { +struct bfa_fcs_rport_sm_table_s { + bfa_fcs_rport_sm_t sm; /* state machine function */ + enum bfa_rport_state state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static inline enum bfa_rport_state +bfa_rport_sm_to_state(struct bfa_fcs_rport_sm_table_s *smt, bfa_fcs_rport_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +static struct bfa_fcs_rport_sm_table_s rport_sm_table[] = { {BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT}, {BFA_SM(bfa_fcs_rport_sm_plogi_sending), BFA_RPORT_PLOGI}, {BFA_SM(bfa_fcs_rport_sm_plogiacc_sending), BFA_RPORT_ONLINE}, @@ -2964,7 +2980,7 @@ bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport) { - return bfa_sm_to_state(rport_sm_table, rport->sm); + return bfa_rport_sm_to_state(rport_sm_table, rport->sm); } @@ -3107,20 +3123,6 @@ static void bfa_fcs_rpf_rpsc2_response(void *fcsarg, static void bfa_fcs_rpf_timeout(void *arg); -/* - * fcs_rport_ftrs_sm FCS rport state machine events - */ - -enum rpf_event { - RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */ - RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */ - RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */ - RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */ - RPFSM_EVENT_RPSC_COMP = 5, - RPFSM_EVENT_RPSC_FAIL = 6, - RPFSM_EVENT_RPSC_ERROR = 7, -}; - static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event); static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index e1ed1424fddb..ea2f107f564c 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -114,21 +114,6 @@ static enum bfi_ioc_img_ver_cmp_e bfa_ioc_flash_fwver_cmp( /* * IOC state machine definitions/declarations */ -enum ioc_event { - IOC_E_RESET = 1, /* IOC reset request */ - IOC_E_ENABLE = 2, /* IOC enable request */ - IOC_E_DISABLE = 3, /* IOC disable request */ - IOC_E_DETACH = 4, /* driver detach cleanup */ - IOC_E_ENABLED = 5, /* f/w enabled */ - IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ - IOC_E_DISABLED = 7, /* f/w disabled */ - IOC_E_PFFAILED = 8, /* failure notice by iocpf sm */ - IOC_E_HBFAIL = 9, /* heartbeat failure */ - IOC_E_HWERROR = 10, /* hardware error interrupt */ - IOC_E_TIMEOUT = 11, /* timeout */ - IOC_E_HWFAILED = 12, /* PCI mapping failure notice */ -}; - bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event); @@ -140,7 +125,13 @@ bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event); -static struct bfa_sm_table_s ioc_sm_table[] = { +struct bfa_ioc_sm_table { + bfa_ioc_sm_t sm; /* state machine function */ + enum bfa_ioc_state state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static struct bfa_ioc_sm_table ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING}, @@ -153,6 +144,16 @@ static struct bfa_sm_table_s ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL}, }; +static inline enum bfa_ioc_state +bfa_ioc_sm_to_state(struct bfa_ioc_sm_table *smt, bfa_ioc_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + /* * IOCPF state machine definitions/declarations */ @@ -178,24 +179,6 @@ static void bfa_iocpf_timeout(void *ioc_arg); static void bfa_iocpf_sem_timeout(void *ioc_arg); static void bfa_iocpf_poll_timeout(void *ioc_arg); -/* - * IOCPF state machine events - */ -enum iocpf_event { - IOCPF_E_ENABLE = 1, /* IOCPF enable request */ - IOCPF_E_DISABLE = 2, /* IOCPF disable request */ - IOCPF_E_STOP = 3, /* stop on driver detach */ - IOCPF_E_FWREADY = 4, /* f/w initialization done */ - IOCPF_E_FWRSP_ENABLE = 5, /* enable f/w response */ - IOCPF_E_FWRSP_DISABLE = 6, /* disable f/w response */ - IOCPF_E_FAIL = 7, /* failure notice by ioc sm */ - IOCPF_E_INITFAIL = 8, /* init fail notice by ioc sm */ - IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ - IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ - IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ - IOCPF_E_SEM_ERROR = 12, /* h/w sem mapping error */ -}; - /* * IOCPF states */ @@ -228,7 +211,23 @@ bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf_s, enum iocpf_event); bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event); -static struct bfa_sm_table_s iocpf_sm_table[] = { +struct bfa_iocpf_sm_table { + bfa_iocpf_sm_t sm; /* state machine function */ + enum bfa_iocpf_state state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static inline enum bfa_iocpf_state +bfa_iocpf_sm_to_state(struct bfa_iocpf_sm_table *smt, bfa_iocpf_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +static struct bfa_iocpf_sm_table iocpf_sm_table[] = { {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, @@ -2815,12 +2814,12 @@ enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc) { enum bfa_iocpf_state iocpf_st; - enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm); + enum bfa_ioc_state ioc_st = bfa_ioc_sm_to_state(ioc_sm_table, ioc->fsm); if (ioc_st == BFA_IOC_ENABLING || ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) { - iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); + iocpf_st = bfa_iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); switch (iocpf_st) { case BFA_IOCPF_SEMWAIT: @@ -5805,18 +5804,6 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) } } -/* - * DCONF state machine events - */ -enum bfa_dconf_event { - BFA_DCONF_SM_INIT = 1, /* dconf Init */ - BFA_DCONF_SM_FLASH_COMP = 2, /* read/write to flash */ - BFA_DCONF_SM_WR = 3, /* binding change, map */ - BFA_DCONF_SM_TIMEOUT = 4, /* Start timer */ - BFA_DCONF_SM_EXIT = 5, /* exit dconf module */ - BFA_DCONF_SM_IOCDISABLE = 6, /* IOC disable event */ -}; - /* forward declaration of DCONF state machine */ static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event); diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 5e568d6d7b26..3ec10503caff 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -260,6 +260,24 @@ struct bfa_ioc_cbfn_s { /* * IOC event notification mechanism. */ +enum ioc_event { + IOC_E_RESET = 1, /* IOC reset request */ + IOC_E_ENABLE = 2, /* IOC enable request */ + IOC_E_DISABLE = 3, /* IOC disable request */ + IOC_E_DETACH = 4, /* driver detach cleanup */ + IOC_E_ENABLED = 5, /* f/w enabled */ + IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ + IOC_E_DISABLED = 7, /* f/w disabled */ + IOC_E_PFFAILED = 8, /* failure notice by iocpf sm */ + IOC_E_HBFAIL = 9, /* heartbeat failure */ + IOC_E_HWERROR = 10, /* hardware error interrupt */ + IOC_E_TIMEOUT = 11, /* timeout */ + IOC_E_HWFAILED = 12, /* PCI mapping failure notice */ +}; + +struct bfa_ioc_s; +typedef void (*bfa_ioc_sm_t)(struct bfa_ioc_s *fsm, enum ioc_event); + enum bfa_ioc_event_e { BFA_IOC_E_ENABLED = 1, BFA_IOC_E_DISABLED = 2, @@ -282,8 +300,29 @@ struct bfa_ioc_notify_s { (__notify)->cbarg = (__cbarg); \ } while (0) +/* + * IOCPF state machine events + */ +enum iocpf_event { + IOCPF_E_ENABLE = 1, /* IOCPF enable request */ + IOCPF_E_DISABLE = 2, /* IOCPF disable request */ + IOCPF_E_STOP = 3, /* stop on driver detach */ + IOCPF_E_FWREADY = 4, /* f/w initialization done */ + IOCPF_E_FWRSP_ENABLE = 5, /* enable f/w response */ + IOCPF_E_FWRSP_DISABLE = 6, /* disable f/w response */ + IOCPF_E_FAIL = 7, /* failure notice by ioc sm */ + IOCPF_E_INITFAIL = 8, /* init fail notice by ioc sm */ + IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ + IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ + IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ + IOCPF_E_SEM_ERROR = 12, /* h/w sem mapping error */ +}; + +struct bfa_iocpf_s; +typedef void (*bfa_iocpf_sm_t)(struct bfa_iocpf_s *fsm, enum iocpf_event); + struct bfa_iocpf_s { - bfa_fsm_t fsm; + bfa_iocpf_sm_t fsm; struct bfa_ioc_s *ioc; bfa_boolean_t fw_mismatch_notified; bfa_boolean_t auto_recover; @@ -291,7 +330,7 @@ struct bfa_iocpf_s { }; struct bfa_ioc_s { - bfa_fsm_t fsm; + bfa_ioc_sm_t fsm; struct bfa_s *bfa; struct bfa_pcidev_s pcidev; struct bfa_timer_mod_s *timer_mod; @@ -379,22 +418,6 @@ struct bfa_cb_qe_s { void *cbarg; }; -/* - * IOCFC state machine definitions/declarations - */ -enum iocfc_event { - IOCFC_E_INIT = 1, /* IOCFC init request */ - IOCFC_E_START = 2, /* IOCFC mod start request */ - IOCFC_E_STOP = 3, /* IOCFC stop request */ - IOCFC_E_ENABLE = 4, /* IOCFC enable request */ - IOCFC_E_DISABLE = 5, /* IOCFC disable request */ - IOCFC_E_IOC_ENABLED = 6, /* IOC enabled message */ - IOCFC_E_IOC_DISABLED = 7, /* IOC disabled message */ - IOCFC_E_IOC_FAILED = 8, /* failure notice by IOC sm */ - IOCFC_E_DCONF_DONE = 9, /* dconf read/write done */ - IOCFC_E_CFG_DONE = 10, /* IOCFC config complete */ -}; - /* * ASIC block configurtion related */ @@ -779,8 +802,23 @@ struct bfa_dconf_s { }; #pragma pack() +/* + * DCONF state machine events + */ +enum bfa_dconf_event { + BFA_DCONF_SM_INIT = 1, /* dconf Init */ + BFA_DCONF_SM_FLASH_COMP = 2, /* read/write to flash */ + BFA_DCONF_SM_WR = 3, /* binding change, map */ + BFA_DCONF_SM_TIMEOUT = 4, /* Start timer */ + BFA_DCONF_SM_EXIT = 5, /* exit dconf module */ + BFA_DCONF_SM_IOCDISABLE = 6, /* IOC disable event */ +}; + +struct bfa_dconf_mod_s; +typedef void (*bfa_dconf_sm_t)(struct bfa_dconf_mod_s *fsm, enum bfa_dconf_event); + struct bfa_dconf_mod_s { - bfa_sm_t sm; + bfa_dconf_sm_t sm; u8 instance; bfa_boolean_t read_data_valid; bfa_boolean_t min_cfg; diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index c9745c0b4eee..9f33aa303b18 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -40,36 +40,6 @@ BFA_TRC_FILE(HAL, FCXP); ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \ (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE)) -/* - * BFA port state machine events - */ -enum bfa_fcport_sm_event { - BFA_FCPORT_SM_START = 1, /* start port state machine */ - BFA_FCPORT_SM_STOP = 2, /* stop port state machine */ - BFA_FCPORT_SM_ENABLE = 3, /* enable port */ - BFA_FCPORT_SM_DISABLE = 4, /* disable port state machine */ - BFA_FCPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */ - BFA_FCPORT_SM_LINKUP = 6, /* firmware linkup event */ - BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ - BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ - BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ - BFA_FCPORT_SM_DPORTENABLE = 10, /* enable dport */ - BFA_FCPORT_SM_DPORTDISABLE = 11,/* disable dport */ - BFA_FCPORT_SM_FAA_MISCONFIG = 12, /* FAA misconfiguratin */ - BFA_FCPORT_SM_DDPORTENABLE = 13, /* enable ddport */ - BFA_FCPORT_SM_DDPORTDISABLE = 14, /* disable ddport */ -}; - -/* - * BFA port link notification state machine events - */ - -enum bfa_fcport_ln_sm_event { - BFA_FCPORT_LN_SM_LINKUP = 1, /* linkup event */ - BFA_FCPORT_LN_SM_LINKDOWN = 2, /* linkdown event */ - BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */ -}; - /* * RPORT related definitions */ @@ -201,7 +171,23 @@ static void bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, static void bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, enum bfa_fcport_ln_sm_event event); -static struct bfa_sm_table_s hal_port_sm_table[] = { +struct bfa_fcport_sm_table_s { + bfa_fcport_sm_t sm; /* state machine function */ + enum bfa_port_states state; /* state machine encoding */ + char *name; /* state name for display */ +}; + +static inline enum bfa_port_states +bfa_fcport_sm_to_state(struct bfa_fcport_sm_table_s *smt, bfa_fcport_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +static struct bfa_fcport_sm_table_s hal_port_sm_table[] = { {BFA_SM(bfa_fcport_sm_uninit), BFA_PORT_ST_UNINIT}, {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PORT_ST_ENABLING_QWAIT}, {BFA_SM(bfa_fcport_sm_enabling), BFA_PORT_ST_ENABLING}, @@ -3545,7 +3531,7 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) fcport->event_arg.i2hmsg = i2hmsg; bfa_trc(bfa, msg->mhdr.msg_id); - bfa_trc(bfa, bfa_sm_to_state(hal_port_sm_table, fcport->sm)); + bfa_trc(bfa, bfa_fcport_sm_to_state(hal_port_sm_table, fcport->sm)); switch (msg->mhdr.msg_id) { case BFI_FCPORT_I2H_ENABLE_RSP: @@ -3980,7 +3966,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); - attr->port_state = bfa_sm_to_state(hal_port_sm_table, fcport->sm); + attr->port_state = bfa_fcport_sm_to_state(hal_port_sm_table, fcport->sm); attr->fec_state = fcport->fec_state; @@ -4062,7 +4048,7 @@ bfa_fcport_is_disabled(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - return bfa_sm_to_state(hal_port_sm_table, fcport->sm) == + return bfa_fcport_sm_to_state(hal_port_sm_table, fcport->sm) == BFA_PORT_ST_DISABLED; } @@ -4072,7 +4058,7 @@ bfa_fcport_is_dport(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - return (bfa_sm_to_state(hal_port_sm_table, fcport->sm) == + return (bfa_fcport_sm_to_state(hal_port_sm_table, fcport->sm) == BFA_PORT_ST_DPORT); } @@ -4081,7 +4067,7 @@ bfa_fcport_is_ddport(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - return (bfa_sm_to_state(hal_port_sm_table, fcport->sm) == + return (bfa_fcport_sm_to_state(hal_port_sm_table, fcport->sm) == BFA_PORT_ST_DDPORT); } @@ -5641,20 +5627,6 @@ enum bfa_dport_test_state_e { BFA_DPORT_ST_NOTSTART = 4, /*!< test not start dport is enabled */ }; -/* - * BFA DPORT state machine events - */ -enum bfa_dport_sm_event { - BFA_DPORT_SM_ENABLE = 1, /* dport enable event */ - BFA_DPORT_SM_DISABLE = 2, /* dport disable event */ - BFA_DPORT_SM_FWRSP = 3, /* fw enable/disable rsp */ - BFA_DPORT_SM_QRESUME = 4, /* CQ space available */ - BFA_DPORT_SM_HWFAIL = 5, /* IOC h/w failure */ - BFA_DPORT_SM_START = 6, /* re-start dport test */ - BFA_DPORT_SM_REQFAIL = 7, /* request failure */ - BFA_DPORT_SM_SCN = 8, /* state change notify frm fw */ -}; - static void bfa_dport_sm_disabled(struct bfa_dport_s *dport, enum bfa_dport_sm_event event); static void bfa_dport_sm_enabling_qwait(struct bfa_dport_s *dport, diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 9c83109574e9..26eeee82bedc 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -226,22 +226,6 @@ struct bfa_fcxp_wqe_s { void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -/* - * RPORT related defines - */ -enum bfa_rport_event { - BFA_RPORT_SM_CREATE = 1, /* rport create event */ - BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */ - BFA_RPORT_SM_ONLINE = 3, /* rport is online */ - BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */ - BFA_RPORT_SM_FWRSP = 5, /* firmware response */ - BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */ - BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */ - BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */ - BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */ -}; - #define BFA_RPORT_MIN 4 struct bfa_rport_mod_s { @@ -284,12 +268,30 @@ struct bfa_rport_info_s { enum bfa_port_speed speed; /* Rport's current speed */ }; +/* + * RPORT related defines + */ +enum bfa_rport_event { + BFA_RPORT_SM_CREATE = 1, /* rport create event */ + BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */ + BFA_RPORT_SM_ONLINE = 3, /* rport is online */ + BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */ + BFA_RPORT_SM_FWRSP = 5, /* firmware response */ + BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */ + BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */ + BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */ + BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */ +}; + +struct bfa_rport_s; +typedef void (*bfa_rport_sm_t)(struct bfa_rport_s *, enum bfa_rport_event); + /* * BFA rport data structure */ struct bfa_rport_s { struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ + bfa_rport_sm_t sm; /* state machine */ struct bfa_s *bfa; /* backpointer to BFA */ void *rport_drv; /* fcs/driver rport object */ u16 fw_handle; /* firmware rport handle */ @@ -377,13 +379,31 @@ struct bfa_uf_mod_s { void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw); +/* + * lps_pvt BFA LPS private functions + */ + +enum bfa_lps_event { + BFA_LPS_SM_LOGIN = 1, /* login request from user */ + BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ + BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ + BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ + BFA_LPS_SM_DELETE = 5, /* lps delete from user */ + BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ + BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ + BFA_LPS_SM_SET_N2N_PID = 8, /* Set assigned PID for n2n */ +}; + +struct bfa_lps_s; +typedef void (*bfa_lps_sm_t)(struct bfa_lps_s *, enum bfa_lps_event); + /* * LPS - bfa lport login/logout service interface */ struct bfa_lps_s { struct list_head qe; /* queue element */ struct bfa_s *bfa; /* parent bfa instance */ - bfa_sm_t sm; /* finite state machine */ + bfa_lps_sm_t sm; /* finite state machine */ u8 bfa_tag; /* lport tag */ u8 fw_tag; /* lport fw tag */ u8 reqq; /* lport request queue */ @@ -439,12 +459,25 @@ void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); #define BFA_FCPORT(_bfa) (&((_bfa)->modules.port)) +/* + * BFA port link notification state machine events + */ + +enum bfa_fcport_ln_sm_event { + BFA_FCPORT_LN_SM_LINKUP = 1, /* linkup event */ + BFA_FCPORT_LN_SM_LINKDOWN = 2, /* linkdown event */ + BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */ +}; + +struct bfa_fcport_ln_s; +typedef void (*bfa_fcport_ln_sm_t)(struct bfa_fcport_ln_s *, enum bfa_fcport_ln_sm_event); + /* * Link notification data structure */ struct bfa_fcport_ln_s { struct bfa_fcport_s *fcport; - bfa_sm_t sm; + bfa_fcport_ln_sm_t sm; struct bfa_cb_qe_s ln_qe; /* BFA callback queue elem for ln */ enum bfa_port_linkstate ln_event; /* ln event for callback */ }; @@ -453,12 +486,35 @@ struct bfa_fcport_trunk_s { struct bfa_trunk_attr_s attr; }; +/* + * BFA port state machine events + */ +enum bfa_fcport_sm_event { + BFA_FCPORT_SM_START = 1, /* start port state machine */ + BFA_FCPORT_SM_STOP = 2, /* stop port state machine */ + BFA_FCPORT_SM_ENABLE = 3, /* enable port */ + BFA_FCPORT_SM_DISABLE = 4, /* disable port state machine */ + BFA_FCPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */ + BFA_FCPORT_SM_LINKUP = 6, /* firmware linkup event */ + BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ + BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ + BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ + BFA_FCPORT_SM_DPORTENABLE = 10, /* enable dport */ + BFA_FCPORT_SM_DPORTDISABLE = 11,/* disable dport */ + BFA_FCPORT_SM_FAA_MISCONFIG = 12, /* FAA misconfiguratin */ + BFA_FCPORT_SM_DDPORTENABLE = 13, /* enable ddport */ + BFA_FCPORT_SM_DDPORTDISABLE = 14, /* disable ddport */ +}; + +struct bfa_fcport_s; +typedef void (*bfa_fcport_sm_t)(struct bfa_fcport_s *, enum bfa_fcport_sm_event); + /* * BFA FC port data structure */ struct bfa_fcport_s { struct bfa_s *bfa; /* parent BFA instance */ - bfa_sm_t sm; /* port state machine */ + bfa_fcport_sm_t sm; /* port state machine */ wwn_t nwwn; /* node wwn of physical port */ wwn_t pwwn; /* port wwn of physical oprt */ enum bfa_port_speed speed_sup; @@ -706,9 +762,26 @@ struct bfa_fcdiag_lb_s { u32 status; }; +/* + * BFA DPORT state machine events + */ +enum bfa_dport_sm_event { + BFA_DPORT_SM_ENABLE = 1, /* dport enable event */ + BFA_DPORT_SM_DISABLE = 2, /* dport disable event */ + BFA_DPORT_SM_FWRSP = 3, /* fw enable/disable rsp */ + BFA_DPORT_SM_QRESUME = 4, /* CQ space available */ + BFA_DPORT_SM_HWFAIL = 5, /* IOC h/w failure */ + BFA_DPORT_SM_START = 6, /* re-start dport test */ + BFA_DPORT_SM_REQFAIL = 7, /* request failure */ + BFA_DPORT_SM_SCN = 8, /* state change notify frm fw */ +}; + +struct bfa_dport_s; +typedef void (*bfa_dport_sm_t)(struct bfa_dport_s *, enum bfa_dport_sm_event); + struct bfa_dport_s { struct bfa_s *bfa; /* Back pointer to BFA */ - bfa_sm_t sm; /* finite state machine */ + bfa_dport_sm_t sm; /* finite state machine */ struct bfa_reqq_wait_s reqq_wait; bfa_cb_diag_t cbfn; void *cbarg; diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 7682cfa34265..da42e3261237 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -175,11 +175,27 @@ union bfad_tmp_buf { wwn_t wwn[BFA_FCS_MAX_LPORTS]; }; +/* BFAD state machine events */ +enum bfad_sm_event { + BFAD_E_CREATE = 1, + BFAD_E_KTHREAD_CREATE_FAILED = 2, + BFAD_E_INIT = 3, + BFAD_E_INIT_SUCCESS = 4, + BFAD_E_HAL_INIT_FAILED = 5, + BFAD_E_INIT_FAILED = 6, + BFAD_E_FCS_EXIT_COMP = 7, + BFAD_E_EXIT_COMP = 8, + BFAD_E_STOP = 9 +}; + +struct bfad_s; +typedef void (*bfad_sm_t)(struct bfad_s *, enum bfad_sm_event); + /* * BFAD (PCI function) data structure */ struct bfad_s { - bfa_sm_t sm; /* state machine */ + bfad_sm_t sm; /* state machine */ struct list_head list_entry; struct bfa_s bfa; struct bfa_fcs_s bfa_fcs; @@ -226,19 +242,6 @@ struct bfad_s { struct list_head vport_list; }; -/* BFAD state machine events */ -enum bfad_sm_event { - BFAD_E_CREATE = 1, - BFAD_E_KTHREAD_CREATE_FAILED = 2, - BFAD_E_INIT = 3, - BFAD_E_INIT_SUCCESS = 4, - BFAD_E_HAL_INIT_FAILED = 5, - BFAD_E_INIT_FAILED = 6, - BFAD_E_FCS_EXIT_COMP = 7, - BFAD_E_EXIT_COMP = 8, - BFAD_E_STOP = 9 -}; - /* * RPORT data structure */ From e100c01efa85c8a0ee7527bf28ef7ea7c3ca57e1 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 26 Feb 2024 23:53:44 +0000 Subject: [PATCH 539/814] scsi: lpfc: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect ae->value_string to be NUL-terminated because there's a comment that says as much; these attr strings are also used with other string APIs, further cementing the fact. Now, the question of whether or not to NUL-pad the destination buffer: lpfc_fdmi_rprt_defer() initializes vports (all zero-initialized), then we call lpfc_fdmi_cmd() with each vport and a mask. Then, inside of lpfc_fdmi_cmd() we check each bit in the mask to invoke the proper callback. Importantly, the zero-initialized vport is passed in as the "attr" parameter. Seeing this: | struct lpfc_fdmi_attr_string *ae = attr; ... we can tell that ae->value_string is entirely zero-initialized. Due to this, NUL-padding is _not_ required as it would be redundant. Considering the above, a suitable replacement is strscpy() [2]. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20240226-strncpy-drivers-scsi-lpfc-lpfc_ct-c-v2-1-2df2e46569b9@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index b30765b9689a..8cc08e58dc05 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -2553,9 +2553,9 @@ lpfc_fdmi_set_attr_string(void *attr, uint16_t attrtype, char *attrstring) * 64 bytes or less. */ - strncpy(ae->value_string, attrstring, sizeof(ae->value_string)); + strscpy(ae->value_string, attrstring, sizeof(ae->value_string)); len = strnlen(ae->value_string, sizeof(ae->value_string)); - /* round string length to a 32bit boundary. Ensure there's a NULL */ + /* round string length to a 32bit boundary */ len += (len & 3) ? (4 - (len & 3)) : 4; /* size is Type/Len (4 bytes) plus string length */ size = FOURBYTES + len; From 3e24118ec1859afe2df18062e1ebdabc12e3b8c1 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 21 Feb 2024 23:50:26 +0000 Subject: [PATCH 540/814] scsi: libfc: replace deprecated strncpy() with memcpy() strncpy() is deprecated [1] and as such we should use different apis to copy string data. We can see that ct is NUL-initialized with fc_ct_hdr_fill: | ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len, ... In fc_ct_hdr_fill(): | memset(ct, 0, ct_plen); We also calculate the length of the source string: | len = strnlen(fc_host_symbolic_name(lport->host), 255); ...then this argument is used in strncpy(), which is bad because the pattern of (dest, src, strlen(src)) usually leaves the destination buffer without NUL-termination. However, it looks as though we do not require NUL-termination since fr_name is part of a seq_buf-like structure wherein its length is monitored: | struct fc_ns_rspn { | struct fc_ns_fid fr_fid; /* port ID object */ | __u8 fr_name_len; | char fr_name[]; | } __attribute__((__packed__)); So, this is really just a byte copy into a length-bounded buffer. Let's use memcpy(). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20240221-strncpy-drivers-scsi-libfc-fc_encode-h-v2-1-019a0889c5ca@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_encode.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libfc/fc_encode.h b/drivers/scsi/libfc/fc_encode.h index 7dcac3b6baa7..6b7e4ca6b7b5 100644 --- a/drivers/scsi/libfc/fc_encode.h +++ b/drivers/scsi/libfc/fc_encode.h @@ -136,22 +136,24 @@ static inline int fc_ct_ns_fill(struct fc_lport *lport, break; case FC_NS_RSPN_ID: - len = strnlen(fc_host_symbolic_name(lport->host), 255); + len = strnlen(fc_host_symbolic_name(lport->host), + FC_SYMBOLIC_NAME_SIZE); ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len, FC_FST_DIR, FC_NS_SUBTYPE); hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id); - strncpy(ct->payload.spn.fr_name, - fc_host_symbolic_name(lport->host), len); + memcpy(ct->payload.spn.fr_name, + fc_host_symbolic_name(lport->host), len); ct->payload.spn.fr_name_len = len; break; case FC_NS_RSNN_NN: - len = strnlen(fc_host_symbolic_name(lport->host), 255); + len = strnlen(fc_host_symbolic_name(lport->host), + FC_SYMBOLIC_NAME_SIZE); ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len, FC_FST_DIR, FC_NS_SUBTYPE); put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn); - strncpy(ct->payload.snn.fr_name, - fc_host_symbolic_name(lport->host), len); + memcpy(ct->payload.snn.fr_name, + fc_host_symbolic_name(lport->host), len); ct->payload.snn.fr_name_len = len; break; From 517bcc2b4db435f230fe864f3db0a0f21d2f6951 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 19 Feb 2024 08:45:53 -0300 Subject: [PATCH 541/814] scsi: core: Constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the scsi_host_type, scsi_target_type and scsi_dev_type variables to be constant structures as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240219-device_cleanup-scsi-v1-1-c5edf2afe178@marliere.net Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 2 +- drivers/scsi/scsi_scan.c | 2 +- drivers/scsi/scsi_sysfs.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index d7f51b84f3c7..4f495a41ec4a 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -371,7 +371,7 @@ static void scsi_host_dev_release(struct device *dev) kfree(shost); } -static struct device_type scsi_host_type = { +static const struct device_type scsi_host_type = { .name = "scsi_host", .release = scsi_host_dev_release, }; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 70c0319be34c..44c1956b1720 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -412,7 +412,7 @@ static void scsi_target_dev_release(struct device *dev) put_device(parent); } -static struct device_type scsi_target_type = { +static const struct device_type scsi_target_type = { .name = "scsi_target", .release = scsi_target_dev_release, }; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 14d0be0da0c6..49dd34426d5e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -27,7 +27,7 @@ #include "scsi_priv.h" #include "scsi_logging.h" -static struct device_type scsi_dev_type; +static const struct device_type scsi_dev_type; static const struct { enum scsi_device_state value; @@ -1626,7 +1626,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) return 0; } -static struct device_type scsi_dev_type = { +static const struct device_type scsi_dev_type = { .name = "scsi_device", .release = scsi_device_dev_release, .groups = scsi_sdev_attr_groups, From 8e24eeedfda34a920d35eda2f17a0f4b4473dcde Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Fri, 23 Feb 2024 12:21:02 -0800 Subject: [PATCH 542/814] KVM: VMX: fix comment to add LBR to passthrough MSRs According to the is_valid_passthrough_msr(), the LBR MSRs are also passthrough MSRs, since the commit 1b5ac3226a1a ("KVM: vmx/pmu: Pass-through LBR msrs when the guest LBR event is ACTIVE"). Signed-off-by: Dongli Zhang Link: https://lore.kernel.org/r/20240223202104.3330974-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index d4e6625e0a9a..05319b74bd3d 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -159,7 +159,7 @@ module_param(allow_smaller_maxphyaddr, bool, S_IRUGO); /* * List of MSRs that can be directly passed to the guest. - * In addition to these x2apic and PT MSRs are handled specially. + * In addition to these x2apic, PT and LBR MSRs are handled specially. */ static u32 vmx_possible_passthrough_msrs[MAX_POSSIBLE_PASSTHROUGH_MSRS] = { MSR_IA32_SPEC_CTRL, From bab22040d7fdeb935e57215a183912ba46eee7f0 Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Fri, 23 Feb 2024 12:21:03 -0800 Subject: [PATCH 543/814] KVM: VMX: return early if msr_bitmap is not supported The vmx_msr_filter_changed() may directly/indirectly calls only vmx_enable_intercept_for_msr() or vmx_disable_intercept_for_msr(). Those two functions may exit immediately if !cpu_has_vmx_msr_bitmap(). vmx_msr_filter_changed() -> vmx_disable_intercept_for_msr() -> pt_update_intercept_for_msr() -> vmx_set_intercept_for_msr() -> vmx_enable_intercept_for_msr() -> vmx_disable_intercept_for_msr() Therefore, we exit early if !cpu_has_vmx_msr_bitmap(). Signed-off-by: Dongli Zhang Link: https://lore.kernel.org/r/20240223202104.3330974-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 05319b74bd3d..5a866d3c2bc8 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4127,6 +4127,9 @@ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); u32 i; + if (!cpu_has_vmx_msr_bitmap()) + return; + /* * Redo intercept permissions for MSRs that KVM is passing through to * the guest. Disabling interception will check the new MSR filter and From 29ef55cec33de325562c6c056b167f58d61ddab0 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 27 Feb 2024 09:41:14 +0000 Subject: [PATCH 544/814] KVM: arm64: Fail the idreg iterator if idregs aren't initialized Return an error to userspace if the VM's ID register values haven't been initialized in preparation for changing the debugfs file initialization order. Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240227094115.1723330-2-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e3faedc8b7a3..e9319d90d66f 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3431,7 +3431,8 @@ static void *idregs_debug_start(struct seq_file *s, loff_t *pos) mutex_lock(&kvm->arch.config_lock); iter = &kvm->arch.idreg_debugfs_iter; - if (*iter == (u8)~0) { + if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags) && + *iter == (u8)~0) { *iter = *pos; if (*iter >= KVM_ARM_ID_REG_NUM) iter = NULL; From 5c1ebe9ada19f95e5582f80b37e0b5003dc79ddb Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 27 Feb 2024 09:41:15 +0000 Subject: [PATCH 545/814] KVM: arm64: Don't initialize idreg debugfs w/ preemption disabled Testing KVM with DEBUG_ATOMIC_SLEEP enabled doesn't get far before hitting the first splat: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1578 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 13062, name: vgic_lpi_stress preempt_count: 1, expected: 0 2 locks held by vgic_lpi_stress/13062: #0: ffff080084553240 (&vcpu->mutex){+.+.}-{3:3}, at: kvm_vcpu_ioctl+0xc0/0x13f0 #1: ffff800080485f08 (&kvm->arch.config_lock){+.+.}-{3:3}, at: kvm_arch_vcpu_ioctl+0xd60/0x1788 CPU: 19 PID: 13062 Comm: vgic_lpi_stress Tainted: G W O 6.8.0-dbg-DEV #1 Call trace: dump_backtrace+0xf8/0x148 show_stack+0x20/0x38 dump_stack_lvl+0xb4/0xf8 dump_stack+0x18/0x40 __might_resched+0x248/0x2a0 __might_sleep+0x50/0x88 down_write+0x30/0x150 start_creating+0x90/0x1a0 __debugfs_create_file+0x5c/0x1b0 debugfs_create_file+0x34/0x48 kvm_reset_sys_regs+0x120/0x1e8 kvm_reset_vcpu+0x148/0x270 kvm_arch_vcpu_ioctl+0xddc/0x1788 kvm_vcpu_ioctl+0xb6c/0x13f0 __arm64_sys_ioctl+0x98/0xd8 invoke_syscall+0x48/0x108 el0_svc_common+0xb4/0xf0 do_el0_svc+0x24/0x38 el0_svc+0x54/0x128 el0t_64_sync_handler+0x68/0xc0 el0t_64_sync+0x1a8/0x1b0 kvm_reset_vcpu() disables preemption as it needs to unload vCPU state from the CPU to twiddle with it, which subsequently explodes when taking the parent inode's rwsem while creating the idreg debugfs file. Fix it by moving the initialization to kvm_arch_create_vm_debugfs(). Fixes: 891766581dea ("KVM: arm64: Add debugfs file for guest's ID registers") Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20240227094115.1723330-3-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 5 +++++ arch/arm64/kvm/sys_regs.c | 13 ++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 181fef12e8e8..6883963bbc3a 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1102,6 +1102,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu); int kvm_handle_sys_reg(struct kvm_vcpu *vcpu); int kvm_handle_cp10_id(struct kvm_vcpu *vcpu); +void kvm_sys_regs_create_debugfs(struct kvm *kvm); void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); int __init kvm_sys_reg_table_init(void); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 9f806c9b7d5d..9b04dbd3aef1 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -190,6 +190,11 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } +int kvm_arch_create_vm_debugfs(struct kvm *kvm) +{ + kvm_sys_regs_create_debugfs(kvm); + return 0; +} /** * kvm_arch_destroy_vm - destroy the VM data structure diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e9319d90d66f..5d2b13953141 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3499,6 +3499,14 @@ static const struct seq_operations idregs_debug_sops = { DEFINE_SEQ_ATTRIBUTE(idregs_debug); +void kvm_sys_regs_create_debugfs(struct kvm *kvm) +{ + kvm->arch.idreg_debugfs_iter = ~0; + + debugfs_create_file("idregs", 0444, kvm->debugfs_dentry, kvm, + &idregs_debug_fops); +} + static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) { const struct sys_reg_desc *idreg = first_idreg; @@ -3518,11 +3526,6 @@ static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) id = reg_to_encoding(idreg); } - kvm->arch.idreg_debugfs_iter = ~0; - - debugfs_create_file("idregs", 0444, kvm->debugfs_dentry, kvm, - &idregs_debug_fops); - set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags); } From a364c014a2c1ad6e011bc5fdb8afb9d4ba316956 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 13 Feb 2024 11:23:40 -0800 Subject: [PATCH 546/814] kvm/x86: allocate the write-tracking metadata on-demand The write-track is used externally only by the gpu/drm/i915 driver. Currently, it is always enabled, if a kernel has been compiled with this driver. Enabling the write-track mechanism adds a two-byte overhead per page across all memory slots. It isn't significant for regular VMs. However in gVisor, where the entire process virtual address space is mapped into the VM, even with a 39-bit address space, the overhead amounts to 256MB. Rework the write-tracking mechanism to enable it on-demand in kvm_page_track_register_notifier. Here is Sean's comment about the locking scheme: The only potential hiccup would be if taking slots_arch_lock would deadlock, but it should be impossible for slots_arch_lock to be taken in any other path that involves VFIO and/or KVMGT *and* can be coincident. Except for kvm_arch_destroy_vm() (which deletes KVM's internal memslots), slots_arch_lock is taken only through KVM ioctls(), and the caller of kvm_page_track_register_notifier() *must* hold a reference to the VM. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Zhenyu Wang Co-developed-by: Sean Christopherson Signed-off-by: Andrei Vagin Link: https://lore.kernel.org/r/20240213192340.2023366-1-avagin@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 9 +++++ arch/x86/kvm/mmu/page_track.c | 68 ++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b5b2d0fde579..7d33a2605ad5 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1466,6 +1466,15 @@ struct kvm_arch { */ bool shadow_root_allocated; +#ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING + /* + * If set, the VM has (or had) an external write tracking user, and + * thus all write tracking metadata has been allocated, even if KVM + * itself isn't using write tracking. + */ + bool external_write_tracking_enabled; +#endif + #if IS_ENABLED(CONFIG_HYPERV) hpa_t hv_root_tdp; spinlock_t hv_root_tdp_lock; diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c index c87da11f3a04..f6448284c18e 100644 --- a/arch/x86/kvm/mmu/page_track.c +++ b/arch/x86/kvm/mmu/page_track.c @@ -20,10 +20,23 @@ #include "mmu_internal.h" #include "page_track.h" +static bool kvm_external_write_tracking_enabled(struct kvm *kvm) +{ +#ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING + /* + * Read external_write_tracking_enabled before related pointers. Pairs + * with the smp_store_release in kvm_page_track_write_tracking_enable(). + */ + return smp_load_acquire(&kvm->arch.external_write_tracking_enabled); +#else + return false; +#endif +} + bool kvm_page_track_write_tracking_enabled(struct kvm *kvm) { - return IS_ENABLED(CONFIG_KVM_EXTERNAL_WRITE_TRACKING) || - !tdp_enabled || kvm_shadow_root_allocated(kvm); + return kvm_external_write_tracking_enabled(kvm) || + kvm_shadow_root_allocated(kvm) || !tdp_enabled; } void kvm_page_track_free_memslot(struct kvm_memory_slot *slot) @@ -153,6 +166,50 @@ int kvm_page_track_init(struct kvm *kvm) return init_srcu_struct(&head->track_srcu); } +static int kvm_enable_external_write_tracking(struct kvm *kvm) +{ + struct kvm_memslots *slots; + struct kvm_memory_slot *slot; + int r = 0, i, bkt; + + mutex_lock(&kvm->slots_arch_lock); + + /* + * Check for *any* write tracking user (not just external users) under + * lock. This avoids unnecessary work, e.g. if KVM itself is using + * write tracking, or if two external users raced when registering. + */ + if (kvm_page_track_write_tracking_enabled(kvm)) + goto out_success; + + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { + slots = __kvm_memslots(kvm, i); + kvm_for_each_memslot(slot, bkt, slots) { + /* + * Intentionally do NOT free allocations on failure to + * avoid having to track which allocations were made + * now versus when the memslot was created. The + * metadata is guaranteed to be freed when the slot is + * freed, and will be kept/used if userspace retries + * the failed ioctl() instead of killing the VM. + */ + r = kvm_page_track_write_tracking_alloc(slot); + if (r) + goto out_unlock; + } + } + +out_success: + /* + * Ensure that external_write_tracking_enabled becomes true strictly + * after all the related pointers are set. + */ + smp_store_release(&kvm->arch.external_write_tracking_enabled, true); +out_unlock: + mutex_unlock(&kvm->slots_arch_lock); + return r; +} + /* * register the notifier so that event interception for the tracked guest * pages can be received. @@ -161,10 +218,17 @@ int kvm_page_track_register_notifier(struct kvm *kvm, struct kvm_page_track_notifier_node *n) { struct kvm_page_track_notifier_head *head; + int r; if (!kvm || kvm->mm != current->mm) return -ESRCH; + if (!kvm_external_write_tracking_enabled(kvm)) { + r = kvm_enable_external_write_tracking(kvm); + if (r) + return r; + } + kvm_get_kvm(kvm); head = &kvm->arch.track_notifier_head; From 78ccfce774435a08d9c69ce434099166cc7952c8 Mon Sep 17 00:00:00 2001 From: John Allen Date: Tue, 27 Feb 2024 20:03:56 +0000 Subject: [PATCH 547/814] KVM: SVM: Rename vmplX_ssp -> plX_ssp The SSP fields in the SEV-ES save area were mistakenly named vmplX_ssp instead of plX_ssp. Rename these to the correct names as defined in the APM. Fixes: 6d3b3d34e39e ("KVM: SVM: Update the SEV-ES save area mapping") Signed-off-by: John Allen Link: https://lore.kernel.org/r/20240227200356.35114-1-john.allen@amd.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/svm.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 87a7b917d30e..728c98175b9c 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -358,10 +358,10 @@ struct sev_es_save_area { struct vmcb_seg ldtr; struct vmcb_seg idtr; struct vmcb_seg tr; - u64 vmpl0_ssp; - u64 vmpl1_ssp; - u64 vmpl2_ssp; - u64 vmpl3_ssp; + u64 pl0_ssp; + u64 pl1_ssp; + u64 pl2_ssp; + u64 pl3_ssp; u64 u_cet; u8 reserved_0xc8[2]; u8 vmpl; From 259720c37d51aae21f70060ef96e1f1b08df0652 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 23 Feb 2024 12:21:04 -0800 Subject: [PATCH 548/814] KVM: VMX: Combine "check" and "get" APIs for passthrough MSR lookups Combine possible_passthrough_msr_slot() and is_valid_passthrough_msr() into a single function, vmx_get_passthrough_msr_slot(), and have the combined helper return the slot on success, using a negative value to indicate "failure". Combining the operations avoids iterating over the array of passthrough MSRs twice for relevant MSRs. Suggested-by: Dongli Zhang Reviewed-by: Dongli Zhang Link: https://lore.kernel.org/r/20240223202104.3330974-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 65 +++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 5a866d3c2bc8..7e7d044e0669 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -658,25 +658,14 @@ static inline bool cpu_need_virtualize_apic_accesses(struct kvm_vcpu *vcpu) return flexpriority_enabled && lapic_in_kernel(vcpu); } -static int possible_passthrough_msr_slot(u32 msr) +static int vmx_get_passthrough_msr_slot(u32 msr) { - u32 i; - - for (i = 0; i < ARRAY_SIZE(vmx_possible_passthrough_msrs); i++) - if (vmx_possible_passthrough_msrs[i] == msr) - return i; - - return -ENOENT; -} - -static bool is_valid_passthrough_msr(u32 msr) -{ - bool r; + int i; switch (msr) { case 0x800 ... 0x8ff: /* x2APIC MSRs. These are handled in vmx_update_msr_bitmap_x2apic() */ - return true; + return -ENOENT; case MSR_IA32_RTIT_STATUS: case MSR_IA32_RTIT_OUTPUT_BASE: case MSR_IA32_RTIT_OUTPUT_MASK: @@ -691,14 +680,16 @@ static bool is_valid_passthrough_msr(u32 msr) case MSR_LBR_CORE_FROM ... MSR_LBR_CORE_FROM + 8: case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8: /* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */ - return true; + return -ENOENT; } - r = possible_passthrough_msr_slot(msr) != -ENOENT; + for (i = 0; i < ARRAY_SIZE(vmx_possible_passthrough_msrs); i++) { + if (vmx_possible_passthrough_msrs[i] == msr) + return i; + } - WARN(!r, "Invalid MSR %x, please adapt vmx_possible_passthrough_msrs[]", msr); - - return r; + WARN(1, "Invalid MSR %x, please adapt vmx_possible_passthrough_msrs[]", msr); + return -ENOENT; } struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr) @@ -3954,6 +3945,7 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) { struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap; + int idx; if (!cpu_has_vmx_msr_bitmap()) return; @@ -3963,16 +3955,13 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) /* * Mark the desired intercept state in shadow bitmap, this is needed * for resync when the MSR filters change. - */ - if (is_valid_passthrough_msr(msr)) { - int idx = possible_passthrough_msr_slot(msr); - - if (idx != -ENOENT) { - if (type & MSR_TYPE_R) - clear_bit(idx, vmx->shadow_msr_intercept.read); - if (type & MSR_TYPE_W) - clear_bit(idx, vmx->shadow_msr_intercept.write); - } + */ + idx = vmx_get_passthrough_msr_slot(msr); + if (idx >= 0) { + if (type & MSR_TYPE_R) + clear_bit(idx, vmx->shadow_msr_intercept.read); + if (type & MSR_TYPE_W) + clear_bit(idx, vmx->shadow_msr_intercept.write); } if ((type & MSR_TYPE_R) && @@ -3998,6 +3987,7 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) { struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap; + int idx; if (!cpu_has_vmx_msr_bitmap()) return; @@ -4007,16 +3997,13 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) /* * Mark the desired intercept state in shadow bitmap, this is needed * for resync when the MSR filter changes. - */ - if (is_valid_passthrough_msr(msr)) { - int idx = possible_passthrough_msr_slot(msr); - - if (idx != -ENOENT) { - if (type & MSR_TYPE_R) - set_bit(idx, vmx->shadow_msr_intercept.read); - if (type & MSR_TYPE_W) - set_bit(idx, vmx->shadow_msr_intercept.write); - } + */ + idx = vmx_get_passthrough_msr_slot(msr); + if (idx >= 0) { + if (type & MSR_TYPE_R) + set_bit(idx, vmx->shadow_msr_intercept.read); + if (type & MSR_TYPE_W) + set_bit(idx, vmx->shadow_msr_intercept.write); } if (type & MSR_TYPE_R) From 73cb4a2d8d7e0259f94046116727084f21e4599f Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 28 Nov 2023 23:16:00 +0100 Subject: [PATCH 549/814] parisc: Use irq_enter_rcu() to fix warning at kernel/context_tracking.c:367 Use irq*_rcu() functions to fix this kernel warning: WARNING: CPU: 0 PID: 0 at kernel/context_tracking.c:367 ct_irq_enter+0xa0/0xd0 Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 6.7.0-rc3-64bit+ #1037 Hardware name: 9000/785/C3700 IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000412cd758 00000000412cd75c IIR: 03ffe01f ISR: 0000000000000000 IOR: 0000000043c20c20 CPU: 0 CR30: 0000000041caa000 CR31: 0000000000000000 ORIG_R28: 0000000000000005 IAOQ[0]: ct_irq_enter+0xa0/0xd0 IAOQ[1]: ct_irq_enter+0xa4/0xd0 RP(r2): irq_enter+0x34/0x68 Backtrace: [<000000004034a3ec>] irq_enter+0x34/0x68 [<000000004030dc48>] do_cpu_irq_mask+0xc0/0x450 [<0000000040303070>] intr_return+0x0/0xc Signed-off-by: Helge Deller --- arch/parisc/kernel/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 2f81bfd4f15e..dff66be65d29 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -498,7 +498,7 @@ asmlinkage void do_cpu_irq_mask(struct pt_regs *regs) old_regs = set_irq_regs(regs); local_irq_disable(); - irq_enter(); + irq_enter_rcu(); eirr_val = mfctl(23) & cpu_eiem & per_cpu(local_ack_eiem, cpu); if (!eirr_val) @@ -533,7 +533,7 @@ asmlinkage void do_cpu_irq_mask(struct pt_regs *regs) #endif /* CONFIG_IRQSTACKS */ out: - irq_exit(); + irq_exit_rcu(); set_irq_regs(old_regs); return; From 94a1b192290c9fdb33085ecacf82afb27bd63fa8 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 22 Jan 2024 23:15:48 +0100 Subject: [PATCH 550/814] parisc: Show kernel unaligned memory accesses Warn if some kernel function triggers unaligned memory accesses. Signed-off-by: Helge Deller --- arch/parisc/kernel/unaligned.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index c520e551a165..95a2741f26f3 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -399,6 +399,13 @@ void handle_unaligned(struct pt_regs *regs) if (!unaligned_enabled) goto force_sigbus; + } else { + static DEFINE_RATELIMIT_STATE(kernel_ratelimit, 5 * HZ, 5); + if (!(current->thread.flags & PARISC_UAC_NOPRINT) && + __ratelimit(&kernel_ratelimit)) + pr_warn("Kernel: unaligned access to " RFMT " in %pS " + "(iir " RFMT ")\n", + regs->ior, (void *)regs->iaoq[0], regs->iir); } /* handle modification - OK, it's ugly, see the instruction manual */ From cf159848860d38c2f2509ec19d595f5490ed03e5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Feb 2024 12:20:51 +0100 Subject: [PATCH 551/814] parisc: avoid c23 'nullptr' idenitifier Starting in c23, this is a reserved keyword, so in the future, using it will start causing build failures: arch/parisc/math-emu/frnd.c:36:23: error: expected ';', ',' or ')' before 'nullptr' Since I can't think of a good replacement name, add a leading underscore to the function argument to avoid this namespace conflict. Apparently all of these arguments are unused. Signed-off-by: Arnd Bergmann Signed-off-by: Helge Deller --- arch/parisc/math-emu/dfsqrt.c | 4 ++-- arch/parisc/math-emu/fcnvff.c | 8 ++++---- arch/parisc/math-emu/fcnvfu.c | 16 ++++++++-------- arch/parisc/math-emu/fcnvfut.c | 16 ++++++++-------- arch/parisc/math-emu/fcnvfx.c | 16 ++++++++-------- arch/parisc/math-emu/fcnvfxt.c | 16 ++++++++-------- arch/parisc/math-emu/fcnvuf.c | 16 ++++++++-------- arch/parisc/math-emu/fcnvxf.c | 16 ++++++++-------- arch/parisc/math-emu/frnd.c | 8 ++++---- arch/parisc/math-emu/sfsqrt.c | 4 ++-- 10 files changed, 60 insertions(+), 60 deletions(-) diff --git a/arch/parisc/math-emu/dfsqrt.c b/arch/parisc/math-emu/dfsqrt.c index 63d339c81c14..e3a3a19b966b 100644 --- a/arch/parisc/math-emu/dfsqrt.c +++ b/arch/parisc/math-emu/dfsqrt.c @@ -15,7 +15,7 @@ * Double Floating-point Square Root * * External Interfaces: - * dbl_fsqrt(srcptr,nullptr,dstptr,status) + * dbl_fsqrt(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -37,7 +37,7 @@ unsigned int dbl_fsqrt( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/fcnvff.c b/arch/parisc/math-emu/fcnvff.c index 0530e6127797..61e489704c86 100644 --- a/arch/parisc/math-emu/fcnvff.c +++ b/arch/parisc/math-emu/fcnvff.c @@ -16,8 +16,8 @@ * Double Floating-point to Single Floating-point * * External Interfaces: - * dbl_to_sgl_fcnvff(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvff(srcptr,nullptr,dstptr,status) + * dbl_to_sgl_fcnvff(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvff(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -40,7 +40,7 @@ int sgl_to_dbl_fcnvff( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { @@ -127,7 +127,7 @@ sgl_to_dbl_fcnvff( int dbl_to_sgl_fcnvff( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/fcnvfu.c b/arch/parisc/math-emu/fcnvfu.c index c971618a6f3c..c31790ceecca 100644 --- a/arch/parisc/math-emu/fcnvfu.c +++ b/arch/parisc/math-emu/fcnvfu.c @@ -15,10 +15,10 @@ * Floating-point to Unsigned Fixed-point Converts * * External Interfaces: - * dbl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvfu(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvfu(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvfu(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvfu(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -45,7 +45,7 @@ int sgl_to_sgl_fcnvfu( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, unsigned int *dstptr, unsigned int *status) { @@ -166,7 +166,7 @@ sgl_to_sgl_fcnvfu( int sgl_to_dbl_fcnvfu( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_unsigned *dstptr, unsigned int *status) { @@ -285,7 +285,7 @@ sgl_to_dbl_fcnvfu( */ /*ARGSUSED*/ int -dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr, +dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *_nullptr, unsigned int *dstptr, unsigned int *status) { register unsigned int srcp1, srcp2, result; @@ -408,7 +408,7 @@ dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr, */ /*ARGSUSED*/ int -dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr, +dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *_nullptr, dbl_unsigned * dstptr, unsigned int *status) { register int src_exponent; diff --git a/arch/parisc/math-emu/fcnvfut.c b/arch/parisc/math-emu/fcnvfut.c index 5b657f852578..2cf1daf3b7ad 100644 --- a/arch/parisc/math-emu/fcnvfut.c +++ b/arch/parisc/math-emu/fcnvfut.c @@ -15,10 +15,10 @@ * Floating-point to Unsigned Fixed-point Converts with Truncation * * External Interfaces: - * dbl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvfut(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvfut(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvfut(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvfut(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -44,7 +44,7 @@ */ /*ARGSUSED*/ int -sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr, +sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *_nullptr, unsigned int *dstptr, unsigned int *status) { register unsigned int src, result; @@ -113,7 +113,7 @@ sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr, */ /*ARGSUSED*/ int -sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr, +sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *_nullptr, dbl_unsigned * dstptr, unsigned int *status) { register int src_exponent; @@ -183,7 +183,7 @@ sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr, */ /*ARGSUSED*/ int -dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr, +dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *_nullptr, unsigned int *dstptr, unsigned int *status) { register unsigned int srcp1, srcp2, result; @@ -252,7 +252,7 @@ dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr, */ /*ARGSUSED*/ int -dbl_to_dbl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr, +dbl_to_dbl_fcnvfut (dbl_floating_point * srcptr, unsigned int *_nullptr, dbl_unsigned * dstptr, unsigned int *status) { register int src_exponent; diff --git a/arch/parisc/math-emu/fcnvfx.c b/arch/parisc/math-emu/fcnvfx.c index 5e153078d803..99bd61479452 100644 --- a/arch/parisc/math-emu/fcnvfx.c +++ b/arch/parisc/math-emu/fcnvfx.c @@ -18,10 +18,10 @@ * Double Floating-point to Double Fixed-point * * External Interfaces: - * dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvfx(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvfx(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvfx(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvfx(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -44,7 +44,7 @@ int sgl_to_sgl_fcnvfx( sgl_floating_point *srcptr, - sgl_floating_point *nullptr, + sgl_floating_point *_nullptr, int *dstptr, sgl_floating_point *status) { @@ -141,7 +141,7 @@ sgl_to_sgl_fcnvfx( int sgl_to_dbl_fcnvfx( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_integer *dstptr, unsigned int *status) { @@ -262,7 +262,7 @@ sgl_to_dbl_fcnvfx( int dbl_to_sgl_fcnvfx( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, int *dstptr, unsigned int *status) { @@ -373,7 +373,7 @@ dbl_to_sgl_fcnvfx( int dbl_to_dbl_fcnvfx( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_integer *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/fcnvfxt.c b/arch/parisc/math-emu/fcnvfxt.c index ebec31e40d01..3b7cc62257d0 100644 --- a/arch/parisc/math-emu/fcnvfxt.c +++ b/arch/parisc/math-emu/fcnvfxt.c @@ -18,10 +18,10 @@ * Double Floating-point to Double Fixed-point /w truncated result * * External Interfaces: - * dbl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvfxt(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvfxt(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvfxt(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvfxt(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -45,7 +45,7 @@ int sgl_to_sgl_fcnvfxt( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, int *dstptr, unsigned int *status) { @@ -109,7 +109,7 @@ sgl_to_sgl_fcnvfxt( int sgl_to_dbl_fcnvfxt( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_integer *dstptr, unsigned int *status) { @@ -183,7 +183,7 @@ sgl_to_dbl_fcnvfxt( int dbl_to_sgl_fcnvfxt( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, int *dstptr, unsigned int *status) { @@ -248,7 +248,7 @@ dbl_to_sgl_fcnvfxt( int dbl_to_dbl_fcnvfxt( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_integer *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/fcnvuf.c b/arch/parisc/math-emu/fcnvuf.c index c54978a0ace1..c166feb57045 100644 --- a/arch/parisc/math-emu/fcnvuf.c +++ b/arch/parisc/math-emu/fcnvuf.c @@ -15,10 +15,10 @@ * Fixed point to Floating-point Converts * * External Interfaces: - * dbl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvuf(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvuf(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvuf(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvuf(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -45,7 +45,7 @@ int sgl_to_sgl_fcnvuf( unsigned int *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { @@ -104,7 +104,7 @@ sgl_to_sgl_fcnvuf( int sgl_to_dbl_fcnvuf( unsigned int *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { @@ -145,7 +145,7 @@ sgl_to_dbl_fcnvuf( int dbl_to_sgl_fcnvuf( dbl_unsigned *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { @@ -227,7 +227,7 @@ dbl_to_sgl_fcnvuf( int dbl_to_dbl_fcnvuf( dbl_unsigned *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/fcnvxf.c b/arch/parisc/math-emu/fcnvxf.c index 69401797146b..11bc1e8a13aa 100644 --- a/arch/parisc/math-emu/fcnvxf.c +++ b/arch/parisc/math-emu/fcnvxf.c @@ -18,10 +18,10 @@ * Double Fixed-point to Double Floating-point * * External Interfaces: - * dbl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status) - * dbl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status) - * sgl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status) - * sgl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status) + * dbl_to_dbl_fcnvxf(srcptr,_nullptr,dstptr,status) + * dbl_to_sgl_fcnvxf(srcptr,_nullptr,dstptr,status) + * sgl_to_dbl_fcnvxf(srcptr,_nullptr,dstptr,status) + * sgl_to_sgl_fcnvxf(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -44,7 +44,7 @@ int sgl_to_sgl_fcnvxf( int *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { @@ -115,7 +115,7 @@ sgl_to_sgl_fcnvxf( int sgl_to_dbl_fcnvxf( int *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { @@ -166,7 +166,7 @@ sgl_to_dbl_fcnvxf( int dbl_to_sgl_fcnvxf( dbl_integer *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { @@ -271,7 +271,7 @@ dbl_to_sgl_fcnvxf( int dbl_to_dbl_fcnvxf( dbl_integer *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/frnd.c b/arch/parisc/math-emu/frnd.c index 0b0e8493e08a..825d89650c2d 100644 --- a/arch/parisc/math-emu/frnd.c +++ b/arch/parisc/math-emu/frnd.c @@ -14,8 +14,8 @@ * Quad Floating-point Round to Integer (returns unimplemented) * * External Interfaces: - * dbl_frnd(srcptr,nullptr,dstptr,status) - * sgl_frnd(srcptr,nullptr,dstptr,status) + * dbl_frnd(srcptr,_nullptr,dstptr,status) + * sgl_frnd(srcptr,_nullptr,dstptr,status) * * END_DESC */ @@ -33,7 +33,7 @@ /*ARGSUSED*/ int sgl_frnd(sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { @@ -138,7 +138,7 @@ sgl_frnd(sgl_floating_point *srcptr, int dbl_frnd( dbl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, dbl_floating_point *dstptr, unsigned int *status) { diff --git a/arch/parisc/math-emu/sfsqrt.c b/arch/parisc/math-emu/sfsqrt.c index bd6a84f468d8..8e9e023e7b2e 100644 --- a/arch/parisc/math-emu/sfsqrt.c +++ b/arch/parisc/math-emu/sfsqrt.c @@ -15,7 +15,7 @@ * Single Floating-point Square Root * * External Interfaces: - * sgl_fsqrt(srcptr,nullptr,dstptr,status) + * sgl_fsqrt(srcptr,_nullptr,dstptr,status) * * Internal Interfaces: * @@ -37,7 +37,7 @@ unsigned int sgl_fsqrt( sgl_floating_point *srcptr, - unsigned int *nullptr, + unsigned int *_nullptr, sgl_floating_point *dstptr, unsigned int *status) { From 0b9ec151b9b45fee749d32d744d50e1b721d79b2 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:38:02 -0300 Subject: [PATCH 552/814] parisc: make parisc_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the parisc_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Signed-off-by: Helge Deller --- arch/parisc/include/asm/parisc-device.h | 2 +- arch/parisc/kernel/drivers.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h index 4de3b391d812..7ddd7f433367 100644 --- a/arch/parisc/include/asm/parisc-device.h +++ b/arch/parisc/include/asm/parisc-device.h @@ -61,7 +61,7 @@ parisc_get_drvdata(struct parisc_device *d) return dev_get_drvdata(&d->dev); } -extern struct bus_type parisc_bus_type; +extern const struct bus_type parisc_bus_type; int iosapic_serial_irq(struct parisc_device *dev); diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index c7ff339732ba..ac19d685e4a5 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -618,7 +618,7 @@ static struct attribute *parisc_device_attrs[] = { }; ATTRIBUTE_GROUPS(parisc_device); -struct bus_type parisc_bus_type = { +const struct bus_type parisc_bus_type = { .name = "parisc", .match = parisc_generic_match, .uevent = parisc_uevent, From e5db6a74571a8baf87a116ea39aab946283362ff Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 16 Feb 2024 14:26:55 +0100 Subject: [PATCH 553/814] parisc/unaligned: Rewrite 64-bit inline assembly of emulate_ldd() Convert to use real temp variables instead of clobbering processor registers. This aligns the 64-bit inline assembly code with the 32-bit assembly code which was rewritten with commit 427c1073a2a1 ("parisc/unaligned: Rewrite 32-bit inline assembly of emulate_ldd()"). While at it, fix comment in 32-bit rewrite code. Temporary variables are now used for both 32-bit and 64-bit code, so move their declarations to the function header. No functional change intended. Signed-off-by: Guenter Roeck Cc: stable@vger.kernel.org # v6.0+ Signed-off-by: Helge Deller --- arch/parisc/kernel/unaligned.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 95a2741f26f3..71e596ca5a86 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -169,6 +169,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) { unsigned long saddr = regs->ior; + unsigned long shift, temp1; __u64 val = 0; ASM_EXCEPTIONTABLE_VAR(ret); @@ -180,25 +181,22 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) #ifdef CONFIG_64BIT __asm__ __volatile__ ( -" depd,z %3,60,3,%%r19\n" /* r19=(ofs&7)*8 */ -" mtsp %4, %%sr1\n" -" depd %%r0,63,3,%3\n" -"1: ldd 0(%%sr1,%3),%0\n" -"2: ldd 8(%%sr1,%3),%%r20\n" -" subi 64,%%r19,%%r19\n" -" mtsar %%r19\n" -" shrpd %0,%%r20,%%sar,%0\n" +" depd,z %2,60,3,%3\n" /* shift=(ofs&7)*8 */ +" mtsp %5, %%sr1\n" +" depd %%r0,63,3,%2\n" +"1: ldd 0(%%sr1,%2),%0\n" +"2: ldd 8(%%sr1,%2),%4\n" +" subi 64,%3,%3\n" +" mtsar %3\n" +" shrpd %0,%4,%%sar,%0\n" "3: \n" ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") - : "=r" (val), "+r" (ret) - : "0" (val), "r" (saddr), "r" (regs->isr) - : "r19", "r20" ); + : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) + : "r" (regs->isr) ); #else - { - unsigned long shift, temp1; __asm__ __volatile__ ( -" zdep %2,29,2,%3\n" /* r19=(ofs&3)*8 */ +" zdep %2,29,2,%3\n" /* shift=(ofs&3)*8 */ " mtsp %5, %%sr1\n" " dep %%r0,31,2,%2\n" "1: ldw 0(%%sr1,%2),%0\n" @@ -214,7 +212,6 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) : "r" (regs->isr) ); - } #endif DPRINTF("val = 0x%llx\n", val); From 4603fbaa76b5e703b38ac8cc718102834eb6e330 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Fri, 23 Feb 2024 16:40:51 +0100 Subject: [PATCH 554/814] parisc: Avoid clobbering the C/B bits in the PSW with tophys and tovirt macros Use add,l to avoid clobbering the C/B bits in the PSW. Signed-off-by: John David Anglin Signed-off-by: Helge Deller Cc: stable@vger.kernel.org # v5.10+ --- arch/parisc/include/asm/assembly.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 5937d5edaba1..000a28e1c5e8 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -97,26 +97,28 @@ * version takes two arguments: a src and destination register. * However, the source and destination registers can not be * the same register. + * + * We use add,l to avoid clobbering the C/B bits in the PSW. */ .macro tophys grvirt, grphys - ldil L%(__PAGE_OFFSET), \grphys - sub \grvirt, \grphys, \grphys + ldil L%(-__PAGE_OFFSET), \grphys + addl \grvirt, \grphys, \grphys .endm - + .macro tovirt grphys, grvirt ldil L%(__PAGE_OFFSET), \grvirt - add \grphys, \grvirt, \grvirt + addl \grphys, \grvirt, \grvirt .endm .macro tophys_r1 gr - ldil L%(__PAGE_OFFSET), %r1 - sub \gr, %r1, \gr + ldil L%(-__PAGE_OFFSET), %r1 + addl \gr, %r1, \gr .endm - + .macro tovirt_r1 gr ldil L%(__PAGE_OFFSET), %r1 - add \gr, %r1, \gr + addl \gr, %r1, \gr .endm .macro delay value From a2abae8f0b638c31bb9799d9dd847306e0d005bd Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 10 Feb 2024 09:55:26 -0800 Subject: [PATCH 555/814] parisc: Fix ip_fast_csum IP checksum unit tests report the following error when run on hppa/hppa64. # test_ip_fast_csum: ASSERTION FAILED at lib/checksum_kunit.c:463 Expected ( u64)csum_result == ( u64)expected, but ( u64)csum_result == 33754 (0x83da) ( u64)expected == 10946 (0x2ac2) not ok 4 test_ip_fast_csum 0x83da is the expected result if the IP header length is 20 bytes. 0x2ac2 is the expected result if the IP header length is 24 bytes. The test fails with an IP header length of 24 bytes. It appears that ip_fast_csum() always returns the checksum for a 20-byte header, no matter how long the header actually is. Code analysis shows a suspicious assembler sequence in ip_fast_csum(). " addc %0, %3, %0\n" "1: ldws,ma 4(%1), %3\n" " addib,< 0, %2, 1b\n" <--- While my understanding of HPPA assembler is limited, it does not seem to make much sense to subtract 0 from a register and to expect the result to ever be negative. Subtracting 1 from the length parameter makes more sense. On top of that, the operation should be repeated if and only if the result is still > 0, so change the suspicious instruction to " addib,> -1, %2, 1b\n" The IP checksum unit test passes after this change. Cc: Palmer Dabbelt Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Tested-by: Charlie Jenkins Reviewed-by: Charlie Jenkins Signed-off-by: Helge Deller --- arch/parisc/include/asm/checksum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h index 3c43baca7b39..f705e5dd1074 100644 --- a/arch/parisc/include/asm/checksum.h +++ b/arch/parisc/include/asm/checksum.h @@ -40,7 +40,7 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) " addc %0, %5, %0\n" " addc %0, %3, %0\n" "1: ldws,ma 4(%1), %3\n" -" addib,< 0, %2, 1b\n" +" addib,> -1, %2, 1b\n" " addc %0, %3, %0\n" "\n" " extru %0, 31, 16, %4\n" From 4408ba75e4ba80c91fde7e10bccccf388f5c09be Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 10 Feb 2024 11:15:56 -0800 Subject: [PATCH 556/814] parisc: Fix csum_ipv6_magic on 32-bit systems Calculating the IPv6 checksum on 32-bit systems missed overflows when adding the proto+len fields into the checksum. This results in the following unit test failure. # test_csum_ipv6_magic: ASSERTION FAILED at lib/checksum_kunit.c:506 Expected ( u64)csum_result == ( u64)expected, but ( u64)csum_result == 46722 (0xb682) ( u64)expected == 46721 (0xb681) not ok 5 test_csum_ipv6_magic This is probably rarely seen in the real world because proto+len are usually small values which will rarely result in overflows when calculating the checksum. However, the unit test code uses large values for the length field, causing the test to fail. Fix the problem by adding the missing carry into the final checksum. Cc: Palmer Dabbelt Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Tested-by: Charlie Jenkins Reviewed-by: Charlie Jenkins Signed-off-by: Helge Deller --- arch/parisc/include/asm/checksum.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h index f705e5dd1074..e619e67440db 100644 --- a/arch/parisc/include/asm/checksum.h +++ b/arch/parisc/include/asm/checksum.h @@ -163,7 +163,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, " ldw,ma 4(%2), %7\n" /* 4th daddr */ " addc %6, %0, %0\n" " addc %7, %0, %0\n" -" addc %3, %0, %0\n" /* fold in proto+len, catch carry */ +" addc %3, %0, %0\n" /* fold in proto+len */ +" addc 0, %0, %0\n" /* add carry */ #endif : "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len), From 4b75b12d70506e31fc02356bbca60f8d5ca012d0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 13 Feb 2024 15:46:31 -0800 Subject: [PATCH 557/814] parisc: Fix csum_ipv6_magic on 64-bit systems hppa 64-bit systems calculates the IPv6 checksum using 64-bit add operations. The last add folds protocol and length fields into the 64-bit result. While unlikely, this operation can overflow. The overflow can be triggered with a code sequence such as the following. /* try to trigger massive overflows */ memset(tmp_buf, 0xff, sizeof(struct in6_addr)); csum_result = csum_ipv6_magic((struct in6_addr *)tmp_buf, (struct in6_addr *)tmp_buf, 0xffff, 0xff, 0xffffffff); Fix the problem by adding any overflows from the final add operation into the calculated checksum. Fortunately, we can do this without additional cost by replacing the add operation used to fold the checksum into 32 bit with "add,dc" to add in the missing carry. Cc: Palmer Dabbelt Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Reviewed-by: Charlie Jenkins Tested-by: Guenter Roeck Signed-off-by: Helge Deller --- arch/parisc/include/asm/checksum.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h index e619e67440db..c949aa20fa16 100644 --- a/arch/parisc/include/asm/checksum.h +++ b/arch/parisc/include/asm/checksum.h @@ -137,8 +137,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, " add,dc %3, %0, %0\n" /* fold in proto+len | carry bit */ " extrd,u %0, 31, 32, %4\n"/* copy upper half down */ " depdi 0, 31, 32, %0\n"/* clear upper half */ -" add %4, %0, %0\n" /* fold into 32-bits */ -" addc 0, %0, %0\n" /* add carry */ +" add,dc %4, %0, %0\n" /* fold into 32-bits, plus carry */ +" addc 0, %0, %0\n" /* add final carry */ #else From 0568b6f0d863643db2edcc7be31165740c89fa82 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 27 Feb 2024 12:33:51 -0800 Subject: [PATCH 558/814] parisc: Strip upper 32 bit of sum in csum_ipv6_magic for 64-bit builds IPv6 checksum tests with unaligned addresses on 64-bit builds result in unexpected failures. Expected expected == csum_result, but expected == 46591 (0xb5ff) csum_result == 46381 (0xb52d) with alignment offset 1 Oddly enough, the problem disappeared after adding test code into the beginning of csum_ipv6_magic(). As it turns out, the 'sum' parameter of csum_ipv6_magic() is declared as __wsum, which is a 32-bit variable. However, it is treated as 64-bit variable in the 64-bit assembler code. Tests showed that the upper 32 bit of the register used to pass the variable are _not_ cleared when entering the function. This can result in checksum calculation errors. Clearing the upper 32 bit of 'sum' as first operation in the assembler code fixes the problem. Acked-by: Helge Deller Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Helge Deller --- arch/parisc/include/asm/checksum.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h index c949aa20fa16..2aceebcd695c 100644 --- a/arch/parisc/include/asm/checksum.h +++ b/arch/parisc/include/asm/checksum.h @@ -126,6 +126,7 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, ** Try to keep 4 registers with "live" values ahead of the ALU. */ +" depdi 0, 31, 32, %0\n"/* clear upper half of incoming checksum */ " ldd,ma 8(%1), %4\n" /* get 1st saddr word */ " ldd,ma 8(%2), %5\n" /* get 1st daddr word */ " add %4, %0, %0\n" From af43e871c93640a69af58ddb33aec2d4be80bf6b Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sun, 9 Apr 2023 11:43:06 +0100 Subject: [PATCH 559/814] MIPS: mipsregs: Parse fp and sp register by name in parse_r parse_r helper is used to parse register number from oprand, it only handles oprand which use number to refer register before. However compiler may use $gp and $sp to reference register 29 and 30. Handle this situation by adding relevant match name. Fixes compilation error: {standard input}: Assembler messages: {standard input}:1937: Error: Unable to parse register name $fp Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mipsregs.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index d2c7bc241a84..3c6ddc0c2c7a 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1422,11 +1422,13 @@ static inline int mm_insn_16bit(u16 insn) */ /* Match an individual register number and assign to \var */ -#define _IFC_REG(n) \ - ".ifc \\r, $" #n "\n\t" \ +#define _IFC_REG_NAME(name, n) \ + ".ifc \\r, $" #name "\n\t" \ "\\var = " #n "\n\t" \ ".endif\n\t" +#define _IFC_REG(n) _IFC_REG_NAME(n, n) + #define _ASM_SET_PARSE_R \ ".macro parse_r var r\n\t" \ "\\var = -1\n\t" \ @@ -1438,6 +1440,7 @@ static inline int mm_insn_16bit(u16 insn) _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23) \ _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27) \ _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31) \ + _IFC_REG_NAME(sp, 29) _IFC_REG_NAME(fp, 30) \ ".iflt \\var\n\t" \ ".error \"Unable to parse register name \\r\"\n\t" \ ".endif\n\t" \ From 31d90deb653a5c34d8d648b8a1b459b929be1a73 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 27 Sep 2023 12:59:13 -0400 Subject: [PATCH 560/814] SUNRPC: Don't retry using the same source port if connection failed If the TCP connection attempt fails without ever establishing a connection, then assume the problem may be the server is rejecting us due to port reuse. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 58f3dc8d0d71..1a961314b737 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -62,6 +62,7 @@ #include "sunrpc.h" static void xs_close(struct rpc_xprt *xprt); +static void xs_reset_srcport(struct sock_xprt *transport); static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock); static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, struct socket *sock); @@ -1565,8 +1566,10 @@ static void xs_tcp_state_change(struct sock *sk) break; case TCP_CLOSE: if (test_and_clear_bit(XPRT_SOCK_CONNECTING, - &transport->sock_state)) + &transport->sock_state)) { + xs_reset_srcport(transport); xprt_clear_connecting(xprt); + } clear_bit(XPRT_CLOSING, &xprt->state); /* Trigger the socket release */ xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT); @@ -1722,6 +1725,11 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) xs_update_peer_port(xprt); } +static void xs_reset_srcport(struct sock_xprt *transport) +{ + transport->srcport = 0; +} + static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock) { if (transport->srcport == 0 && transport->xprt.reuseport) From 0c14584cdbdb58ecc14d149a81ca6c3d42cd38ec Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 12 Dec 2023 15:34:08 +0100 Subject: [PATCH 561/814] SUNRPC: Don't try to send when the connection is shutting down If the connection has been scheduled to shut down, we must assume that the socket is not in a state to accept further transmissions until the connection has been re-established. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index af13fdfa6672..db3754a3298f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1541,6 +1541,9 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task) int is_retrans = RPC_WAS_SENT(task); int status; + if (test_bit(XPRT_CLOSE_WAIT, &xprt->state)) + return -ENOTCONN; + if (!req->rq_bytes_sent) { if (xprt_request_data_received(task)) { status = 0; From 3f7edeac0bbb301a07d7ea2abd28727aaa7fdab0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 12 Dec 2023 16:13:22 +0100 Subject: [PATCH 562/814] SUNRPC: Add a transport callback to handle dequeuing of an RPC request Add a transport level callback to allow it to handle the consequences of dequeuing the request that was in the process of being transmitted. For something like a TCP connection, we may need to disconnect if the request was partially transmitted. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/xprt.c | 6 ++++++ net/sunrpc/xprtsock.c | 13 +++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 464f6a9492ab..81b952649d35 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -152,6 +152,7 @@ struct rpc_xprt_ops { int (*prepare_request)(struct rpc_rqst *req, struct xdr_buf *buf); int (*send_request)(struct rpc_rqst *req); + void (*abort_send_request)(struct rpc_rqst *req); void (*wait_for_reply_request)(struct rpc_task *task); void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task); void (*release_request)(struct rpc_task *task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index db3754a3298f..09f245cda526 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1398,6 +1398,12 @@ xprt_request_dequeue_transmit_locked(struct rpc_task *task) if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) return; if (!list_empty(&req->rq_xmit)) { + struct rpc_xprt *xprt = req->rq_xprt; + + if (list_is_first(&req->rq_xmit, &xprt->xmit_queue) && + xprt->ops->abort_send_request) + xprt->ops->abort_send_request(req); + list_del(&req->rq_xmit); if (!list_empty(&req->rq_xmit2)) { struct rpc_rqst *next = list_first_entry(&req->rq_xmit2, diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 1a961314b737..bb81050c870e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -884,6 +884,17 @@ static int xs_stream_prepare_request(struct rpc_rqst *req, struct xdr_buf *buf) return xdr_alloc_bvec(buf, rpc_task_gfp_mask()); } +static void xs_stream_abort_send_request(struct rpc_rqst *req) +{ + struct rpc_xprt *xprt = req->rq_xprt; + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + + if (transport->xmit.offset != 0 && + !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) + xprt_force_disconnect(xprt); +} + /* * Determine if the previous message in the stream was aborted before it * could complete transmission. @@ -3029,6 +3040,7 @@ static const struct rpc_xprt_ops xs_local_ops = { .buf_free = rpc_free, .prepare_request = xs_stream_prepare_request, .send_request = xs_local_send_request, + .abort_send_request = xs_stream_abort_send_request, .wait_for_reply_request = xprt_wait_for_reply_request_def, .close = xs_close, .destroy = xs_destroy, @@ -3076,6 +3088,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = { .buf_free = rpc_free, .prepare_request = xs_stream_prepare_request, .send_request = xs_tcp_send_request, + .abort_send_request = xs_stream_abort_send_request, .wait_for_reply_request = xprt_wait_for_reply_request_def, .close = xs_tcp_shutdown, .destroy = xs_destroy, From 53a43dd48f8e5e9cc046f14506a11250efc46bf6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 8 Feb 2024 21:48:39 +0100 Subject: [PATCH 563/814] KVM: selftests: Move setting a vCPU's entry point to a dedicated API Extract the code to set a vCPU's entry point out of vm_arch_vcpu_add() and into a new API, vcpu_arch_set_entry_point(). Providing a separate API will allow creating a KVM selftests hardness that can handle tests that use different entry points for sub-tests, whereas *requiring* the entry point to be specified at vCPU creation makes it difficult to create a generic harness, e.g. the boilerplate setup/teardown can't easily create and destroy the VM and vCPUs. Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-4-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/kvm_util_base.h | 11 +++++---- .../selftests/kvm/lib/aarch64/processor.c | 24 ++++++++++++++----- .../selftests/kvm/lib/riscv/processor.c | 9 ++++--- .../selftests/kvm/lib/s390x/processor.c | 13 +++++----- .../selftests/kvm/lib/x86_64/processor.c | 13 +++++++--- 5 files changed, 48 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 9e5afc472c14..a6e7738a8db7 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -969,15 +969,18 @@ static inline void vcpu_dump(FILE *stream, struct kvm_vcpu *vcpu, * Input Args: * vm - Virtual Machine * vcpu_id - The id of the VCPU to add to the VM. - * guest_code - The vCPU's entry point */ -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - void *guest_code); +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id); +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code); static inline struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, void *guest_code) { - return vm_arch_vcpu_add(vm, vcpu_id, guest_code); + struct kvm_vcpu *vcpu = vm_arch_vcpu_add(vm, vcpu_id); + + vcpu_arch_set_entry_point(vcpu, guest_code); + + return vcpu; } /* Re-create a vCPU after restarting a VM, e.g. for state save/restore tests. */ diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 41c776b642c0..c83616e19bad 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -365,8 +365,13 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) indent, "", pstate, pc); } -struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_vcpu_init *init, void *guest_code) +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) +{ + vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); +} + +static struct kvm_vcpu *__aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init) { size_t stack_size; uint64_t stack_vaddr; @@ -381,15 +386,22 @@ struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, aarch64_vcpu_setup(vcpu, init); vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); - vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); + return vcpu; +} + +struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init, void *guest_code) +{ + struct kvm_vcpu *vcpu = __aarch64_vcpu_add(vm, vcpu_id, init); + + vcpu_arch_set_entry_point(vcpu, guest_code); return vcpu; } -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - void *guest_code) +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { - return aarch64_vcpu_add(vm, vcpu_id, NULL, guest_code); + return __aarch64_vcpu_add(vm, vcpu_id, NULL); } void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 7ca736fb4194..c993947f0782 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -277,8 +277,12 @@ static void __aligned(16) guest_unexp_trap(void) 0, 0, 0, 0, 0, 0); } -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - void *guest_code) +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) +{ + vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); +} + +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { int r; size_t stack_size; @@ -312,7 +316,6 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, /* Setup stack pointer and program counter of guest */ vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.sp), stack_vaddr + stack_size); - vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); /* Setup default exception vector of guest */ vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)guest_unexp_trap); diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index 15945121daf1..cd5301cc9788 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -155,15 +155,18 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) virt_dump_region(stream, vm, indent, vm->pgd); } -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - void *guest_code) +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) +{ + vcpu->run->psw_addr = (uintptr_t)guest_code; +} + +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { size_t stack_size = DEFAULT_STACK_PGS * getpagesize(); uint64_t stack_vaddr; struct kvm_regs regs; struct kvm_sregs sregs; struct kvm_vcpu *vcpu; - struct kvm_run *run; TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x", vm->page_size); @@ -184,9 +187,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, sregs.crs[1] = vm->pgd | 0xf; /* Primary region table */ vcpu_sregs_set(vcpu, &sregs); - run = vcpu->run; - run->psw_mask = 0x0400000180000000ULL; /* DAT enabled + 64 bit mode */ - run->psw_addr = (uintptr_t)guest_code; + vcpu->run->psw_mask = 0x0400000180000000ULL; /* DAT enabled + 64 bit mode */ return vcpu; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index d8288374078e..b9b6cb730a08 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -562,8 +562,16 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) sync_global_to_guest(vm, host_cpu_is_amd); } -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, - void *guest_code) +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) +{ + struct kvm_regs regs; + + vcpu_regs_get(vcpu, ®s); + regs.rip = (unsigned long) guest_code; + vcpu_regs_set(vcpu, ®s); +} + +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { struct kvm_mp_state mp_state; struct kvm_regs regs; @@ -597,7 +605,6 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, vcpu_regs_get(vcpu, ®s); regs.rflags = regs.rflags | 0x2; regs.rsp = stack_vaddr; - regs.rip = (unsigned long) guest_code; vcpu_regs_set(vcpu, ®s); /* Setup the MP state */ From 55f2cf88486cdc504176d4c5ebccdb65ea4be161 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:40 +0100 Subject: [PATCH 564/814] KVM: selftests: Add a macro to define a test with one vcpu Most tests are currently not giving any proper output for the user to see how much sub-tests have already been run, or whether new sub-tests are part of a binary or not. So it would be good to support TAP output in the KVM selftests. There is already a nice framework for this in the kselftest_harness.h header which we can use. But since we also need a vcpu in most KVM selftests, it also makes sense to introduce our own wrapper around this which takes care of creating a VM with one vcpu, so we don't have to repeat this boilerplate in each and every test. Thus let's introduce a KVM_ONE_VCPU_TEST() macro here which takes care of this. Suggested-by: Sean Christopherson Link: https://lore.kernel.org/all/Y2v+B3xxYKJSM%2FfH@google.com/ Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-5-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/kvm_test_harness.h | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/kvm_test_harness.h diff --git a/tools/testing/selftests/kvm/include/kvm_test_harness.h b/tools/testing/selftests/kvm/include/kvm_test_harness.h new file mode 100644 index 000000000000..8f7c6858e8e2 --- /dev/null +++ b/tools/testing/selftests/kvm/include/kvm_test_harness.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Macros for defining a KVM test + * + * Copyright (C) 2022, Google LLC. + */ + +#ifndef SELFTEST_KVM_TEST_HARNESS_H +#define SELFTEST_KVM_TEST_HARNESS_H + +#include "kselftest_harness.h" + +#define KVM_ONE_VCPU_TEST_SUITE(name) \ + FIXTURE(name) { \ + struct kvm_vcpu *vcpu; \ + }; \ + \ + FIXTURE_SETUP(name) { \ + (void)vm_create_with_one_vcpu(&self->vcpu, NULL); \ + } \ + \ + FIXTURE_TEARDOWN(name) { \ + kvm_vm_free(self->vcpu->vm); \ + } + +#define KVM_ONE_VCPU_TEST(suite, test, guestcode) \ +static void __suite##_##test(struct kvm_vcpu *vcpu); \ + \ +TEST_F(suite, test) \ +{ \ + vcpu_arch_set_entry_point(self->vcpu, guestcode); \ + __suite##_##test(self->vcpu); \ +} \ +static void __suite##_##test(struct kvm_vcpu *vcpu) + +#endif /* SELFTEST_KVM_TEST_HARNESS_H */ From ba97ed0af6fe22dd718535ce663297ccd0ff52c5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:41 +0100 Subject: [PATCH 565/814] KVM: selftests: x86: Use TAP interface in the sync_regs test The sync_regs test currently does not have any output (unless one of the TEST_ASSERT statement fails), so it's hard to say for a user whether a certain new sub-test has been included in the binary or not. Let's make this a little bit more user-friendly and include some TAP output via the kselftest_harness.h / kvm_test_harness.h interface. To be able to use the interface, we have to break up the huge main() function here in more fine grained parts - then we can use the new KVM_ONE_VCPU_TEST() macro to define the individual tests. Since these are run with a separate VM now, we have also to make sure to create the expected state at the beginning of each test, so some parts grow a little bit - which should be OK considering that the individual tests are more self-contained now. Suggested-by: David Matlack Suggested-by: Sean Christopherson Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-6-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/sync_regs_test.c | 116 +++++++++++++----- 1 file changed, 87 insertions(+), 29 deletions(-) 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 1cd19dfa0046..67f78c0a58a5 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -17,6 +17,7 @@ #include #include +#include "kvm_test_harness.h" #include "test_util.h" #include "kvm_util.h" #include "processor.h" @@ -41,6 +42,8 @@ void guest_code(void) : "rax", "rbx"); } +KVM_ONE_VCPU_TEST_SUITE(sync_regs_test); + static void compare_regs(struct kvm_regs *left, struct kvm_regs *right) { #define REG_COMPARE(reg) \ @@ -152,18 +155,15 @@ static noinline void *race_sregs_cr4(void *arg) return NULL; } -static void race_sync_regs(void *racer) +static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer) { const time_t TIMEOUT = 2; /* seconds, roughly */ struct kvm_x86_state *state; 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; @@ -205,26 +205,12 @@ static void race_sync_regs(void *racer) TEST_ASSERT_EQ(pthread_join(thread, NULL), 0); kvm_x86_state_cleanup(state); - kvm_vm_free(vm); } -int main(int argc, char *argv[]) +KVM_ONE_VCPU_TEST(sync_regs_test, read_invalid, guest_code) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; - struct kvm_run *run; - struct kvm_regs regs; - struct kvm_sregs sregs; - struct kvm_vcpu_events events; - int rv, cap; - - cap = kvm_check_cap(KVM_CAP_SYNC_REGS); - TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS); - TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD)); - - vm = vm_create_with_one_vcpu(&vcpu, guest_code); - - run = vcpu->run; + struct kvm_run *run = vcpu->run; + int rv; /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; @@ -240,6 +226,12 @@ int main(int argc, char *argv[]) "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_valid_regs = 0; +} + +KVM_ONE_VCPU_TEST(sync_regs_test, set_invalid, guest_code) +{ + struct kvm_run *run = vcpu->run; + int rv; /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; @@ -255,6 +247,14 @@ int main(int argc, char *argv[]) "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_dirty_regs = 0; +} + +KVM_ONE_VCPU_TEST(sync_regs_test, req_and_verify_all_valid, guest_code) +{ + struct kvm_run *run = vcpu->run; + struct kvm_vcpu_events events; + struct kvm_sregs sregs; + struct kvm_regs regs; /* Request and verify all valid register sets. */ /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ @@ -270,6 +270,19 @@ int main(int argc, char *argv[]) vcpu_events_get(vcpu, &events); compare_vcpu_events(&events, &run->s.regs.events); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, set_and_verify_various, guest_code) +{ + struct kvm_run *run = vcpu->run; + struct kvm_vcpu_events events; + struct kvm_sregs sregs; + struct kvm_regs regs; + + /* Run once to get register set */ + run->kvm_valid_regs = TEST_SYNC_FIELDS; + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); /* Set and verify various register values. */ run->s.regs.regs.rbx = 0xBAD1DEA; @@ -295,6 +308,11 @@ int main(int argc, char *argv[]) vcpu_events_get(vcpu, &events); compare_vcpu_events(&events, &run->s.regs.events); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_dirty_regs_bits, guest_code) +{ + struct kvm_run *run = vcpu->run; /* Clear kvm_dirty_regs bits, verify new s.regs values are * overwritten with existing guest values. @@ -307,6 +325,17 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.regs.rbx != 0xDEADBEEF, "rbx sync regs value incorrect 0x%llx.", run->s.regs.regs.rbx); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_valid_and_dirty_regs, guest_code) +{ + struct kvm_run *run = vcpu->run; + struct kvm_regs regs; + + /* Run once to get register set */ + run->kvm_valid_regs = TEST_SYNC_FIELDS; + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); /* Clear kvm_valid_regs bits and kvm_dirty_bits. * Verify s.regs values are not overwritten with existing guest values @@ -327,6 +356,17 @@ int main(int argc, char *argv[]) TEST_ASSERT(regs.rbx == 0xBAC0 + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_valid_regs_bits, guest_code) +{ + struct kvm_run *run = vcpu->run; + struct kvm_regs regs; + + /* Run once to get register set */ + run->kvm_valid_regs = TEST_SYNC_FIELDS; + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten * with existing guest values but that guest values are overwritten @@ -344,12 +384,30 @@ int main(int argc, char *argv[]) TEST_ASSERT(regs.rbx == 0xBBBB + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); - - kvm_vm_free(vm); - - race_sync_regs(race_sregs_cr4); - race_sync_regs(race_events_exc); - race_sync_regs(race_events_inj_pen); - - return 0; +} + +KVM_ONE_VCPU_TEST(sync_regs_test, race_cr4, guest_code) +{ + race_sync_regs(vcpu, race_sregs_cr4); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, race_exc, guest_code) +{ + race_sync_regs(vcpu, race_events_exc); +} + +KVM_ONE_VCPU_TEST(sync_regs_test, race_inj_pen, guest_code) +{ + race_sync_regs(vcpu, race_events_inj_pen); +} + +int main(int argc, char *argv[]) +{ + int cap; + + cap = kvm_check_cap(KVM_CAP_SYNC_REGS); + TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS); + TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD)); + + return test_harness_run(argc, argv); } From a6983e8f5fabb249ad06328bc6452583f25b9c76 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:42 +0100 Subject: [PATCH 566/814] KVM: selftests: x86: Use TAP interface in the fix_hypercall test Use the kvm_test_harness.h interface in this test to get TAP output, so that it is easier for the user to see what the test is doing. Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-7-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/fix_hypercall_test.c | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 0f728f05ea82..f3c2239228b1 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -9,6 +9,7 @@ #include #include +#include "kvm_test_harness.h" #include "apic.h" #include "test_util.h" #include "kvm_util.h" @@ -83,6 +84,8 @@ static void guest_main(void) GUEST_DONE(); } +KVM_ONE_VCPU_TEST_SUITE(fix_hypercall); + static void enter_guest(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; @@ -103,14 +106,11 @@ static void enter_guest(struct kvm_vcpu *vcpu) } } -static void test_fix_hypercall(bool disable_quirk) +static void test_fix_hypercall(struct kvm_vcpu *vcpu, bool disable_quirk) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; + struct kvm_vm *vm = vcpu->vm; - vm = vm_create_with_one_vcpu(&vcpu, guest_main); - - vm_init_descriptor_tables(vcpu->vm); + vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vcpu->vm, UD_VECTOR, guest_ud_handler); @@ -126,10 +126,19 @@ static void test_fix_hypercall(bool disable_quirk) enter_guest(vcpu); } -int main(void) +KVM_ONE_VCPU_TEST(fix_hypercall, enable_quirk, guest_main) +{ + test_fix_hypercall(vcpu, false); +} + +KVM_ONE_VCPU_TEST(fix_hypercall, disable_quirk, guest_main) +{ + test_fix_hypercall(vcpu, true); +} + +int main(int argc, char *argv[]) { TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN); - test_fix_hypercall(false); - test_fix_hypercall(true); + return test_harness_run(argc, argv); } From de1b03f25f3b9e723e7dd8db70639abaa557d527 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:43 +0100 Subject: [PATCH 567/814] KVM: selftests: x86: Use TAP interface in the vmx_pmu_caps test Use the kvm_test_harness.h interface in this test to get TAP output, so that it is easier for the user to see what the test is doing. Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-8-thuth@redhat.com [sean: make host_cap static] Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 52 +++++-------------- 1 file changed, 12 insertions(+), 40 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 2a8d4ac2f020..876442fadada 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 @@ -15,10 +15,11 @@ #include +#include "kvm_test_harness.h" #include "kvm_util.h" #include "vmx.h" -union perf_capabilities { +static union perf_capabilities { struct { u64 lbr_format:6; u64 pebs_trap:1; @@ -32,7 +33,7 @@ union perf_capabilities { u64 anythread_deprecated:1; }; u64 capabilities; -}; +} host_cap; /* * The LBR format and most PEBS features are immutable, all other features are @@ -73,19 +74,19 @@ static void guest_code(uint64_t current_val) GUEST_DONE(); } +KVM_ONE_VCPU_TEST_SUITE(vmx_pmu_caps); + /* * Verify that guest WRMSRs to PERF_CAPABILITIES #GP regardless of the value * written, that the guest always sees the userspace controlled value, and that * PERF_CAPABILITIES is immutable after KVM_RUN. */ -static void test_guest_wrmsr_perf_capabilities(union perf_capabilities host_cap) +KVM_ONE_VCPU_TEST(vmx_pmu_caps, guest_wrmsr_perf_capabilities, guest_code) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code); struct ucall uc; int r, i; - vm_init_descriptor_tables(vm); + vm_init_descriptor_tables(vcpu->vm); vcpu_init_descriptor_tables(vcpu); vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities); @@ -117,31 +118,21 @@ static void test_guest_wrmsr_perf_capabilities(union perf_capabilities host_cap) TEST_ASSERT(!r, "Post-KVM_RUN write '0x%llx'didn't fail", host_cap.capabilities ^ BIT_ULL(i)); } - - kvm_vm_free(vm); } /* * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features * enabled, as well as '0' (to disable all features). */ -static void test_basic_perf_capabilities(union perf_capabilities host_cap) +KVM_ONE_VCPU_TEST(vmx_pmu_caps, basic_perf_capabilities, guest_code) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL); - vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0); vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities); - - kvm_vm_free(vm); } -static void test_fungible_perf_capabilities(union perf_capabilities host_cap) +KVM_ONE_VCPU_TEST(vmx_pmu_caps, fungible_perf_capabilities, guest_code) { const uint64_t fungible_caps = host_cap.capabilities & ~immutable_caps.capabilities; - - struct kvm_vcpu *vcpu; - struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL); int bit; for_each_set_bit(bit, &fungible_caps, 64) { @@ -150,8 +141,6 @@ static void test_fungible_perf_capabilities(union perf_capabilities host_cap) host_cap.capabilities & ~BIT_ULL(bit)); } vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities); - - kvm_vm_free(vm); } /* @@ -160,14 +149,11 @@ static void test_fungible_perf_capabilities(union perf_capabilities host_cap) * separately as they are multi-bit values, e.g. toggling or setting a single * bit can generate a false positive without dedicated safeguards. */ -static void test_immutable_perf_capabilities(union perf_capabilities host_cap) +KVM_ONE_VCPU_TEST(vmx_pmu_caps, immutable_perf_capabilities, guest_code) { const uint64_t reserved_caps = (~host_cap.capabilities | immutable_caps.capabilities) & ~format_caps.capabilities; - - struct kvm_vcpu *vcpu; - struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL); union perf_capabilities val = host_cap; int r, bit; @@ -201,8 +187,6 @@ static void test_immutable_perf_capabilities(union perf_capabilities host_cap) TEST_ASSERT(!r, "Bad PEBS FMT = 0x%x didn't fail, host = 0x%x", val.pebs_format, host_cap.pebs_format); } - - kvm_vm_free(vm); } /* @@ -211,17 +195,13 @@ static void test_immutable_perf_capabilities(union perf_capabilities host_cap) * LBR_TOS as those bits are writable across all uarch implementations (arch * LBRs will need to poke a different MSR). */ -static void test_lbr_perf_capabilities(union perf_capabilities host_cap) +KVM_ONE_VCPU_TEST(vmx_pmu_caps, lbr_perf_capabilities, guest_code) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; int r; if (!host_cap.lbr_format) return; - vm = vm_create_with_one_vcpu(&vcpu, NULL); - vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities); vcpu_set_msr(vcpu, MSR_LBR_TOS, 7); @@ -229,14 +209,10 @@ static void test_lbr_perf_capabilities(union perf_capabilities host_cap) r = _vcpu_set_msr(vcpu, MSR_LBR_TOS, 7); TEST_ASSERT(!r, "Writing LBR_TOS should fail after disabling vPMU"); - - kvm_vm_free(vm); } int main(int argc, char *argv[]) { - union perf_capabilities host_cap; - TEST_REQUIRE(get_kvm_param_bool("enable_pmu")); TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM)); @@ -248,9 +224,5 @@ int main(int argc, char *argv[]) TEST_ASSERT(host_cap.full_width_write, "Full-width writes should always be supported"); - test_basic_perf_capabilities(host_cap); - test_fungible_perf_capabilities(host_cap); - test_immutable_perf_capabilities(host_cap); - test_guest_wrmsr_perf_capabilities(host_cap); - test_lbr_perf_capabilities(host_cap); + return test_harness_run(argc, argv); } From 8d251856d4258307ef27a5a8f9020aad560a4057 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 Feb 2024 21:48:44 +0100 Subject: [PATCH 568/814] KVM: selftests: x86: Use TAP interface in the userspace_msr_exit test Use the kselftest_harness.h interface in this test to get TAP output, so that it is easier for the user to see what the test is doing. Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20240208204844.119326-9-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../kvm/x86_64/userspace_msr_exit_test.c | 54 +++++-------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index 3533dc2fbfee..9591a5fd54d7 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -8,6 +8,7 @@ #define _GNU_SOURCE /* for program_invocation_short_name */ #include +#include "kvm_test_harness.h" #include "test_util.h" #include "kvm_util.h" #include "vmx.h" @@ -527,13 +528,12 @@ static void run_guest_then_process_ucall_done(struct kvm_vcpu *vcpu) process_ucall_done(vcpu); } -static void test_msr_filter_allow(void) -{ - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; - int rc; +KVM_ONE_VCPU_TEST_SUITE(user_msr); - vm = vm_create_with_one_vcpu(&vcpu, guest_code_filter_allow); +KVM_ONE_VCPU_TEST(user_msr, msr_filter_allow, guest_code_filter_allow) +{ + struct kvm_vm *vm = vcpu->vm; + int rc; rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); @@ -585,8 +585,6 @@ static void test_msr_filter_allow(void) } else { printf("To run the instruction emulated tests set the module parameter 'kvm.force_emulation_prefix=1'\n"); } - - kvm_vm_free(vm); } static int handle_ucall(struct kvm_vcpu *vcpu) @@ -646,16 +644,12 @@ static void handle_wrmsr(struct kvm_run *run) } } -static void test_msr_filter_deny(void) +KVM_ONE_VCPU_TEST(user_msr, msr_filter_deny, guest_code_filter_deny) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; - struct kvm_run *run; + struct kvm_vm *vm = vcpu->vm; + struct kvm_run *run = vcpu->run; int rc; - vm = vm_create_with_one_vcpu(&vcpu, guest_code_filter_deny); - run = vcpu->run; - rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_INVAL | @@ -689,18 +683,13 @@ static void test_msr_filter_deny(void) done: TEST_ASSERT(msr_reads == 4, "Handled 4 rdmsr in user space"); TEST_ASSERT(msr_writes == 3, "Handled 3 wrmsr in user space"); - - kvm_vm_free(vm); } -static void test_msr_permission_bitmap(void) +KVM_ONE_VCPU_TEST(user_msr, msr_permission_bitmap, guest_code_permission_bitmap) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; + struct kvm_vm *vm = vcpu->vm; int rc; - vm = vm_create_with_one_vcpu(&vcpu, guest_code_permission_bitmap); - rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_FILTER); @@ -715,8 +704,6 @@ static void test_msr_permission_bitmap(void) vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_gs); run_guest_then_process_rdmsr(vcpu, MSR_GS_BASE); run_guest_then_process_ucall_done(vcpu); - - kvm_vm_free(vm); } #define test_user_exit_msr_ioctl(vm, cmd, arg, flag, valid_mask) \ @@ -786,31 +773,18 @@ static void run_msr_filter_flag_test(struct kvm_vm *vm) } /* Test that attempts to write to the unused bits in a flag fails. */ -static void test_user_exit_msr_flags(void) +KVM_ONE_VCPU_TEST(user_msr, user_exit_msr_flags, NULL) { - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; - - vm = vm_create_with_one_vcpu(&vcpu, NULL); + struct kvm_vm *vm = vcpu->vm; /* Test flags for KVM_CAP_X86_USER_SPACE_MSR. */ run_user_space_msr_flag_test(vm); /* Test flags and range flags for KVM_X86_SET_MSR_FILTER. */ run_msr_filter_flag_test(vm); - - kvm_vm_free(vm); } int main(int argc, char *argv[]) { - test_msr_filter_allow(); - - test_msr_filter_deny(); - - test_msr_permission_bitmap(); - - test_user_exit_msr_flags(); - - return 0; + return test_harness_run(argc, argv); } From 126190379c57b7947dc7af278bee848cb3976e10 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 22 Feb 2024 16:42:48 -0800 Subject: [PATCH 569/814] KVM: selftests: Extend VM creation's @shape to allow control of VM subtype Carve out space in the @shape passed to the various VM creation helpers to allow using the shape to control the subtype of VM, e.g. to identify x86's SEV VMs (which are "regular" VMs as far as KVM is concerned). Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerley Tng Cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Link: https://lore.kernel.org/r/20240223004258.3104051-2-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/kvm_util_base.h | 9 +++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index a6e7738a8db7..7ade281682c1 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -90,6 +90,7 @@ enum kvm_mem_region_type { struct kvm_vm { int mode; unsigned long type; + uint8_t subtype; int kvm_fd; int fd; unsigned int pgtable_levels; @@ -191,10 +192,14 @@ enum vm_guest_mode { }; struct vm_shape { - enum vm_guest_mode mode; - unsigned int type; + uint32_t type; + uint8_t mode; + uint8_t subtype; + uint16_t padding; }; +kvm_static_assert(sizeof(struct vm_shape) == sizeof(uint64_t)); + #define VM_TYPE_DEFAULT 0 #define VM_SHAPE(__mode) \ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e066d584c656..22da6a10b41f 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -225,6 +225,7 @@ struct kvm_vm *____vm_create(struct vm_shape shape) vm->mode = shape.mode; vm->type = shape.type; + vm->subtype = shape.subtype; vm->pa_bits = vm_guest_mode_params[vm->mode].pa_bits; vm->va_bits = vm_guest_mode_params[vm->mode].va_bits; From 35f50c91c43e4447803c632adba4ebceaa0b692b Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 22 Feb 2024 16:42:49 -0800 Subject: [PATCH 570/814] KVM: selftests: Make sparsebit structs const where appropriate Make all sparsebit struct pointers "const" where appropriate. This will allow adding a bitmap to track protected/encrypted physical memory that tests can access in a read-only fashion. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerley Tng Cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Signed-off-by: Michael Roth Signed-off-by: Peter Gonda [sean: massage changelog] Link: https://lore.kernel.org/r/20240223004258.3104051-3-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/include/sparsebit.h | 36 +++++++------- tools/testing/selftests/kvm/lib/sparsebit.c | 48 +++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tools/testing/selftests/kvm/include/sparsebit.h b/tools/testing/selftests/kvm/include/sparsebit.h index 12a9a4b9cead..fb5170d57fcb 100644 --- a/tools/testing/selftests/kvm/include/sparsebit.h +++ b/tools/testing/selftests/kvm/include/sparsebit.h @@ -30,26 +30,26 @@ typedef uint64_t sparsebit_num_t; struct sparsebit *sparsebit_alloc(void); void sparsebit_free(struct sparsebit **sbitp); -void sparsebit_copy(struct sparsebit *dstp, struct sparsebit *src); +void sparsebit_copy(struct sparsebit *dstp, const struct sparsebit *src); -bool sparsebit_is_set(struct sparsebit *sbit, sparsebit_idx_t idx); -bool sparsebit_is_set_num(struct sparsebit *sbit, +bool sparsebit_is_set(const struct sparsebit *sbit, sparsebit_idx_t idx); +bool sparsebit_is_set_num(const struct sparsebit *sbit, sparsebit_idx_t idx, sparsebit_num_t num); -bool sparsebit_is_clear(struct sparsebit *sbit, sparsebit_idx_t idx); -bool sparsebit_is_clear_num(struct sparsebit *sbit, +bool sparsebit_is_clear(const struct sparsebit *sbit, sparsebit_idx_t idx); +bool sparsebit_is_clear_num(const struct sparsebit *sbit, sparsebit_idx_t idx, sparsebit_num_t num); -sparsebit_num_t sparsebit_num_set(struct sparsebit *sbit); -bool sparsebit_any_set(struct sparsebit *sbit); -bool sparsebit_any_clear(struct sparsebit *sbit); -bool sparsebit_all_set(struct sparsebit *sbit); -bool sparsebit_all_clear(struct sparsebit *sbit); -sparsebit_idx_t sparsebit_first_set(struct sparsebit *sbit); -sparsebit_idx_t sparsebit_first_clear(struct sparsebit *sbit); -sparsebit_idx_t sparsebit_next_set(struct sparsebit *sbit, sparsebit_idx_t prev); -sparsebit_idx_t sparsebit_next_clear(struct sparsebit *sbit, sparsebit_idx_t prev); -sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *sbit, +sparsebit_num_t sparsebit_num_set(const struct sparsebit *sbit); +bool sparsebit_any_set(const struct sparsebit *sbit); +bool sparsebit_any_clear(const struct sparsebit *sbit); +bool sparsebit_all_set(const struct sparsebit *sbit); +bool sparsebit_all_clear(const struct sparsebit *sbit); +sparsebit_idx_t sparsebit_first_set(const struct sparsebit *sbit); +sparsebit_idx_t sparsebit_first_clear(const struct sparsebit *sbit); +sparsebit_idx_t sparsebit_next_set(const struct sparsebit *sbit, sparsebit_idx_t prev); +sparsebit_idx_t sparsebit_next_clear(const struct sparsebit *sbit, sparsebit_idx_t prev); +sparsebit_idx_t sparsebit_next_set_num(const struct sparsebit *sbit, sparsebit_idx_t start, sparsebit_num_t num); -sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *sbit, +sparsebit_idx_t sparsebit_next_clear_num(const struct sparsebit *sbit, sparsebit_idx_t start, sparsebit_num_t num); void sparsebit_set(struct sparsebit *sbitp, sparsebit_idx_t idx); @@ -62,9 +62,9 @@ void sparsebit_clear_num(struct sparsebit *sbitp, sparsebit_idx_t start, sparsebit_num_t num); void sparsebit_clear_all(struct sparsebit *sbitp); -void sparsebit_dump(FILE *stream, struct sparsebit *sbit, +void sparsebit_dump(FILE *stream, const struct sparsebit *sbit, unsigned int indent); -void sparsebit_validate_internal(struct sparsebit *sbit); +void sparsebit_validate_internal(const struct sparsebit *sbit); #ifdef __cplusplus } diff --git a/tools/testing/selftests/kvm/lib/sparsebit.c b/tools/testing/selftests/kvm/lib/sparsebit.c index 88cb6b84e6f3..cfed9d26cc71 100644 --- a/tools/testing/selftests/kvm/lib/sparsebit.c +++ b/tools/testing/selftests/kvm/lib/sparsebit.c @@ -202,7 +202,7 @@ static sparsebit_num_t node_num_set(struct node *nodep) /* Returns a pointer to the node that describes the * lowest bit index. */ -static struct node *node_first(struct sparsebit *s) +static struct node *node_first(const struct sparsebit *s) { struct node *nodep; @@ -216,7 +216,7 @@ static struct node *node_first(struct sparsebit *s) * lowest bit index > the index of the node pointed to by np. * Returns NULL if no node with a higher index exists. */ -static struct node *node_next(struct sparsebit *s, struct node *np) +static struct node *node_next(const struct sparsebit *s, struct node *np) { struct node *nodep = np; @@ -244,7 +244,7 @@ static struct node *node_next(struct sparsebit *s, struct node *np) * highest index < the index of the node pointed to by np. * Returns NULL if no node with a lower index exists. */ -static struct node *node_prev(struct sparsebit *s, struct node *np) +static struct node *node_prev(const struct sparsebit *s, struct node *np) { struct node *nodep = np; @@ -273,7 +273,7 @@ static struct node *node_prev(struct sparsebit *s, struct node *np) * subtree and duplicates the bit settings to the newly allocated nodes. * Returns the newly allocated copy of subtree. */ -static struct node *node_copy_subtree(struct node *subtree) +static struct node *node_copy_subtree(const struct node *subtree) { struct node *root; @@ -307,7 +307,7 @@ static struct node *node_copy_subtree(struct node *subtree) * index is within the bits described by the mask bits or the number of * contiguous bits set after the mask. Returns NULL if there is no such node. */ -static struct node *node_find(struct sparsebit *s, sparsebit_idx_t idx) +static struct node *node_find(const struct sparsebit *s, sparsebit_idx_t idx) { struct node *nodep; @@ -393,7 +393,7 @@ static struct node *node_add(struct sparsebit *s, sparsebit_idx_t idx) } /* Returns whether all the bits in the sparsebit array are set. */ -bool sparsebit_all_set(struct sparsebit *s) +bool sparsebit_all_set(const struct sparsebit *s) { /* * If any nodes there must be at least one bit set. Only case @@ -775,7 +775,7 @@ static void node_reduce(struct sparsebit *s, struct node *nodep) /* Returns whether the bit at the index given by idx, within the * sparsebit array is set or not. */ -bool sparsebit_is_set(struct sparsebit *s, sparsebit_idx_t idx) +bool sparsebit_is_set(const struct sparsebit *s, sparsebit_idx_t idx) { struct node *nodep; @@ -921,7 +921,7 @@ static inline sparsebit_idx_t node_first_clear(struct node *nodep, int start) * used by test cases after they detect an unexpected condition, as a means * to capture diagnostic information. */ -static void sparsebit_dump_internal(FILE *stream, struct sparsebit *s, +static void sparsebit_dump_internal(FILE *stream, const struct sparsebit *s, unsigned int indent) { /* Dump the contents of s */ @@ -969,7 +969,7 @@ void sparsebit_free(struct sparsebit **sbitp) * sparsebit_alloc(). It can though already have bits set, which * if different from src will be cleared. */ -void sparsebit_copy(struct sparsebit *d, struct sparsebit *s) +void sparsebit_copy(struct sparsebit *d, const struct sparsebit *s) { /* First clear any bits already set in the destination */ sparsebit_clear_all(d); @@ -981,7 +981,7 @@ void sparsebit_copy(struct sparsebit *d, struct sparsebit *s) } /* Returns whether num consecutive bits starting at idx are all set. */ -bool sparsebit_is_set_num(struct sparsebit *s, +bool sparsebit_is_set_num(const struct sparsebit *s, sparsebit_idx_t idx, sparsebit_num_t num) { sparsebit_idx_t next_cleared; @@ -1005,14 +1005,14 @@ bool sparsebit_is_set_num(struct sparsebit *s, } /* Returns whether the bit at the index given by idx. */ -bool sparsebit_is_clear(struct sparsebit *s, +bool sparsebit_is_clear(const struct sparsebit *s, sparsebit_idx_t idx) { return !sparsebit_is_set(s, idx); } /* Returns whether num consecutive bits starting at idx are all cleared. */ -bool sparsebit_is_clear_num(struct sparsebit *s, +bool sparsebit_is_clear_num(const struct sparsebit *s, sparsebit_idx_t idx, sparsebit_num_t num) { sparsebit_idx_t next_set; @@ -1041,13 +1041,13 @@ bool sparsebit_is_clear_num(struct sparsebit *s, * value. Use sparsebit_any_set(), instead of sparsebit_num_set() > 0, * to determine if the sparsebit array has any bits set. */ -sparsebit_num_t sparsebit_num_set(struct sparsebit *s) +sparsebit_num_t sparsebit_num_set(const struct sparsebit *s) { return s->num_set; } /* Returns whether any bit is set in the sparsebit array. */ -bool sparsebit_any_set(struct sparsebit *s) +bool sparsebit_any_set(const struct sparsebit *s) { /* * Nodes only describe set bits. If any nodes then there @@ -1070,20 +1070,20 @@ bool sparsebit_any_set(struct sparsebit *s) } /* Returns whether all the bits in the sparsebit array are cleared. */ -bool sparsebit_all_clear(struct sparsebit *s) +bool sparsebit_all_clear(const struct sparsebit *s) { return !sparsebit_any_set(s); } /* Returns whether all the bits in the sparsebit array are set. */ -bool sparsebit_any_clear(struct sparsebit *s) +bool sparsebit_any_clear(const struct sparsebit *s) { return !sparsebit_all_set(s); } /* Returns the index of the first set bit. Abort if no bits are set. */ -sparsebit_idx_t sparsebit_first_set(struct sparsebit *s) +sparsebit_idx_t sparsebit_first_set(const struct sparsebit *s) { struct node *nodep; @@ -1097,7 +1097,7 @@ sparsebit_idx_t sparsebit_first_set(struct sparsebit *s) /* Returns the index of the first cleared bit. Abort if * no bits are cleared. */ -sparsebit_idx_t sparsebit_first_clear(struct sparsebit *s) +sparsebit_idx_t sparsebit_first_clear(const struct sparsebit *s) { struct node *nodep1, *nodep2; @@ -1151,7 +1151,7 @@ sparsebit_idx_t sparsebit_first_clear(struct sparsebit *s) /* Returns index of next bit set within s after the index given by prev. * Returns 0 if there are no bits after prev that are set. */ -sparsebit_idx_t sparsebit_next_set(struct sparsebit *s, +sparsebit_idx_t sparsebit_next_set(const struct sparsebit *s, sparsebit_idx_t prev) { sparsebit_idx_t lowest_possible = prev + 1; @@ -1244,7 +1244,7 @@ sparsebit_idx_t sparsebit_next_set(struct sparsebit *s, /* Returns index of next bit cleared within s after the index given by prev. * Returns 0 if there are no bits after prev that are cleared. */ -sparsebit_idx_t sparsebit_next_clear(struct sparsebit *s, +sparsebit_idx_t sparsebit_next_clear(const struct sparsebit *s, sparsebit_idx_t prev) { sparsebit_idx_t lowest_possible = prev + 1; @@ -1300,7 +1300,7 @@ sparsebit_idx_t sparsebit_next_clear(struct sparsebit *s, * and returns the index of the first sequence of num consecutively set * bits. Returns a value of 0 of no such sequence exists. */ -sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *s, +sparsebit_idx_t sparsebit_next_set_num(const struct sparsebit *s, sparsebit_idx_t start, sparsebit_num_t num) { sparsebit_idx_t idx; @@ -1335,7 +1335,7 @@ sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *s, * and returns the index of the first sequence of num consecutively cleared * bits. Returns a value of 0 of no such sequence exists. */ -sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *s, +sparsebit_idx_t sparsebit_next_clear_num(const struct sparsebit *s, sparsebit_idx_t start, sparsebit_num_t num) { sparsebit_idx_t idx; @@ -1583,7 +1583,7 @@ static size_t display_range(FILE *stream, sparsebit_idx_t low, * contiguous bits. This is done because '-' is used to specify command-line * options, and sometimes ranges are specified as command-line arguments. */ -void sparsebit_dump(FILE *stream, struct sparsebit *s, +void sparsebit_dump(FILE *stream, const struct sparsebit *s, unsigned int indent) { size_t current_line_len = 0; @@ -1681,7 +1681,7 @@ void sparsebit_dump(FILE *stream, struct sparsebit *s, * s. On error, diagnostic information is printed to stderr and * abort is called. */ -void sparsebit_validate_internal(struct sparsebit *s) +void sparsebit_validate_internal(const struct sparsebit *s) { bool error_detected = false; struct node *nodep, *prev = NULL; From 57e19f05775847d9d8565dad2cee6bbec03cdb06 Mon Sep 17 00:00:00 2001 From: Ackerley Tng Date: Thu, 22 Feb 2024 16:42:50 -0800 Subject: [PATCH 571/814] KVM: selftests: Add a macro to iterate over a sparsebit range Add sparsebit_for_each_set_range() to allow iterator over a range of set bits in a range. This will be used by x86 SEV guests to process protected physical pages (each such page needs to be encrypted _after_ being "added" to the VM). Tested-by: Carlos Bilbao Signed-off-by: Ackerley Tng [sean: split to separate patch] Link: https://lore.kernel.org/r/20240223004258.3104051-4-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/include/sparsebit.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/testing/selftests/kvm/include/sparsebit.h b/tools/testing/selftests/kvm/include/sparsebit.h index fb5170d57fcb..bc760761e1a3 100644 --- a/tools/testing/selftests/kvm/include/sparsebit.h +++ b/tools/testing/selftests/kvm/include/sparsebit.h @@ -66,6 +66,26 @@ void sparsebit_dump(FILE *stream, const struct sparsebit *sbit, unsigned int indent); void sparsebit_validate_internal(const struct sparsebit *sbit); +/* + * Iterate over an inclusive ranges within sparsebit @s. In each iteration, + * @range_begin and @range_end will take the beginning and end of the set + * range, which are of type sparsebit_idx_t. + * + * For example, if the range [3, 7] (inclusive) is set, within the + * iteration,@range_begin will take the value 3 and @range_end will take + * the value 7. + * + * Ensure that there is at least one bit set before using this macro with + * sparsebit_any_set(), because sparsebit_first_set() will abort if none + * are set. + */ +#define sparsebit_for_each_set_range(s, range_begin, range_end) \ + for (range_begin = sparsebit_first_set(s), \ + range_end = sparsebit_next_clear(s, range_begin) - 1; \ + range_begin && range_end; \ + range_begin = sparsebit_next_set(s, range_end), \ + range_end = sparsebit_next_clear(s, range_begin) - 1) + #ifdef __cplusplus } #endif From cd8eb2913205e5a13ec807061c8f72d6fee624c7 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Thu, 22 Feb 2024 16:42:51 -0800 Subject: [PATCH 572/814] KVM: selftests: Add support for allocating/managing protected guest memory Add support for differentiating between protected (a.k.a. private, a.k.a. encrypted) memory and normal (a.k.a. shared) memory for VMs that support protected guest memory, e.g. x86's SEV. Provide and manage a common bitmap for tracking whether a given physical page resides in protected memory, as support for protected memory isn't x86 specific, i.e. adding a arch hook would be a net negative now, and in the future. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerley Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Reviewed-by: Itaru Kitayama Tested-by: Carlos Bilbao Originally-by: Michael Roth Signed-off-by: Peter Gonda Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/20240223004258.3104051-5-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/kvm_util_base.h | 25 +++++++++++++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 22 +++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 7ade281682c1..746cc13b5d6d 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -46,6 +46,7 @@ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ struct userspace_mem_region { struct kvm_userspace_memory_region2 region; struct sparsebit *unused_phy_pages; + struct sparsebit *protected_phy_pages; int fd; off_t offset; enum vm_mem_backing_src_type backing_src_type; @@ -569,6 +570,13 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, uint64_t guest_paddr, uint32_t slot, uint64_t npages, uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset); +#ifndef vm_arch_has_protected_memory +static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) +{ + return false; +} +#endif + void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); @@ -832,10 +840,23 @@ const char *exit_reason_str(unsigned int exit_reason); vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, uint32_t memslot); -vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, - vm_paddr_t paddr_min, uint32_t memslot); +vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, + vm_paddr_t paddr_min, uint32_t memslot, + bool protected); vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); +static inline vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, + vm_paddr_t paddr_min, uint32_t memslot) +{ + /* + * By default, allocate memory as protected for VMs that support + * protected memory, as the majority of memory for such VMs is + * protected, i.e. using shared memory is effectively opt-in. + */ + return __vm_phy_pages_alloc(vm, num, paddr_min, memslot, + vm_arch_has_protected_memory(vm)); +} + /* * ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also * loads the test binary into guest memory and creates an IRQ chip (x86 only). diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 22da6a10b41f..2845349a98ca 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -666,6 +666,7 @@ static void __vm_mem_region_delete(struct kvm_vm *vm, vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); sparsebit_free(®ion->unused_phy_pages); + sparsebit_free(®ion->protected_phy_pages); ret = munmap(region->mmap_start, region->mmap_size); TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); if (region->fd >= 0) { @@ -1047,6 +1048,8 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, } region->unused_phy_pages = sparsebit_alloc(); + if (vm_arch_has_protected_memory(vm)) + region->protected_phy_pages = sparsebit_alloc(); sparsebit_set_num(region->unused_phy_pages, guest_paddr >> vm->page_shift, npages); region->region.slot = slot; @@ -1873,6 +1876,10 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) region->host_mem); fprintf(stream, "%*sunused_phy_pages: ", indent + 2, ""); sparsebit_dump(stream, region->unused_phy_pages, 0); + if (region->protected_phy_pages) { + fprintf(stream, "%*sprotected_phy_pages: ", indent + 2, ""); + sparsebit_dump(stream, region->protected_phy_pages, 0); + } } fprintf(stream, "%*sMapped Virtual Pages:\n", indent, ""); sparsebit_dump(stream, vm->vpages_mapped, indent + 2); @@ -1974,6 +1981,7 @@ const char *exit_reason_str(unsigned int exit_reason) * num - number of pages * paddr_min - Physical address minimum * memslot - Memory region to allocate page from + * protected - True if the pages will be used as protected/private memory * * Output Args: None * @@ -1985,8 +1993,9 @@ const char *exit_reason_str(unsigned int exit_reason) * and their base address is returned. A TEST_ASSERT failure occurs if * not enough pages are available at or above paddr_min. */ -vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, - vm_paddr_t paddr_min, uint32_t memslot) +vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, + vm_paddr_t paddr_min, uint32_t memslot, + bool protected) { struct userspace_mem_region *region; sparsebit_idx_t pg, base; @@ -1999,8 +2008,10 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, paddr_min, vm->page_size); region = memslot2region(vm, memslot); - base = pg = paddr_min >> vm->page_shift; + TEST_ASSERT(!protected || region->protected_phy_pages, + "Region doesn't support protected memory"); + base = pg = paddr_min >> vm->page_shift; do { for (; pg < base + num; ++pg) { if (!sparsebit_is_set(region->unused_phy_pages, pg)) { @@ -2019,8 +2030,11 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, abort(); } - for (pg = base; pg < base + num; ++pg) + for (pg = base; pg < base + num; ++pg) { sparsebit_clear(region->unused_phy_pages, pg); + if (protected) + sparsebit_set(region->protected_phy_pages, pg); + } return base * vm->page_size; } From d210eebb51a23ce45b16c493a51c17b664e81de7 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 22 Feb 2024 16:42:52 -0800 Subject: [PATCH 573/814] KVM: selftests: Add support for protected vm_vaddr_* allocations Test programs may wish to allocate shared vaddrs for things like sharing memory with the guest. Since protected vms will have their memory encrypted by default an interface is needed to explicitly request shared pages. Implement this by splitting the common code out from vm_vaddr_alloc() and introducing a new vm_vaddr_alloc_shared(). Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Reviewed-by: Itaru Kitayama Tested-by: Carlos Bilbao Signed-off-by: Michael Roth Signed-off-by: Peter Gonda Link: https://lore.kernel.org/r/20240223004258.3104051-6-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/kvm_util_base.h | 3 +++ tools/testing/selftests/kvm/lib/kvm_util.c | 26 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 746cc13b5d6d..ba90eb7edc5e 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -586,6 +586,9 @@ vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_mi vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min); vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, enum kvm_mem_region_type type); +vm_vaddr_t vm_vaddr_alloc_shared(struct kvm_vm *vm, size_t sz, + vm_vaddr_t vaddr_min, + enum kvm_mem_region_type type); vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages); vm_vaddr_t __vm_vaddr_alloc_page(struct kvm_vm *vm, enum kvm_mem_region_type type); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 2845349a98ca..a4ef5185bb03 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1380,15 +1380,17 @@ va_found: return pgidx_start * vm->page_size; } -vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, - enum kvm_mem_region_type type) +static vm_vaddr_t ____vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, + vm_vaddr_t vaddr_min, + enum kvm_mem_region_type type, + bool protected) { uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); virt_pgd_alloc(vm); - vm_paddr_t paddr = vm_phy_pages_alloc(vm, pages, - KVM_UTIL_MIN_PFN * vm->page_size, - vm->memslots[type]); + vm_paddr_t paddr = __vm_phy_pages_alloc(vm, pages, + KVM_UTIL_MIN_PFN * vm->page_size, + vm->memslots[type], protected); /* * Find an unused range of virtual page addresses of at least @@ -1408,6 +1410,20 @@ vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, return vaddr_start; } +vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, + enum kvm_mem_region_type type) +{ + return ____vm_vaddr_alloc(vm, sz, vaddr_min, type, + vm_arch_has_protected_memory(vm)); +} + +vm_vaddr_t vm_vaddr_alloc_shared(struct kvm_vm *vm, size_t sz, + vm_vaddr_t vaddr_min, + enum kvm_mem_region_type type) +{ + return ____vm_vaddr_alloc(vm, sz, vaddr_min, type, false); +} + /* * VM Virtual Address Allocate * From 31e00dae72fda939a084cda86b068ac9c302a2d3 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Thu, 22 Feb 2024 16:42:53 -0800 Subject: [PATCH 574/814] KVM: selftests: Explicitly ucall pool from shared memory Allocate the common ucall pool using vm_vaddr_alloc_shared() so that the ucall structures will be placed in shared (unencrypted) memory for VMs with support for protected (encrypted) memory, e.g. x86's SEV. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Signed-off-by: Peter Gonda [sean: massage changelog] Link: https://lore.kernel.org/r/20240223004258.3104051-7-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/lib/ucall_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index 816a3fa109bf..f5af65a41c29 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -29,7 +29,8 @@ void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) vm_vaddr_t vaddr; int i; - vaddr = __vm_vaddr_alloc(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR, MEM_REGION_DATA); + vaddr = vm_vaddr_alloc_shared(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR, + MEM_REGION_DATA); hdr = (struct ucall_header *)addr_gva2hva(vm, vaddr); memset(hdr, 0, sizeof(*hdr)); From d6f4de70f73a106986ee315d7d512539f2f3303a Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 24 Oct 2023 23:58:20 +0200 Subject: [PATCH 575/814] net: sunrpc: Fix an off by one in rpc_sockaddr2uaddr() The intent is to check if the strings' are truncated or not. So, >= should be used instead of >, because strlcat() and snprintf() return the length of the output, excluding the trailing NULL. Fixes: a02d69261134 ("SUNRPC: Provide functions for managing universal addresses") Signed-off-by: Christophe JAILLET Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust --- net/sunrpc/addr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index d435bffc6199..97ff11973c49 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -284,10 +284,10 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) } if (snprintf(portbuf, sizeof(portbuf), - ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) + ".%u.%u", port >> 8, port & 0xff) >= (int)sizeof(portbuf)) return NULL; - if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) + if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) >= sizeof(addrbuf)) return NULL; return kstrdup(addrbuf, gfp_flags); From 6e21eda471129b1b783c5212ec9a738fa7de204d Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Wed, 17 Jan 2024 14:59:12 -0500 Subject: [PATCH 576/814] SUNRPC: add xrpt id to rpc_stats_latency tracepoint In order to get the latency per xprt under the same clientid this patch adds xprt_id to the tracepoint output. Signed-off-by: Olga Kornievskaia Tested-by: Chen Hanxiao Signed-off-by: Trond Myklebust --- include/trace/events/sunrpc.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index cdd3a45e6003..4a2abf9daa46 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -639,6 +639,7 @@ TRACE_EVENT(rpc_stats_latency, __field(unsigned long, backlog) __field(unsigned long, rtt) __field(unsigned long, execute) + __field(u32, xprt_id) ), TP_fast_assign( @@ -651,13 +652,16 @@ TRACE_EVENT(rpc_stats_latency, __entry->backlog = ktime_to_us(backlog); __entry->rtt = ktime_to_us(rtt); __entry->execute = ktime_to_us(execute); + __entry->xprt_id = task->tk_xprt->id; ), TP_printk(SUNRPC_TRACE_TASK_SPECIFIER - " xid=0x%08x %sv%d %s backlog=%lu rtt=%lu execute=%lu", + " xid=0x%08x %sv%d %s backlog=%lu rtt=%lu execute=%lu" + " xprt_id=%d", __entry->task_id, __entry->client_id, __entry->xid, __get_str(progname), __entry->version, __get_str(procname), - __entry->backlog, __entry->rtt, __entry->execute) + __entry->backlog, __entry->rtt, __entry->execute, + __entry->xprt_id) ); TRACE_EVENT(rpc_xdr_overflow, From 490566edad2309f1fe086887efa311fdf65b4a04 Mon Sep 17 00:00:00 2001 From: Chen Hanxiao Date: Thu, 25 Jan 2024 13:52:42 +0800 Subject: [PATCH 577/814] NFS: Display the "fsc=" mount option if it is set With this patch, mount command will show fsc=xxx if set: If -o fsc=6666 clientaddr=192.168.122.208,fsc=6666,local_lock=none If only -o fsc clientaddr=192.168.122.208,fsc,local_lock=none Signed-off-by: Chen Hanxiao Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 075b31c93f87..dc03f98f7616 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -516,8 +516,16 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, else nfs_show_nfsv4_options(m, nfss, showdefaults); - if (nfss->options & NFS_OPTION_FSCACHE) + if (nfss->options & NFS_OPTION_FSCACHE) { +#ifdef CONFIG_NFS_FSCACHE + if (nfss->fscache_uniq) + seq_printf(m, ",fsc=%s", nfss->fscache_uniq); + else + seq_puts(m, ",fsc"); +#else seq_puts(m, ",fsc"); +#endif + } if (nfss->options & NFS_OPTION_MIGRATION) seq_puts(m, ",migration"); From 251a658bbfceafb4d58c76b77682c8bf7bcfad65 Mon Sep 17 00:00:00 2001 From: Jorge Mora Date: Thu, 25 Jan 2024 07:56:12 -0700 Subject: [PATCH 578/814] NFSv4.2: fix nfs4_listxattr kernel BUG at mm/usercopy.c:102 A call to listxattr() with a buffer size = 0 returns the actual size of the buffer needed for a subsequent call. When size > 0, nfs4_listxattr() does not return an error because either generic_listxattr() or nfs4_listxattr_nfs4_label() consumes exactly all the bytes then size is 0 when calling nfs4_listxattr_nfs4_user() which then triggers the following kernel BUG: [ 99.403778] kernel BUG at mm/usercopy.c:102! [ 99.404063] Internal error: Oops - BUG: 00000000f2000800 [#1] SMP [ 99.408463] CPU: 0 PID: 3310 Comm: python3 Not tainted 6.6.0-61.fc40.aarch64 #1 [ 99.415827] Call trace: [ 99.415985] usercopy_abort+0x70/0xa0 [ 99.416227] __check_heap_object+0x134/0x158 [ 99.416505] check_heap_object+0x150/0x188 [ 99.416696] __check_object_size.part.0+0x78/0x168 [ 99.416886] __check_object_size+0x28/0x40 [ 99.417078] listxattr+0x8c/0x120 [ 99.417252] path_listxattr+0x78/0xe0 [ 99.417476] __arm64_sys_listxattr+0x28/0x40 [ 99.417723] invoke_syscall+0x78/0x100 [ 99.417929] el0_svc_common.constprop.0+0x48/0xf0 [ 99.418186] do_el0_svc+0x24/0x38 [ 99.418376] el0_svc+0x3c/0x110 [ 99.418554] el0t_64_sync_handler+0x120/0x130 [ 99.418788] el0t_64_sync+0x194/0x198 [ 99.418994] Code: aa0003e3 d000a3e0 91310000 97f49bdb (d4210000) Issue is reproduced when generic_listxattr() returns 'system.nfs4_acl', thus calling lisxattr() with size = 16 will trigger the bug. Add check on nfs4_listxattr() to return ERANGE error when it is called with size > 0 and the return value is greater than size. Fixes: 012a211abd5d ("NFSv4.2: hook in the user extended attribute handlers") Signed-off-by: Jorge Mora Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 23819a756508..b2ff8c7a2149 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -10615,29 +10615,33 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size) { ssize_t error, error2, error3; + size_t left = size; - error = generic_listxattr(dentry, list, size); + error = generic_listxattr(dentry, list, left); if (error < 0) return error; if (list) { list += error; - size -= error; + left -= error; } - error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size); + error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, left); if (error2 < 0) return error2; if (list) { list += error2; - size -= error2; + left -= error2; } - error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size); + error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, left); if (error3 < 0) return error3; - return error + error2 + error3; + error += error2 + error3; + if (size && error > size) + return -ERANGE; + return error; } static void nfs4_enable_swap(struct inode *inode) From bcac8bff90a6ee1629f90669cdb9d28fb86049b0 Mon Sep 17 00:00:00 2001 From: Jorge Mora Date: Thu, 25 Jan 2024 07:51:28 -0700 Subject: [PATCH 579/814] NFSv4.2: fix listxattr maximum XDR buffer size Switch order of operations to avoid creating a short XDR buffer: e.g., buflen = 12, old xdrlen = 12, new xdrlen = 20. Having a short XDR buffer leads to lxa_maxcount be a few bytes less than what is needed to retrieve the whole list when using a buflen as returned by a call with size = 0: buflen = listxattr(path, NULL, 0); buf = malloc(buflen); buflen = listxattr(path, buf, buflen); For a file with one attribute (name = '123456'), the first call with size = 0 will return buflen = 12 ('user.123456\x00'). The second call with size = 12, sends LISTXATTRS with lxa_maxcount = 12 + 8 (cookie) + 4 (array count) = 24. The XDR buffer needs 8 (cookie) + 4 (array count) + 4 (name count) + 6 (name len) + 2 (padding) + 4 (eof) = 28 which is 4 bytes shorter than the lxa_maxcount provided in the call. Fixes: 04a5da690e8f ("NFSv4.2: define limits and sizes for user xattr handling") Signed-off-by: Jorge Mora Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust --- fs/nfs/nfs42.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h index b59876b01a1e..0282d93c8bcc 100644 --- a/fs/nfs/nfs42.h +++ b/fs/nfs/nfs42.h @@ -55,11 +55,14 @@ int nfs42_proc_removexattr(struct inode *inode, const char *name); * They would be 7 bytes long in the eventual buffer ("user.x\0"), and * 8 bytes long XDR-encoded. * - * Include the trailing eof word as well. + * Include the trailing eof word as well and make the result a multiple + * of 4 bytes. */ static inline u32 nfs42_listxattr_xdrsize(u32 buflen) { - return ((buflen / (XATTR_USER_PREFIX_LEN + 2)) * 8) + 4; + u32 size = 8 * buflen / (XATTR_USER_PREFIX_LEN + 2) + 4; + + return (size + 3) & ~3; } #endif /* CONFIG_NFS_V4_2 */ #endif /* __LINUX_FS_NFS_NFS4_2_H */ From 47f7c956327ff4ff4ddf1305e8571ce530157091 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Fri, 26 Jan 2024 13:04:16 -0500 Subject: [PATCH 580/814] pnfs/filelayout: add tracepoint to getdeviceinfo While decoding filelayout getdeviceinfo received, print out the information about the location of data servers (IPs). Generic getdeviceinfo tracepoints prints the MDS's ip for the dstaddr. In this patch, separate the MDS's address from the DS's addresses. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust --- fs/nfs/filelayout/filelayoutdev.c | 2 ++ fs/nfs/nfs4trace.c | 2 ++ fs/nfs/nfs4trace.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c index acf4b88889dc..4fa304fa5bc4 100644 --- a/fs/nfs/filelayout/filelayoutdev.c +++ b/fs/nfs/filelayout/filelayoutdev.c @@ -35,6 +35,7 @@ #include "../internal.h" #include "../nfs4session.h" #include "filelayout.h" +#include "../nfs4trace.h" #define NFSDBG_FACILITY NFSDBG_PNFS_LD @@ -172,6 +173,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); if (!dsaddr->ds_list[i]) goto out_err_drain_dsaddrs; + trace_fl_getdevinfo(server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr); /* If DS was already in cache, free ds addrs */ while (!list_empty(&dsaddrs)) { diff --git a/fs/nfs/nfs4trace.c b/fs/nfs/nfs4trace.c index d9ac556bebcf..d22c6670f770 100644 --- a/fs/nfs/nfs4trace.c +++ b/fs/nfs/nfs4trace.c @@ -28,4 +28,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_pagelist); EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_read_error); EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_write_error); EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_commit_error); + +EXPORT_TRACEPOINT_SYMBOL_GPL(fl_getdevinfo); #endif diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index d27919d7241d..713d080fd268 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -1991,6 +1991,34 @@ DECLARE_EVENT_CLASS(nfs4_deviceid_status, DEFINE_PNFS_DEVICEID_STATUS(nfs4_getdeviceinfo); DEFINE_PNFS_DEVICEID_STATUS(nfs4_find_deviceid); +TRACE_EVENT(fl_getdevinfo, + TP_PROTO( + const struct nfs_server *server, + const struct nfs4_deviceid *deviceid, + char *ds_remotestr + ), + TP_ARGS(server, deviceid, ds_remotestr), + + TP_STRUCT__entry( + __string(mds_addr, server->nfs_client->cl_hostname) + __array(unsigned char, deviceid, NFS4_DEVICEID4_SIZE) + __string(ds_ips, ds_remotestr) + ), + + TP_fast_assign( + __assign_str(mds_addr, server->nfs_client->cl_hostname); + __assign_str(ds_ips, ds_remotestr); + memcpy(__entry->deviceid, deviceid->data, + NFS4_DEVICEID4_SIZE); + ), + TP_printk( + "deviceid=%s, mds_addr=%s, ds_ips=%s", + __print_hex(__entry->deviceid, NFS4_DEVICEID4_SIZE), + __get_str(mds_addr), + __get_str(ds_ips) + ) +); + DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event, TP_PROTO( const struct nfs_pgio_header *hdr From 1443f76b26619d10ef5dcd08221faebfe93b04d8 Mon Sep 17 00:00:00 2001 From: Chen Hanxiao Date: Wed, 31 Jan 2024 17:49:17 +0800 Subject: [PATCH 581/814] nfs: fix regression in handling of fsc= option in NFSv4 Setting the uniquifier for fscache via the fsc= mount option is currently broken in NFSv4. Fix this by passing fscache_uniq to root_fc if possible. Signed-off-by: Chen Hanxiao Reviewed-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4super.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index d09bcfd7db89..8da5a9c000f4 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -145,6 +145,7 @@ static int do_nfs4_mount(struct nfs_server *server, const char *export_path) { struct nfs_fs_context *root_ctx; + struct nfs_fs_context *ctx; struct fs_context *root_fc; struct vfsmount *root_mnt; struct dentry *dentry; @@ -157,6 +158,12 @@ static int do_nfs4_mount(struct nfs_server *server, .dirfd = -1, }; + struct fs_parameter param_fsc = { + .key = "fsc", + .type = fs_value_is_string, + .dirfd = -1, + }; + if (IS_ERR(server)) return PTR_ERR(server); @@ -168,9 +175,26 @@ static int do_nfs4_mount(struct nfs_server *server, kfree(root_fc->source); root_fc->source = NULL; + ctx = nfs_fc2context(fc); root_ctx = nfs_fc2context(root_fc); root_ctx->internal = true; root_ctx->server = server; + + if (ctx->fscache_uniq) { + len = strlen(ctx->fscache_uniq); + param_fsc.size = len; + param_fsc.string = kmemdup_nul(ctx->fscache_uniq, len, GFP_KERNEL); + if (param_fsc.string == NULL) { + put_fs_context(root_fc); + return -ENOMEM; + } + ret = vfs_parse_fs_param(root_fc, ¶m_fsc); + kfree(param_fsc.string); + if (ret < 0) { + put_fs_context(root_fc); + return ret; + } + } /* We leave export_path unset as it's not used to find the root. */ len = strlen(hostname) + 5; From 2c35f43b5a4b9cdfaa6fdd946f5a212615dac8eb Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Tue, 30 Jan 2024 11:38:25 -0800 Subject: [PATCH 582/814] SUNRPC: increase size of rpc_wait_queue.qlen from unsigned short to unsigned int When the NFS client is under extreme load the rpc_wait_queue.qlen counter can be overflowed. Here is an instant of the backlog queue overflow in a real world environment shown by drgn helper: rpc_task_stats(rpc_clnt): ------------------------- rpc_clnt: 0xffff92b65d2bae00 rpc_xprt: 0xffff9275db64f000 Queue: sending[64887] pending[524] backlog[30441] binding[0] XMIT task: 0xffff925c6b1d8e98 WRITE: 750654 __dta_call_status_580: 65463 __dta_call_transmit_status_579: 1 call_reserveresult: 685189 nfs_client_init_is_complete: 1 COMMIT: 584 call_reserveresult: 573 __dta_call_status_580: 11 ACCESS: 1 __dta_call_status_580: 1 GETATTR: 10 __dta_call_status_580: 4 call_reserveresult: 6 751249 tasks for server 111.222.333.444 Total tasks: 751249 count_rpc_wait_queues(xprt): ---------------------------- **** rpc_xprt: 0xffff9275db64f000 num_reqs: 65511 wait_queue: xprt_binding[0] cnt: 0 wait_queue: xprt_binding[1] cnt: 0 wait_queue: xprt_binding[2] cnt: 0 wait_queue: xprt_binding[3] cnt: 0 rpc_wait_queue[xprt_binding].qlen: 0 maxpriority: 0 wait_queue: xprt_sending[0] cnt: 0 wait_queue: xprt_sending[1] cnt: 64887 wait_queue: xprt_sending[2] cnt: 0 wait_queue: xprt_sending[3] cnt: 0 rpc_wait_queue[xprt_sending].qlen: 64887 maxpriority: 3 wait_queue: xprt_pending[0] cnt: 524 wait_queue: xprt_pending[1] cnt: 0 wait_queue: xprt_pending[2] cnt: 0 wait_queue: xprt_pending[3] cnt: 0 rpc_wait_queue[xprt_pending].qlen: 524 maxpriority: 0 wait_queue: xprt_backlog[0] cnt: 0 wait_queue: xprt_backlog[1] cnt: 685801 wait_queue: xprt_backlog[2] cnt: 0 wait_queue: xprt_backlog[3] cnt: 0 rpc_wait_queue[xprt_backlog].qlen: 30441 maxpriority: 3 [task cnt mismatch] There is no effect on operations when this overflow occurs. However it causes confusion when trying to diagnose the performance problem. Signed-off-by: Dai Ngo Reviewed-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 2d61987b3545..0c77ba488bba 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -197,7 +197,7 @@ struct rpc_wait_queue { unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ unsigned char priority; /* current priority */ unsigned char nr; /* # tasks remaining for cookie */ - unsigned short qlen; /* total # tasks waiting in queue */ + unsigned int qlen; /* total # tasks waiting in queue */ struct rpc_timer timer_list; #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) const char * name; From be1bd4c5394ff7eb6f14aaf8005824ed1946bb82 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Thu, 22 Feb 2024 16:42:54 -0800 Subject: [PATCH 583/814] KVM: selftests: Allow tagging protected memory in guest page tables Add support for tagging and untagging guest physical address, e.g. to allow x86's SEV and TDX guests to embed shared vs. private information in the GPA. SEV (encryption, a.k.a. C-bit) and TDX (shared, a.k.a. S-bit) steal bits from the guest's physical address space that is consumed by the CPU metadata, i.e. effectively aliases the "real" GPA. Implement generic "tagging" so that the shared vs. private metadata can be managed by x86 without bleeding too many details into common code. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Originally-by: Michael Roth Signed-off-by: Peter Gonda Link: https://lore.kernel.org/r/20240223004258.3104051-8-seanjc@google.com Signed-off-by: Sean Christopherson --- .../kvm/include/aarch64/kvm_util_arch.h | 7 +++++++ .../selftests/kvm/include/kvm_util_base.h | 13 ++++++++++++ .../kvm/include/riscv/kvm_util_arch.h | 7 +++++++ .../kvm/include/s390x/kvm_util_arch.h | 7 +++++++ .../kvm/include/x86_64/kvm_util_arch.h | 21 +++++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 17 +++++++++++++++ .../selftests/kvm/lib/x86_64/processor.c | 15 ++++++++++++- 7 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/kvm/include/aarch64/kvm_util_arch.h create mode 100644 tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h create mode 100644 tools/testing/selftests/kvm/include/s390x/kvm_util_arch.h create mode 100644 tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h diff --git a/tools/testing/selftests/kvm/include/aarch64/kvm_util_arch.h b/tools/testing/selftests/kvm/include/aarch64/kvm_util_arch.h new file mode 100644 index 000000000000..e43a57d99b56 --- /dev/null +++ b/tools/testing/selftests/kvm/include/aarch64/kvm_util_arch.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UTIL_ARCH_H +#define SELFTEST_KVM_UTIL_ARCH_H + +struct kvm_vm_arch {}; + +#endif // SELFTEST_KVM_UTIL_ARCH_H diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index ba90eb7edc5e..4a40b332115d 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -18,9 +18,11 @@ #include #include +#include #include +#include "kvm_util_arch.h" #include "sparsebit.h" /* @@ -113,6 +115,9 @@ struct kvm_vm { vm_vaddr_t idt; vm_vaddr_t handlers; uint32_t dirty_ring_size; + uint64_t gpa_tag_mask; + + struct kvm_vm_arch arch; /* Cache of information for binary stats interface */ int stats_fd; @@ -601,6 +606,12 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa); + +static inline vm_paddr_t vm_untag_gpa(struct kvm_vm *vm, vm_paddr_t gpa) +{ + return gpa & ~vm->gpa_tag_mask; +} + void vcpu_run(struct kvm_vcpu *vcpu); int _vcpu_run(struct kvm_vcpu *vcpu); @@ -1113,4 +1124,6 @@ void kvm_selftest_arch_init(void); void kvm_arch_vm_post_create(struct kvm_vm *vm); +bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr); + #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h b/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h new file mode 100644 index 000000000000..e43a57d99b56 --- /dev/null +++ b/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UTIL_ARCH_H +#define SELFTEST_KVM_UTIL_ARCH_H + +struct kvm_vm_arch {}; + +#endif // SELFTEST_KVM_UTIL_ARCH_H diff --git a/tools/testing/selftests/kvm/include/s390x/kvm_util_arch.h b/tools/testing/selftests/kvm/include/s390x/kvm_util_arch.h new file mode 100644 index 000000000000..e43a57d99b56 --- /dev/null +++ b/tools/testing/selftests/kvm/include/s390x/kvm_util_arch.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UTIL_ARCH_H +#define SELFTEST_KVM_UTIL_ARCH_H + +struct kvm_vm_arch {}; + +#endif // SELFTEST_KVM_UTIL_ARCH_H diff --git a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h new file mode 100644 index 000000000000..cfdf8c5e2671 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UTIL_ARCH_H +#define SELFTEST_KVM_UTIL_ARCH_H + +#include +#include + +struct kvm_vm_arch { + uint64_t c_bit; + uint64_t s_bit; +}; + +static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch) +{ + return arch->c_bit || arch->s_bit; +} + +#define vm_arch_has_protected_memory(vm) \ + __vm_arch_has_protected_memory(&(vm)->arch) + +#endif // SELFTEST_KVM_UTIL_ARCH_H diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index a4ef5185bb03..5d562f9698e7 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1546,6 +1546,8 @@ void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) { struct userspace_mem_region *region; + gpa = vm_untag_gpa(vm, gpa); + region = userspace_mem_region_find(vm, gpa, gpa); if (!region) { TEST_FAIL("No vm physical memory at 0x%lx", gpa); @@ -2254,3 +2256,18 @@ void __attribute((constructor)) kvm_selftest_init(void) kvm_selftest_arch_init(); } + +bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr) +{ + sparsebit_idx_t pg = 0; + struct userspace_mem_region *region; + + if (!vm_arch_has_protected_memory(vm)) + return false; + + region = userspace_mem_region_find(vm, paddr, paddr); + TEST_ASSERT(region, "No vm physical memory at 0x%lx", paddr); + + pg = paddr >> vm->page_shift; + return sparsebit_is_set(region->protected_phy_pages, pg); +} diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index b9b6cb730a08..534f36a8a5e8 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -157,6 +157,8 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm, { uint64_t *pte = virt_get_pte(vm, parent_pte, vaddr, current_level); + paddr = vm_untag_gpa(vm, paddr); + if (!(*pte & PTE_PRESENT_MASK)) { *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK; if (current_level == target_level) @@ -200,6 +202,8 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) "Physical address beyond maximum supported,\n" " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", paddr, vm->max_gfn, vm->page_size); + TEST_ASSERT(vm_untag_gpa(vm, paddr) == paddr, + "Unexpected bits in paddr: %lx", paddr); /* * Allocate upper level page tables, if not already present. Return @@ -222,6 +226,15 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) TEST_ASSERT(!(*pte & PTE_PRESENT_MASK), "PTE already present for 4k page at vaddr: 0x%lx\n", vaddr); *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK); + + /* + * Neither SEV nor TDX supports shared page tables, so only the final + * leaf PTE needs manually set the C/S-bit. + */ + if (vm_is_gpa_protected(vm, paddr)) + *pte |= vm->arch.c_bit; + else + *pte |= vm->arch.s_bit; } void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) @@ -496,7 +509,7 @@ vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) * No need for a hugepage mask on the PTE, x86-64 requires the "unused" * address bits to be zero. */ - return PTE_GET_PA(*pte) | (gva & ~HUGEPAGE_MASK(level)); + return vm_untag_gpa(vm, PTE_GET_PA(*pte)) | (gva & ~HUGEPAGE_MASK(level)); } static void kvm_setup_gdt(struct kvm_vm *vm, struct kvm_dtable *dt) From ae20eef5323cce441e8d6c64c8d10493bf3ee232 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Thu, 22 Feb 2024 16:42:55 -0800 Subject: [PATCH 584/814] KVM: selftests: Add library for creating and interacting with SEV guests Add a library/APIs for creating and interfacing with SEV guests, all of which need some amount of common functionality, e.g. an open file handle for the SEV driver (/dev/sev), ioctl() wrappers to pass said file handle to KVM, tracking of the C-bit, etc. Add an x86-specific hook to initialize address properties, a.k.a. the location of the C-bit. An arch specific hook is rather gross, but x86 already has a dedicated #ifdef-protected kvm_get_cpu_address_width() hook, i.e. the ugliest code already exists. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Originally-by: Michael Roth Signed-off-by: Peter Gonda Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/20240223004258.3104051-9-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../kvm/include/x86_64/kvm_util_arch.h | 2 + .../selftests/kvm/include/x86_64/processor.h | 8 ++ .../selftests/kvm/include/x86_64/sev.h | 105 +++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 1 + .../selftests/kvm/lib/x86_64/processor.c | 17 +++ tools/testing/selftests/kvm/lib/x86_64/sev.c | 110 ++++++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/x86_64/sev.h create mode 100644 tools/testing/selftests/kvm/lib/x86_64/sev.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 492e937fab00..4ec6f3bcb7de 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -37,6 +37,7 @@ LIBKVM_x86_64 += lib/x86_64/handlers.S LIBKVM_x86_64 += lib/x86_64/hyperv.c LIBKVM_x86_64 += lib/x86_64/memstress.c LIBKVM_x86_64 += lib/x86_64/processor.c +LIBKVM_x86_64 += lib/x86_64/sev.c LIBKVM_x86_64 += lib/x86_64/svm.c LIBKVM_x86_64 += lib/x86_64/ucall.c LIBKVM_x86_64 += lib/x86_64/vmx.c diff --git a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h index cfdf8c5e2671..9f1725192aa2 100644 --- a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h +++ b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h @@ -8,6 +8,8 @@ struct kvm_vm_arch { uint64_t c_bit; uint64_t s_bit; + int sev_fd; + bool is_pt_protected; }; static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a84863503fcb..20c9e3b33b07 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -23,6 +23,12 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; +enum vm_guest_x86_subtype { + VM_SUBTYPE_NONE = 0, + VM_SUBTYPE_SEV, + VM_SUBTYPE_SEV_ES, +}; + #define NMI_VECTOR 0x02 #define X86_EFLAGS_FIXED (1u << 1) @@ -273,6 +279,7 @@ struct kvm_x86_cpu_property { #define X86_PROPERTY_MAX_EXT_LEAF KVM_X86_CPU_PROPERTY(0x80000000, 0, EAX, 0, 31) #define X86_PROPERTY_MAX_PHY_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 0, 7) #define X86_PROPERTY_MAX_VIRT_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 8, 15) +#define X86_PROPERTY_SEV_C_BIT KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 0, 5) #define X86_PROPERTY_PHYS_ADDR_REDUCTION KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 6, 11) #define X86_PROPERTY_MAX_CENTAUR_LEAF KVM_X86_CPU_PROPERTY(0xC0000000, 0, EAX, 0, 31) @@ -1059,6 +1066,7 @@ do { \ } while (0) void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); +void kvm_init_vm_address_properties(struct kvm_vm *vm); bool vm_is_unrestricted_guest(struct kvm_vm *vm); struct ex_regs { diff --git a/tools/testing/selftests/kvm/include/x86_64/sev.h b/tools/testing/selftests/kvm/include/x86_64/sev.h new file mode 100644 index 000000000000..de5283bef752 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/sev.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Helpers used for SEV guests + * + */ +#ifndef SELFTEST_KVM_SEV_H +#define SELFTEST_KVM_SEV_H + +#include +#include + +#include "linux/psp-sev.h" + +#include "kvm_util.h" +#include "svm_util.h" +#include "processor.h" + +enum sev_guest_state { + SEV_GUEST_STATE_UNINITIALIZED = 0, + SEV_GUEST_STATE_LAUNCH_UPDATE, + SEV_GUEST_STATE_LAUNCH_SECRET, + SEV_GUEST_STATE_RUNNING, +}; + +#define SEV_POLICY_NO_DBG (1UL << 0) +#define SEV_POLICY_ES (1UL << 2) + +void sev_vm_launch(struct kvm_vm *vm, uint32_t policy); +void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement); +void sev_vm_launch_finish(struct kvm_vm *vm); + +struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_code, + struct kvm_vcpu **cpu); + +kvm_static_assert(SEV_RET_SUCCESS == 0); + +/* + * The KVM_MEMORY_ENCRYPT_OP uAPI is utter garbage and takes an "unsigned long" + * instead of a proper struct. The size of the parameter is embedded in the + * ioctl number, i.e. is ABI and thus immutable. Hack around the mess by + * creating an overlay to pass in an "unsigned long" without a cast (casting + * will make the compiler unhappy due to dereferencing an aliased pointer). + */ +#define __vm_sev_ioctl(vm, cmd, arg) \ +({ \ + int r; \ + \ + union { \ + struct kvm_sev_cmd c; \ + unsigned long raw; \ + } sev_cmd = { .c = { \ + .id = (cmd), \ + .data = (uint64_t)(arg), \ + .sev_fd = (vm)->arch.sev_fd, \ + } }; \ + \ + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &sev_cmd.raw); \ + r ?: sev_cmd.c.error; \ +}) + +#define vm_sev_ioctl(vm, cmd, arg) \ +({ \ + int ret = __vm_sev_ioctl(vm, cmd, arg); \ + \ + __TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, vm); \ +}) + +static inline void sev_vm_init(struct kvm_vm *vm) +{ + vm->arch.sev_fd = open_sev_dev_path_or_exit(); + + vm_sev_ioctl(vm, KVM_SEV_INIT, NULL); +} + + +static inline void sev_es_vm_init(struct kvm_vm *vm) +{ + vm->arch.sev_fd = open_sev_dev_path_or_exit(); + + vm_sev_ioctl(vm, KVM_SEV_ES_INIT, NULL); +} + +static inline void sev_register_encrypted_memory(struct kvm_vm *vm, + struct userspace_mem_region *region) +{ + struct kvm_enc_region range = { + .addr = region->region.userspace_addr, + .size = region->region.memory_size, + }; + + vm_ioctl(vm, KVM_MEMORY_ENCRYPT_REG_REGION, &range); +} + +static inline void sev_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa, + uint64_t size) +{ + struct kvm_sev_launch_update_data update_data = { + .uaddr = (unsigned long)addr_gpa2hva(vm, gpa), + .len = size, + }; + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_DATA, &update_data); +} + +#endif /* SELFTEST_KVM_SEV_H */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 5d562f9698e7..adc51b0712ca 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -266,6 +266,7 @@ struct kvm_vm *____vm_create(struct vm_shape shape) case VM_MODE_PXXV48_4K: #ifdef __x86_64__ kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits); + kvm_init_vm_address_properties(vm); /* * Ignore KVM support for 5-level paging (vm->va_bits == 57), * it doesn't take effect unless a CR4.LA57 is set, which it diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 534f36a8a5e8..f1139ba35112 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -9,6 +9,7 @@ #include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "sev.h" #ifndef NUM_INTERRUPTS #define NUM_INTERRUPTS 256 @@ -278,6 +279,9 @@ uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr, { uint64_t *pml4e, *pdpe, *pde; + TEST_ASSERT(!vm->arch.is_pt_protected, + "Walking page tables of protected guests is impossible"); + TEST_ASSERT(*level >= PG_LEVEL_NONE && *level < PG_LEVEL_NUM, "Invalid PG_LEVEL_* '%d'", *level); @@ -573,6 +577,11 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) vm_create_irqchip(vm); sync_global_to_guest(vm, host_cpu_is_intel); sync_global_to_guest(vm, host_cpu_is_amd); + + if (vm->subtype == VM_SUBTYPE_SEV) + sev_vm_init(vm); + else if (vm->subtype == VM_SUBTYPE_SEV_ES) + sev_es_vm_init(vm); } void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) @@ -1061,6 +1070,14 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) } } +void kvm_init_vm_address_properties(struct kvm_vm *vm) +{ + if (vm->subtype == VM_SUBTYPE_SEV) { + vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT)); + vm->gpa_tag_mask = vm->arch.c_bit; + } +} + static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr, int dpl, unsigned short selector) { diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev.c b/tools/testing/selftests/kvm/lib/x86_64/sev.c new file mode 100644 index 000000000000..9f5a3dbb5e65 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86_64/sev.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include + +#include "sev.h" + +/* + * sparsebit_next_clear() can return 0 if [x, 2**64-1] are all set, and the + * -1 would then cause an underflow back to 2**64 - 1. This is expected and + * correct. + * + * If the last range in the sparsebit is [x, y] and we try to iterate, + * sparsebit_next_set() will return 0, and sparsebit_next_clear() will try + * and find the first range, but that's correct because the condition + * expression would cause us to quit the loop. + */ +static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region *region) +{ + const struct sparsebit *protected_phy_pages = region->protected_phy_pages; + const vm_paddr_t gpa_base = region->region.guest_phys_addr; + const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift; + sparsebit_idx_t i, j; + + if (!sparsebit_any_set(protected_phy_pages)) + return; + + sev_register_encrypted_memory(vm, region); + + sparsebit_for_each_set_range(protected_phy_pages, i, j) { + const uint64_t size = (j - i + 1) * vm->page_size; + const uint64_t offset = (i - lowest_page_in_region) * vm->page_size; + + sev_launch_update_data(vm, gpa_base + offset, size); + } +} + +void sev_vm_launch(struct kvm_vm *vm, uint32_t policy) +{ + struct kvm_sev_launch_start launch_start = { + .policy = policy, + }; + struct userspace_mem_region *region; + struct kvm_sev_guest_status status; + int ctr; + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_START, &launch_start); + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + + TEST_ASSERT_EQ(status.policy, policy); + TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_LAUNCH_UPDATE); + + hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) + encrypt_region(vm, region); + + vm->arch.is_pt_protected = true; +} + +void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement) +{ + struct kvm_sev_launch_measure launch_measure; + struct kvm_sev_guest_status guest_status; + + launch_measure.len = 256; + launch_measure.uaddr = (__u64)measurement; + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_MEASURE, &launch_measure); + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &guest_status); + TEST_ASSERT_EQ(guest_status.state, SEV_GUEST_STATE_LAUNCH_SECRET); +} + +void sev_vm_launch_finish(struct kvm_vm *vm) +{ + struct kvm_sev_guest_status status; + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + TEST_ASSERT(status.state == SEV_GUEST_STATE_LAUNCH_UPDATE || + status.state == SEV_GUEST_STATE_LAUNCH_SECRET, + "Unexpected guest state: %d", status.state); + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_FINISH, NULL); + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_RUNNING); +} + +struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_code, + struct kvm_vcpu **cpu) +{ + struct vm_shape shape = { + .type = VM_TYPE_DEFAULT, + .mode = VM_MODE_DEFAULT, + .subtype = VM_SUBTYPE_SEV, + }; + struct kvm_vm *vm; + struct kvm_vcpu *cpus[1]; + uint8_t measurement[512]; + + vm = __vm_create_with_vcpus(shape, 1, 0, guest_code, cpus); + *cpu = cpus[0]; + + sev_vm_launch(vm, policy); + + /* TODO: Validate the measurement is as expected. */ + sev_vm_launch_measure(vm, measurement); + + sev_vm_launch_finish(vm); + + return vm; +} From 69f8e15ab61f2f011612dad5f0522ea4d56971d9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 22 Feb 2024 16:42:56 -0800 Subject: [PATCH 585/814] KVM: selftests: Use the SEV library APIs in the intra-host migration test Port the existing intra-host SEV(-ES) migration test to the recently added SEV library, which handles much of the boilerplate needed to create and configure SEV guests. Tested-by: Carlos Bilbao Link: https://lore.kernel.org/r/20240223004258.3104051-10-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/sev_migrate_tests.c | 60 ++++++------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index c7ef97561038..ec3709e1c684 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -10,11 +10,9 @@ #include "test_util.h" #include "kvm_util.h" #include "processor.h" -#include "svm_util.h" +#include "sev.h" #include "kselftest.h" -#define SEV_POLICY_ES 0b100 - #define NR_MIGRATE_TEST_VCPUS 4 #define NR_MIGRATE_TEST_VMS 3 #define NR_LOCK_TESTING_THREADS 3 @@ -22,46 +20,24 @@ bool have_sev_es; -static int __sev_ioctl(int vm_fd, int cmd_id, void *data, __u32 *fw_error) -{ - struct kvm_sev_cmd cmd = { - .id = cmd_id, - .data = (uint64_t)data, - .sev_fd = open_sev_dev_path_or_exit(), - }; - int ret; - - ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd); - *fw_error = cmd.error; - return ret; -} - -static void sev_ioctl(int vm_fd, int cmd_id, void *data) -{ - int ret; - __u32 fw_error; - - ret = __sev_ioctl(vm_fd, cmd_id, data, &fw_error); - TEST_ASSERT(ret == 0 && fw_error == SEV_RET_SUCCESS, - "%d failed: return code: %d, errno: %d, fw error: %d", - cmd_id, ret, errno, fw_error); -} - static struct kvm_vm *sev_vm_create(bool es) { struct kvm_vm *vm; - struct kvm_sev_launch_start start = { 0 }; int i; vm = vm_create_barebones(); - sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL); + if (!es) + sev_vm_init(vm); + else + sev_es_vm_init(vm); + for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) __vm_vcpu_add(vm, i); + + sev_vm_launch(vm, es ? SEV_POLICY_ES : 0); + if (es) - start.policy |= SEV_POLICY_ES; - sev_ioctl(vm->fd, KVM_SEV_LAUNCH_START, &start); - if (es) - sev_ioctl(vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); return vm; } @@ -181,7 +157,7 @@ static void test_sev_migrate_parameters(void) sev_vm = sev_vm_create(/* es= */ false); sev_es_vm = sev_vm_create(/* es= */ true); sev_es_vm_no_vmsa = vm_create_barebones(); - sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); + sev_es_vm_init(sev_es_vm_no_vmsa); __vm_vcpu_add(sev_es_vm_no_vmsa, 1); ret = __sev_migrate_from(sev_vm, sev_es_vm); @@ -230,13 +206,13 @@ static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src) TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno); } -static void verify_mirror_allowed_cmds(int vm_fd) +static void verify_mirror_allowed_cmds(struct kvm_vm *vm) { struct kvm_sev_guest_status status; + int cmd_id; - for (int cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) { + for (cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) { int ret; - __u32 fw_error; /* * These commands are allowed for mirror VMs, all others are @@ -256,14 +232,14 @@ static void verify_mirror_allowed_cmds(int vm_fd) * These commands should be disallowed before the data * parameter is examined so NULL is OK here. */ - ret = __sev_ioctl(vm_fd, cmd_id, NULL, &fw_error); + ret = __vm_sev_ioctl(vm, cmd_id, NULL); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able call command: %d. ret: %d, errno: %d\n", cmd_id, ret, errno); } - sev_ioctl(vm_fd, KVM_SEV_GUEST_STATUS, &status); + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); } static void test_sev_mirror(bool es) @@ -281,9 +257,9 @@ static void test_sev_mirror(bool es) __vm_vcpu_add(dst_vm, i); if (es) - sev_ioctl(dst_vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); + vm_sev_ioctl(dst_vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); - verify_mirror_allowed_cmds(dst_vm->fd); + verify_mirror_allowed_cmds(dst_vm); kvm_vm_free(src_vm); kvm_vm_free(dst_vm); From be250ff437fa260550113a361ff0b31ccd34e9e5 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Thu, 22 Feb 2024 16:42:57 -0800 Subject: [PATCH 586/814] KVM: selftests: Add a basic SEV smoke test Add a basic smoke test for SEV guests to verify that KVM can launch an SEV guest and run a few instructions without exploding. To verify that SEV is indeed enabled, assert that SEV is reported as enabled in MSR_AMD64_SEV, a.k.a. SEV_STATUS, which cannot be intercepted by KVM (architecturally enforced). Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Suggested-by: Michael Roth Tested-by: Carlos Bilbao Signed-off-by: Peter Gonda [sean: rename to "sev_smoke_test"] Link: https://lore.kernel.org/r/20240223004258.3104051-11-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/sev_smoke_test.c | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/sev_smoke_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 4ec6f3bcb7de..c75251d5c97c 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -118,6 +118,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_pmu_caps_test TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests +TEST_GEN_PROGS_x86_64 += x86_64/sev_smoke_test TEST_GEN_PROGS_x86_64 += x86_64/amx_test TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test diff --git a/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c new file mode 100644 index 000000000000..54d72efd9b4d --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "svm_util.h" +#include "linux/psp-sev.h" +#include "sev.h" + +static void guest_sev_code(void) +{ + GUEST_ASSERT(this_cpu_has(X86_FEATURE_SEV)); + GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED); + + GUEST_DONE(); +} + +static void test_sev(void *guest_code, uint64_t policy) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + + vm = vm_sev_create_with_one_vcpu(policy, guest_code, &vcpu); + + for (;;) { + vcpu_run(vcpu); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + continue; + case UCALL_DONE: + return; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + default: + TEST_FAIL("Unexpected exit: %s", + exit_reason_str(vcpu->run->exit_reason)); + } + } + + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV)); + + test_sev(guest_sev_code, SEV_POLICY_NO_DBG); + test_sev(guest_sev_code, 0); + + return 0; +} From 40e09b3ccfacc640d58e1e3d6b8f29b2db0a9848 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 22 Feb 2024 16:42:58 -0800 Subject: [PATCH 587/814] KVM: selftests: Add a basic SEV-ES smoke test Extend sev_smoke_test to also run a minimal SEV-ES smoke test so that it's possible to test KVM's unique VMRUN=>#VMEXIT path for SEV-ES guests without needing a full blown SEV-ES capable VM, which requires a rather absurd amount of properly configured collateral. Punt on proper GHCB and ucall support, and instead use the GHCB MSR protocol to signal test completion. The most important thing at this point is to have _any_ kind of testing of KVM's __svm_sev_es_vcpu_run(). Cc: Tom Lendacky Cc: Michael Roth Cc: Peter Gonda Cc: Carlos Bilbao Tested-by: Carlos Bilbao Link: https://lore.kernel.org/r/20240223004258.3104051-12-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/sev.h | 2 ++ .../selftests/kvm/lib/x86_64/processor.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/sev.c | 6 +++- .../selftests/kvm/x86_64/sev_smoke_test.c | 30 +++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/sev.h b/tools/testing/selftests/kvm/include/x86_64/sev.h index de5283bef752..8a1bf88474c9 100644 --- a/tools/testing/selftests/kvm/include/x86_64/sev.h +++ b/tools/testing/selftests/kvm/include/x86_64/sev.h @@ -25,6 +25,8 @@ enum sev_guest_state { #define SEV_POLICY_NO_DBG (1UL << 0) #define SEV_POLICY_ES (1UL << 2) +#define GHCB_MSR_TERM_REQ 0x100 + void sev_vm_launch(struct kvm_vm *vm, uint32_t policy); void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement); void sev_vm_launch_finish(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index f1139ba35112..49288fe10cd3 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1072,7 +1072,7 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) void kvm_init_vm_address_properties(struct kvm_vm *vm) { - if (vm->subtype == VM_SUBTYPE_SEV) { + if (vm->subtype == VM_SUBTYPE_SEV || vm->subtype == VM_SUBTYPE_SEV_ES) { vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT)); vm->gpa_tag_mask = vm->arch.c_bit; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev.c b/tools/testing/selftests/kvm/lib/x86_64/sev.c index 9f5a3dbb5e65..e248d3364b9c 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/sev.c +++ b/tools/testing/selftests/kvm/lib/x86_64/sev.c @@ -53,6 +53,9 @@ void sev_vm_launch(struct kvm_vm *vm, uint32_t policy) hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) encrypt_region(vm, region); + if (policy & SEV_POLICY_ES) + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); + vm->arch.is_pt_protected = true; } @@ -90,7 +93,8 @@ struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_code, struct vm_shape shape = { .type = VM_TYPE_DEFAULT, .mode = VM_MODE_DEFAULT, - .subtype = VM_SUBTYPE_SEV, + .subtype = policy & SEV_POLICY_ES ? VM_SUBTYPE_SEV_ES : + VM_SUBTYPE_SEV, }; struct kvm_vm *vm; struct kvm_vcpu *cpus[1]; diff --git a/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c index 54d72efd9b4d..026779f3ed06 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c +++ b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c @@ -12,6 +12,21 @@ #include "linux/psp-sev.h" #include "sev.h" + +static void guest_sev_es_code(void) +{ + /* TODO: Check CPUID after GHCB-based hypercall support is added. */ + GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED); + GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ES_ENABLED); + + /* + * TODO: Add GHCB and ucall support for SEV-ES guests. For now, simply + * force "termination" to signal "done" via the GHCB MSR protocol. + */ + wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ); + __asm__ __volatile__("rep; vmmcall"); +} + static void guest_sev_code(void) { GUEST_ASSERT(this_cpu_has(X86_FEATURE_SEV)); @@ -31,6 +46,16 @@ static void test_sev(void *guest_code, uint64_t policy) for (;;) { vcpu_run(vcpu); + if (policy & SEV_POLICY_ES) { + TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT, + "Wanted SYSTEM_EVENT, got %s", + exit_reason_str(vcpu->run->exit_reason)); + TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM); + TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1); + TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ); + break; + } + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: continue; @@ -54,5 +79,10 @@ int main(int argc, char *argv[]) test_sev(guest_sev_code, SEV_POLICY_NO_DBG); test_sev(guest_sev_code, 0); + if (kvm_cpu_has(X86_FEATURE_SEV_ES)) { + test_sev(guest_sev_es_code, SEV_POLICY_ES | SEV_POLICY_NO_DBG); + test_sev(guest_sev_es_code, SEV_POLICY_ES); + } + return 0; } From 43b3bedb7cc4348f2885a30e960b63b94d1be381 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 22 Nov 2023 22:15:26 +0000 Subject: [PATCH 588/814] KVM: selftests: aarch64: Remove unused functions from vpmu test vpmu_counter_access's disable_counter() carries a bug that disables all the counters that are enabled, instead of just the requested one. Fortunately, it's not an issue as there are no callers of it. Hence, instead of fixing it, remove the definition entirely. Remove enable_counter() as it's unused as well. Signed-off-by: Raghavendra Rao Ananta Reviewed-by: Zenghui Yu Link: https://lore.kernel.org/r/20231122221526.2750966-1-rananta@google.com Signed-off-by: Oliver Upton --- .../selftests/kvm/aarch64/vpmu_counter_access.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c index f8f0c655c723..1b51cd11ee93 100644 --- a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c @@ -93,22 +93,6 @@ static inline void write_sel_evtyper(int sel, unsigned long val) isb(); } -static inline void enable_counter(int idx) -{ - uint64_t v = read_sysreg(pmcntenset_el0); - - write_sysreg(BIT(idx) | v, pmcntenset_el0); - isb(); -} - -static inline void disable_counter(int idx) -{ - uint64_t v = read_sysreg(pmcntenset_el0); - - write_sysreg(BIT(idx) | v, pmcntenclr_el0); - isb(); -} - static void pmu_disable_reset(void) { uint64_t pmcr = read_sysreg(pmcr_el0); From f66a211e8c5d9b1b0531364c1b16874b0499e0d2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 21 Feb 2024 13:19:15 +0800 Subject: [PATCH 589/814] crypto: dh - Make public key test FIPS-only The function dh_is_pubkey_valid was added to for FIPS but it was only partially conditional to fips_enabled. In particular, the first test in the function relies on the last test to work properly, but the last test is only run in FIPS mode. Fix this inconsistency by making the whole function conditional on fips_enabled. Signed-off-by: Herbert Xu --- crypto/dh.c | 63 +++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/crypto/dh.c b/crypto/dh.c index 0fcad279e6fe..68d11d66c0b5 100644 --- a/crypto/dh.c +++ b/crypto/dh.c @@ -106,6 +106,12 @@ err_clear_ctx: */ static int dh_is_pubkey_valid(struct dh_ctx *ctx, MPI y) { + MPI val, q; + int ret; + + if (!fips_enabled) + return 0; + if (unlikely(!ctx->p)) return -EINVAL; @@ -125,41 +131,36 @@ static int dh_is_pubkey_valid(struct dh_ctx *ctx, MPI y) * * For the safe-prime groups q = (p - 1)/2. */ - if (fips_enabled) { - MPI val, q; - int ret; - - val = mpi_alloc(0); - if (!val) - return -ENOMEM; - - q = mpi_alloc(mpi_get_nlimbs(ctx->p)); - if (!q) { - mpi_free(val); - return -ENOMEM; - } - - /* - * ->p is odd, so no need to explicitly subtract one - * from it before shifting to the right. - */ - mpi_rshift(q, ctx->p, 1); - - ret = mpi_powm(val, y, q, ctx->p); - mpi_free(q); - if (ret) { - mpi_free(val); - return ret; - } - - ret = mpi_cmp_ui(val, 1); + val = mpi_alloc(0); + if (!val) + return -ENOMEM; + q = mpi_alloc(mpi_get_nlimbs(ctx->p)); + if (!q) { mpi_free(val); - - if (ret != 0) - return -EINVAL; + return -ENOMEM; } + /* + * ->p is odd, so no need to explicitly subtract one + * from it before shifting to the right. + */ + mpi_rshift(q, ctx->p, 1); + + ret = mpi_powm(val, y, q, ctx->p); + mpi_free(q); + if (ret) { + mpi_free(val); + return ret; + } + + ret = mpi_cmp_ui(val, 1); + + mpi_free(val); + + if (ret != 0) + return -EINVAL; + return 0; } From 2beb81fbf0c01a62515a1bcef326168494ee2bd0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 23 Feb 2024 01:03:34 -0800 Subject: [PATCH 590/814] crypto: remove CONFIG_CRYPTO_STATS Remove support for the "Crypto usage statistics" feature (CONFIG_CRYPTO_STATS). This feature does not appear to have ever been used, and it is harmful because it significantly reduces performance and is a large maintenance burden. Covering each of these points in detail: 1. Feature is not being used Since these generic crypto statistics are only readable using netlink, it's fairly straightforward to look for programs that use them. I'm unable to find any evidence that any such programs exist. For example, Debian Code Search returns no hits except the kernel header and kernel code itself and translations of the kernel header: https://codesearch.debian.net/search?q=CRYPTOCFGA_STAT&literal=1&perpkg=1 The patch series that added this feature in 2018 (https://lore.kernel.org/linux-crypto/1537351855-16618-1-git-send-email-clabbe@baylibre.com/) said "The goal is to have an ifconfig for crypto device." This doesn't appear to have happened. It's not clear that there is real demand for crypto statistics. Just because the kernel provides other types of statistics such as I/O and networking statistics and some people find those useful does not mean that crypto statistics are useful too. Further evidence that programs are not using CONFIG_CRYPTO_STATS is that it was able to be disabled in RHEL and Fedora as a bug fix (https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/2947). Even further evidence comes from the fact that there are and have been bugs in how the stats work, but they were never reported. For example, before Linux v6.7 hash stats were double-counted in most cases. There has also never been any documentation for this feature, so it might be hard to use even if someone wanted to. 2. CONFIG_CRYPTO_STATS significantly reduces performance Enabling CONFIG_CRYPTO_STATS significantly reduces the performance of the crypto API, even if no program ever retrieves the statistics. This primarily affects systems with large number of CPUs. For example, https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2039576 reported that Lustre client encryption performance improved from 21.7GB/s to 48.2GB/s by disabling CONFIG_CRYPTO_STATS. It can be argued that this means that CONFIG_CRYPTO_STATS should be optimized with per-cpu counters similar to many of the networking counters. But no one has done this in 5+ years. This is consistent with the fact that the feature appears to be unused, so there seems to be little interest in improving it as opposed to just disabling it. It can be argued that because CONFIG_CRYPTO_STATS is off by default, performance doesn't matter. But Linux distros tend to error on the side of enabling options. The option is enabled in Ubuntu and Arch Linux, and until recently was enabled in RHEL and Fedora (see above). So, even just having the option available is harmful to users. 3. CONFIG_CRYPTO_STATS is a large maintenance burden There are over 1000 lines of code associated with CONFIG_CRYPTO_STATS, spread among 32 files. It significantly complicates much of the implementation of the crypto API. After the initial submission, many fixes and refactorings have consumed effort of multiple people to keep this feature "working". We should be spending this effort elsewhere. Cc: Corentin Labbe Signed-off-by: Eric Biggers Acked-by: Ard Biesheuvel Acked-by: Corentin Labbe Signed-off-by: Herbert Xu --- arch/s390/configs/debug_defconfig | 1 - arch/s390/configs/defconfig | 1 - crypto/Kconfig | 20 --- crypto/Makefile | 2 - crypto/acompress.c | 47 +---- crypto/aead.c | 84 +-------- crypto/ahash.c | 63 +------ crypto/akcipher.c | 31 ---- crypto/compress.h | 5 - crypto/{crypto_user_base.c => crypto_user.c} | 10 +- crypto/crypto_user_stat.c | 176 ------------------- crypto/hash.h | 30 ---- crypto/kpp.c | 30 ---- crypto/lskcipher.c | 73 +------- crypto/rng.c | 44 +---- crypto/scompress.c | 8 +- crypto/shash.c | 75 +------- crypto/sig.c | 13 -- crypto/skcipher.c | 86 +-------- crypto/skcipher.h | 10 -- include/crypto/acompress.h | 90 +--------- include/crypto/aead.h | 21 --- include/crypto/akcipher.h | 78 +------- include/crypto/algapi.h | 3 - include/crypto/hash.h | 22 --- include/crypto/internal/acompress.h | 7 +- include/crypto/internal/cryptouser.h | 16 -- include/crypto/internal/scompress.h | 8 +- include/crypto/kpp.h | 58 +----- include/crypto/rng.h | 51 +----- include/crypto/skcipher.h | 25 --- include/uapi/linux/cryptouser.h | 28 +-- 32 files changed, 77 insertions(+), 1139 deletions(-) rename crypto/{crypto_user_base.c => crypto_user.c} (98%) delete mode 100644 crypto/crypto_user_stat.c delete mode 100644 include/crypto/internal/cryptouser.h diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index cae2dd34fbb4..063f0c11087d 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -766,7 +766,6 @@ CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m -CONFIG_CRYPTO_STATS=y CONFIG_CRYPTO_CRC32_S390=y CONFIG_CRYPTO_SHA512_S390=m CONFIG_CRYPTO_SHA1_S390=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 42b988873e54..ab608ce768b7 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -752,7 +752,6 @@ CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m -CONFIG_CRYPTO_STATS=y CONFIG_CRYPTO_CRC32_S390=y CONFIG_CRYPTO_SHA512_S390=m CONFIG_CRYPTO_SHA1_S390=m diff --git a/crypto/Kconfig b/crypto/Kconfig index 44661c2e30ca..f937142aa94d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1456,26 +1456,6 @@ config CRYPTO_USER_API_ENABLE_OBSOLETE already been phased out from internal use by the kernel, and are only useful for userspace clients that still rely on them. -config CRYPTO_STATS - bool "Crypto usage statistics" - depends on CRYPTO_USER - help - Enable the gathering of crypto stats. - - Enabling this option reduces the performance of the crypto API. It - should only be enabled when there is actually a use case for it. - - This collects data sizes, numbers of requests, and numbers - of errors processed by: - - AEAD ciphers (encrypt, decrypt) - - asymmetric key ciphers (encrypt, decrypt, verify, sign) - - symmetric key ciphers (encrypt, decrypt) - - compression algorithms (compress, decompress) - - hash algorithms (hash) - - key-agreement protocol primitives (setsecret, generate - public key, compute shared secret) - - RNG (generate, seed) - endmenu config CRYPTO_HASH_INFO diff --git a/crypto/Makefile b/crypto/Makefile index 408f0a1f9ab9..de9a3312a2c8 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -69,8 +69,6 @@ cryptomgr-y := algboss.o testmgr.o obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o obj-$(CONFIG_CRYPTO_USER) += crypto_user.o -crypto_user-y := crypto_user_base.o -crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o obj-$(CONFIG_CRYPTO_CMAC) += cmac.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o obj-$(CONFIG_CRYPTO_VMAC) += vmac.o diff --git a/crypto/acompress.c b/crypto/acompress.c index 1c682810a484..484a865b23cd 100644 --- a/crypto/acompress.c +++ b/crypto/acompress.c @@ -25,7 +25,7 @@ static const struct crypto_type crypto_acomp_type; static inline struct acomp_alg *__crypto_acomp_alg(struct crypto_alg *alg) { - return container_of(alg, struct acomp_alg, calg.base); + return container_of(alg, struct acomp_alg, base); } static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm) @@ -93,32 +93,6 @@ static unsigned int crypto_acomp_extsize(struct crypto_alg *alg) return extsize; } -static inline int __crypto_acomp_report_stat(struct sk_buff *skb, - struct crypto_alg *alg) -{ - struct comp_alg_common *calg = __crypto_comp_alg_common(alg); - struct crypto_istat_compress *istat = comp_get_stat(calg); - struct crypto_stat_compress racomp; - - memset(&racomp, 0, sizeof(racomp)); - - strscpy(racomp.type, "acomp", sizeof(racomp.type)); - racomp.stat_compress_cnt = atomic64_read(&istat->compress_cnt); - racomp.stat_compress_tlen = atomic64_read(&istat->compress_tlen); - racomp.stat_decompress_cnt = atomic64_read(&istat->decompress_cnt); - racomp.stat_decompress_tlen = atomic64_read(&istat->decompress_tlen); - racomp.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp); -} - -#ifdef CONFIG_CRYPTO_STATS -int crypto_acomp_report_stat(struct sk_buff *skb, struct crypto_alg *alg) -{ - return __crypto_acomp_report_stat(skb, alg); -} -#endif - static const struct crypto_type crypto_acomp_type = { .extsize = crypto_acomp_extsize, .init_tfm = crypto_acomp_init_tfm, @@ -127,9 +101,6 @@ static const struct crypto_type crypto_acomp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_acomp_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_acomp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_ACOMPRESS_MASK, @@ -182,24 +153,12 @@ void acomp_request_free(struct acomp_req *req) } EXPORT_SYMBOL_GPL(acomp_request_free); -void comp_prepare_alg(struct comp_alg_common *alg) -{ - struct crypto_istat_compress *istat = comp_get_stat(alg); - struct crypto_alg *base = &alg->base; - - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); -} - int crypto_register_acomp(struct acomp_alg *alg) { - struct crypto_alg *base = &alg->calg.base; - - comp_prepare_alg(&alg->calg); + struct crypto_alg *base = &alg->base; base->cra_type = &crypto_acomp_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_ACOMPRESS; return crypto_register_alg(base); diff --git a/crypto/aead.c b/crypto/aead.c index 54906633566a..0e75a69189df 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -20,15 +20,6 @@ #include "internal.h" -static inline struct crypto_istat_aead *aead_get_stat(struct aead_alg *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { @@ -90,62 +81,28 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) } EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); -static inline int crypto_aead_errstat(struct crypto_istat_aead *istat, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&istat->err_cnt); - - return err; -} - int crypto_aead_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct aead_alg *alg = crypto_aead_alg(aead); - struct crypto_istat_aead *istat; - int ret; - - istat = aead_get_stat(alg); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - atomic64_inc(&istat->encrypt_cnt); - atomic64_add(req->cryptlen, &istat->encrypt_tlen); - } if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - ret = -ENOKEY; - else - ret = alg->encrypt(req); + return -ENOKEY; - return crypto_aead_errstat(istat, ret); + return crypto_aead_alg(aead)->encrypt(req); } EXPORT_SYMBOL_GPL(crypto_aead_encrypt); int crypto_aead_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct aead_alg *alg = crypto_aead_alg(aead); - struct crypto_istat_aead *istat; - int ret; - - istat = aead_get_stat(alg); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - atomic64_inc(&istat->encrypt_cnt); - atomic64_add(req->cryptlen, &istat->encrypt_tlen); - } if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - ret = -ENOKEY; - else if (req->cryptlen < crypto_aead_authsize(aead)) - ret = -EINVAL; - else - ret = alg->decrypt(req); + return -ENOKEY; - return crypto_aead_errstat(istat, ret); + if (req->cryptlen < crypto_aead_authsize(aead)) + return -EINVAL; + + return crypto_aead_alg(aead)->decrypt(req); } EXPORT_SYMBOL_GPL(crypto_aead_decrypt); @@ -215,26 +172,6 @@ static void crypto_aead_free_instance(struct crypto_instance *inst) aead->free(aead); } -static int __maybe_unused crypto_aead_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct aead_alg *aead = container_of(alg, struct aead_alg, base); - struct crypto_istat_aead *istat = aead_get_stat(aead); - struct crypto_stat_aead raead; - - memset(&raead, 0, sizeof(raead)); - - strscpy(raead.type, "aead", sizeof(raead.type)); - - raead.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); - raead.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); - raead.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); - raead.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); - raead.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead); -} - static const struct crypto_type crypto_aead_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_aead_init_tfm, @@ -244,9 +181,6 @@ static const struct crypto_type crypto_aead_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_aead_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_aead_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -277,7 +211,6 @@ EXPORT_SYMBOL_GPL(crypto_has_aead); static int aead_prepare_alg(struct aead_alg *alg) { - struct crypto_istat_aead *istat = aead_get_stat(alg); struct crypto_alg *base = &alg->base; if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) > @@ -291,9 +224,6 @@ static int aead_prepare_alg(struct aead_alg *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); - return 0; } diff --git a/crypto/ahash.c b/crypto/ahash.c index 0ac83f7f701d..bcd9de009a91 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -27,22 +27,6 @@ #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e -static inline struct crypto_istat_hash *ahash_get_stat(struct ahash_alg *alg) -{ - return hash_get_stat(&alg->halg); -} - -static inline int crypto_ahash_errstat(struct ahash_alg *alg, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&ahash_get_stat(alg)->err_cnt); - - return err; -} - /* * For an ahash tfm that is using an shash algorithm (instead of an ahash * algorithm), this returns the underlying shash tfm. @@ -344,75 +328,47 @@ static void ahash_restore_req(struct ahash_request *req, int err) int crypto_ahash_update(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ahash_alg *alg; if (likely(tfm->using_shash)) return shash_ahash_update(req, ahash_request_ctx(req)); - alg = crypto_ahash_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_add(req->nbytes, &ahash_get_stat(alg)->hash_tlen); - return crypto_ahash_errstat(alg, alg->update(req)); + return crypto_ahash_alg(tfm)->update(req); } EXPORT_SYMBOL_GPL(crypto_ahash_update); int crypto_ahash_final(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ahash_alg *alg; if (likely(tfm->using_shash)) return crypto_shash_final(ahash_request_ctx(req), req->result); - alg = crypto_ahash_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&ahash_get_stat(alg)->hash_cnt); - return crypto_ahash_errstat(alg, alg->final(req)); + return crypto_ahash_alg(tfm)->final(req); } EXPORT_SYMBOL_GPL(crypto_ahash_final); int crypto_ahash_finup(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ahash_alg *alg; if (likely(tfm->using_shash)) return shash_ahash_finup(req, ahash_request_ctx(req)); - alg = crypto_ahash_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_hash *istat = ahash_get_stat(alg); - - atomic64_inc(&istat->hash_cnt); - atomic64_add(req->nbytes, &istat->hash_tlen); - } - return crypto_ahash_errstat(alg, alg->finup(req)); + return crypto_ahash_alg(tfm)->finup(req); } EXPORT_SYMBOL_GPL(crypto_ahash_finup); int crypto_ahash_digest(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ahash_alg *alg; - int err; if (likely(tfm->using_shash)) return shash_ahash_digest(req, prepare_shash_desc(req, tfm)); - alg = crypto_ahash_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_hash *istat = ahash_get_stat(alg); - - atomic64_inc(&istat->hash_cnt); - atomic64_add(req->nbytes, &istat->hash_tlen); - } - if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - err = -ENOKEY; - else - err = alg->digest(req); + return -ENOKEY; - return crypto_ahash_errstat(alg, err); + return crypto_ahash_alg(tfm)->digest(req); } EXPORT_SYMBOL_GPL(crypto_ahash_digest); @@ -571,12 +527,6 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) __crypto_hash_alg_common(alg)->digestsize); } -static int __maybe_unused crypto_ahash_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - return crypto_hash_report_stat(skb, alg, "ahash"); -} - static const struct crypto_type crypto_ahash_type = { .extsize = crypto_ahash_extsize, .init_tfm = crypto_ahash_init_tfm, @@ -586,9 +536,6 @@ static const struct crypto_type crypto_ahash_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_ahash_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_ahash_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 52813f0b19e4..e0ff5f4dda6d 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -70,30 +70,6 @@ static void crypto_akcipher_free_instance(struct crypto_instance *inst) akcipher->free(akcipher); } -static int __maybe_unused crypto_akcipher_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct akcipher_alg *akcipher = __crypto_akcipher_alg(alg); - struct crypto_istat_akcipher *istat; - struct crypto_stat_akcipher rakcipher; - - istat = akcipher_get_stat(akcipher); - - memset(&rakcipher, 0, sizeof(rakcipher)); - - strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); - rakcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); - rakcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); - rakcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); - rakcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); - rakcipher.stat_sign_cnt = atomic64_read(&istat->sign_cnt); - rakcipher.stat_verify_cnt = atomic64_read(&istat->verify_cnt); - rakcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, - sizeof(rakcipher), &rakcipher); -} - static const struct crypto_type crypto_akcipher_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_akcipher_init_tfm, @@ -103,9 +79,6 @@ static const struct crypto_type crypto_akcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_akcipher_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_akcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, @@ -131,15 +104,11 @@ EXPORT_SYMBOL_GPL(crypto_alloc_akcipher); static void akcipher_prepare_alg(struct akcipher_alg *alg) { - struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); struct crypto_alg *base = &alg->base; base->cra_type = &crypto_akcipher_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AKCIPHER; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); } static int akcipher_default_op(struct akcipher_request *req) diff --git a/crypto/compress.h b/crypto/compress.h index 19f65516d699..23ea43810810 100644 --- a/crypto/compress.h +++ b/crypto/compress.h @@ -12,15 +12,10 @@ #include "internal.h" struct acomp_req; -struct comp_alg_common; struct sk_buff; int crypto_init_scomp_ops_async(struct crypto_tfm *tfm); struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req); void crypto_acomp_scomp_free_ctx(struct acomp_req *req); -int crypto_acomp_report_stat(struct sk_buff *skb, struct crypto_alg *alg); - -void comp_prepare_alg(struct comp_alg_common *alg); - #endif /* _LOCAL_CRYPTO_COMPRESS_H */ diff --git a/crypto/crypto_user_base.c b/crypto/crypto_user.c similarity index 98% rename from crypto/crypto_user_base.c rename to crypto/crypto_user.c index 3fa20f12989f..6c571834e86a 100644 --- a/crypto/crypto_user_base.c +++ b/crypto/crypto_user.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "internal.h" @@ -33,7 +32,7 @@ struct crypto_dump_info { u16 nlmsg_flags; }; -struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) +static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) { struct crypto_alg *q, *alg = NULL; @@ -387,6 +386,13 @@ static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh, return crypto_del_default_rng(); } +static int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + struct nlattr **attrs) +{ + /* No longer supported */ + return -ENOTSUPP; +} + #define MSGSIZE(type) sizeof(struct type) static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = { diff --git a/crypto/crypto_user_stat.c b/crypto/crypto_user_stat.c deleted file mode 100644 index d4f3d39b5137..000000000000 --- a/crypto/crypto_user_stat.c +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Crypto user configuration API. - * - * Copyright (C) 2017-2018 Corentin Labbe - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define null_terminated(x) (strnlen(x, sizeof(x)) < sizeof(x)) - -struct crypto_dump_info { - struct sk_buff *in_skb; - struct sk_buff *out_skb; - u32 nlmsg_seq; - u16 nlmsg_flags; -}; - -static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_stat_cipher rcipher; - - memset(&rcipher, 0, sizeof(rcipher)); - - strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); - - return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); -} - -static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_stat_compress rcomp; - - memset(&rcomp, 0, sizeof(rcomp)); - - strscpy(rcomp.type, "compression", sizeof(rcomp.type)); - - return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp); -} - -static int crypto_reportstat_one(struct crypto_alg *alg, - struct crypto_user_alg *ualg, - struct sk_buff *skb) -{ - memset(ualg, 0, sizeof(*ualg)); - - strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name)); - strscpy(ualg->cru_driver_name, alg->cra_driver_name, - sizeof(ualg->cru_driver_name)); - strscpy(ualg->cru_module_name, module_name(alg->cra_module), - sizeof(ualg->cru_module_name)); - - ualg->cru_type = 0; - ualg->cru_mask = 0; - ualg->cru_flags = alg->cra_flags; - ualg->cru_refcnt = refcount_read(&alg->cra_refcnt); - - if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority)) - goto nla_put_failure; - if (alg->cra_flags & CRYPTO_ALG_LARVAL) { - struct crypto_stat_larval rl; - - memset(&rl, 0, sizeof(rl)); - strscpy(rl.type, "larval", sizeof(rl.type)); - if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl)) - goto nla_put_failure; - goto out; - } - - if (alg->cra_type && alg->cra_type->report_stat) { - if (alg->cra_type->report_stat(skb, alg)) - goto nla_put_failure; - goto out; - } - - switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { - case CRYPTO_ALG_TYPE_CIPHER: - if (crypto_report_cipher(skb, alg)) - goto nla_put_failure; - break; - case CRYPTO_ALG_TYPE_COMPRESS: - if (crypto_report_comp(skb, alg)) - goto nla_put_failure; - break; - default: - pr_err("ERROR: Unhandled alg %d in %s\n", - alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL), - __func__); - } - -out: - return 0; - -nla_put_failure: - return -EMSGSIZE; -} - -static int crypto_reportstat_alg(struct crypto_alg *alg, - struct crypto_dump_info *info) -{ - struct sk_buff *in_skb = info->in_skb; - struct sk_buff *skb = info->out_skb; - struct nlmsghdr *nlh; - struct crypto_user_alg *ualg; - int err = 0; - - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq, - CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags); - if (!nlh) { - err = -EMSGSIZE; - goto out; - } - - ualg = nlmsg_data(nlh); - - err = crypto_reportstat_one(alg, ualg, skb); - if (err) { - nlmsg_cancel(skb, nlh); - goto out; - } - - nlmsg_end(skb, nlh); - -out: - return err; -} - -int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, - struct nlattr **attrs) -{ - struct net *net = sock_net(in_skb->sk); - struct crypto_user_alg *p = nlmsg_data(in_nlh); - struct crypto_alg *alg; - struct sk_buff *skb; - struct crypto_dump_info info; - int err; - - if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) - return -EINVAL; - - alg = crypto_alg_match(p, 0); - if (!alg) - return -ENOENT; - - err = -ENOMEM; - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!skb) - goto drop_alg; - - info.in_skb = in_skb; - info.out_skb = skb; - info.nlmsg_seq = in_nlh->nlmsg_seq; - info.nlmsg_flags = 0; - - err = crypto_reportstat_alg(alg, &info); - -drop_alg: - crypto_mod_put(alg); - - if (err) { - kfree_skb(skb); - return err; - } - - return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid); -} - -MODULE_LICENSE("GPL"); diff --git a/crypto/hash.h b/crypto/hash.h index 93f6ba0df263..cf9aee07f77d 100644 --- a/crypto/hash.h +++ b/crypto/hash.h @@ -8,39 +8,9 @@ #define _LOCAL_CRYPTO_HASH_H #include -#include #include "internal.h" -static inline struct crypto_istat_hash *hash_get_stat( - struct hash_alg_common *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - -static inline int crypto_hash_report_stat(struct sk_buff *skb, - struct crypto_alg *alg, - const char *type) -{ - struct hash_alg_common *halg = __crypto_hash_alg_common(alg); - struct crypto_istat_hash *istat = hash_get_stat(halg); - struct crypto_stat_hash rhash; - - memset(&rhash, 0, sizeof(rhash)); - - strscpy(rhash.type, type, sizeof(rhash.type)); - - rhash.stat_hash_cnt = atomic64_read(&istat->hash_cnt); - rhash.stat_hash_tlen = atomic64_read(&istat->hash_tlen); - rhash.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash); -} - extern const struct crypto_type crypto_shash_type; int hash_prepare_alg(struct hash_alg_common *alg); diff --git a/crypto/kpp.c b/crypto/kpp.c index 33d44e59387f..ecc63a1a948d 100644 --- a/crypto/kpp.c +++ b/crypto/kpp.c @@ -66,29 +66,6 @@ static void crypto_kpp_free_instance(struct crypto_instance *inst) kpp->free(kpp); } -static int __maybe_unused crypto_kpp_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct kpp_alg *kpp = __crypto_kpp_alg(alg); - struct crypto_istat_kpp *istat; - struct crypto_stat_kpp rkpp; - - istat = kpp_get_stat(kpp); - - memset(&rkpp, 0, sizeof(rkpp)); - - strscpy(rkpp.type, "kpp", sizeof(rkpp.type)); - - rkpp.stat_setsecret_cnt = atomic64_read(&istat->setsecret_cnt); - rkpp.stat_generate_public_key_cnt = - atomic64_read(&istat->generate_public_key_cnt); - rkpp.stat_compute_shared_secret_cnt = - atomic64_read(&istat->compute_shared_secret_cnt); - rkpp.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp); -} - static const struct crypto_type crypto_kpp_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_kpp_init_tfm, @@ -98,9 +75,6 @@ static const struct crypto_type crypto_kpp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_kpp_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_kpp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -131,15 +105,11 @@ EXPORT_SYMBOL_GPL(crypto_has_kpp); static void kpp_prepare_alg(struct kpp_alg *alg) { - struct crypto_istat_kpp *istat = kpp_get_stat(alg); struct crypto_alg *base = &alg->base; base->cra_type = &crypto_kpp_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_KPP; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); } int crypto_register_kpp(struct kpp_alg *alg) diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index 0b6dd8aa21f2..0a800292ca4e 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -29,25 +29,6 @@ static inline struct lskcipher_alg *__crypto_lskcipher_alg( return container_of(alg, struct lskcipher_alg, co.base); } -static inline struct crypto_istat_cipher *lskcipher_get_stat( - struct lskcipher_alg *alg) -{ - return skcipher_get_stat_common(&alg->co); -} - -static inline int crypto_lskcipher_errstat(struct lskcipher_alg *alg, int err) -{ - struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); - - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err) - atomic64_inc(&istat->err_cnt); - - return err; -} - static int lskcipher_setkey_unaligned(struct crypto_lskcipher *tfm, const u8 *key, unsigned int keylen) { @@ -147,20 +128,13 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, u32 flags)) { unsigned long alignmask = crypto_lskcipher_alignmask(tfm); - struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); - int ret; if (((unsigned long)src | (unsigned long)dst | (unsigned long)iv) & - alignmask) { - ret = crypto_lskcipher_crypt_unaligned(tfm, src, dst, len, iv, - crypt); - goto out; - } + alignmask) + return crypto_lskcipher_crypt_unaligned(tfm, src, dst, len, iv, + crypt); - ret = crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); - -out: - return crypto_lskcipher_errstat(alg, ret); + return crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); } int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, @@ -168,13 +142,6 @@ int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, { struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); - - atomic64_inc(&istat->encrypt_cnt); - atomic64_add(len, &istat->encrypt_tlen); - } - return crypto_lskcipher_crypt(tfm, src, dst, len, iv, alg->encrypt); } EXPORT_SYMBOL_GPL(crypto_lskcipher_encrypt); @@ -184,13 +151,6 @@ int crypto_lskcipher_decrypt(struct crypto_lskcipher *tfm, const u8 *src, { struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); - - atomic64_inc(&istat->decrypt_cnt); - atomic64_add(len, &istat->decrypt_tlen); - } - return crypto_lskcipher_crypt(tfm, src, dst, len, iv, alg->decrypt); } EXPORT_SYMBOL_GPL(crypto_lskcipher_decrypt); @@ -322,28 +282,6 @@ static int __maybe_unused crypto_lskcipher_report( sizeof(rblkcipher), &rblkcipher); } -static int __maybe_unused crypto_lskcipher_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct lskcipher_alg *skcipher = __crypto_lskcipher_alg(alg); - struct crypto_istat_cipher *istat; - struct crypto_stat_cipher rcipher; - - istat = lskcipher_get_stat(skcipher); - - memset(&rcipher, 0, sizeof(rcipher)); - - strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); - - rcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); - rcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); - rcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); - rcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); - rcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); -} - static const struct crypto_type crypto_lskcipher_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_lskcipher_init_tfm, @@ -353,9 +291,6 @@ static const struct crypto_type crypto_lskcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_lskcipher_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_lskcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, diff --git a/crypto/rng.c b/crypto/rng.c index 279dffdebf59..9d8804e46422 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -30,30 +30,24 @@ static int crypto_default_rng_refcnt; int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) { - struct rng_alg *alg = crypto_rng_alg(tfm); u8 *buf = NULL; int err; - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&rng_get_stat(alg)->seed_cnt); - if (!seed && slen) { buf = kmalloc(slen, GFP_KERNEL); - err = -ENOMEM; if (!buf) - goto out; + return -ENOMEM; err = get_random_bytes_wait(buf, slen); if (err) - goto free_buf; + goto out; seed = buf; } - err = alg->seed(tfm, seed, slen); -free_buf: - kfree_sensitive(buf); + err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); out: - return crypto_rng_errstat(alg, err); + kfree_sensitive(buf); + return err; } EXPORT_SYMBOL_GPL(crypto_rng_reset); @@ -91,27 +85,6 @@ static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "seedsize : %u\n", seedsize(alg)); } -static int __maybe_unused crypto_rng_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct rng_alg *rng = __crypto_rng_alg(alg); - struct crypto_istat_rng *istat; - struct crypto_stat_rng rrng; - - istat = rng_get_stat(rng); - - memset(&rrng, 0, sizeof(rrng)); - - strscpy(rrng.type, "rng", sizeof(rrng.type)); - - rrng.stat_generate_cnt = atomic64_read(&istat->generate_cnt); - rrng.stat_generate_tlen = atomic64_read(&istat->generate_tlen); - rrng.stat_seed_cnt = atomic64_read(&istat->seed_cnt); - rrng.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng); -} - static const struct crypto_type crypto_rng_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_rng_init_tfm, @@ -120,9 +93,6 @@ static const struct crypto_type crypto_rng_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_rng_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_rng_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -199,7 +169,6 @@ EXPORT_SYMBOL_GPL(crypto_del_default_rng); int crypto_register_rng(struct rng_alg *alg) { - struct crypto_istat_rng *istat = rng_get_stat(alg); struct crypto_alg *base = &alg->base; if (alg->seedsize > PAGE_SIZE / 8) @@ -209,9 +178,6 @@ int crypto_register_rng(struct rng_alg *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_RNG; - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); - return crypto_register_alg(base); } EXPORT_SYMBOL_GPL(crypto_register_rng); diff --git a/crypto/scompress.c b/crypto/scompress.c index b108a30a7600..9cda4ef84a9b 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -248,9 +248,6 @@ static const struct crypto_type crypto_scomp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_scomp_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_acomp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -260,11 +257,10 @@ static const struct crypto_type crypto_scomp_type = { int crypto_register_scomp(struct scomp_alg *alg) { - struct crypto_alg *base = &alg->calg.base; - - comp_prepare_alg(&alg->calg); + struct crypto_alg *base = &alg->base; base->cra_type = &crypto_scomp_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_SCOMPRESS; return crypto_register_alg(base); diff --git a/crypto/shash.c b/crypto/shash.c index c3f7f6a25280..0ffe671b519e 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -16,18 +16,6 @@ #include "hash.h" -static inline struct crypto_istat_hash *shash_get_stat(struct shash_alg *alg) -{ - return hash_get_stat(&alg->halg); -} - -static inline int crypto_shash_errstat(struct shash_alg *alg, int err) -{ - if (IS_ENABLED(CONFIG_CRYPTO_STATS) && err) - atomic64_inc(&shash_get_stat(alg)->err_cnt); - return err; -} - int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { @@ -61,29 +49,13 @@ EXPORT_SYMBOL_GPL(crypto_shash_setkey); int crypto_shash_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct shash_alg *shash = crypto_shash_alg(desc->tfm); - int err; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_add(len, &shash_get_stat(shash)->hash_tlen); - - err = shash->update(desc, data, len); - - return crypto_shash_errstat(shash, err); + return crypto_shash_alg(desc->tfm)->update(desc, data, len); } EXPORT_SYMBOL_GPL(crypto_shash_update); int crypto_shash_final(struct shash_desc *desc, u8 *out) { - struct shash_alg *shash = crypto_shash_alg(desc->tfm); - int err; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&shash_get_stat(shash)->hash_cnt); - - err = shash->final(desc, out); - - return crypto_shash_errstat(shash, err); + return crypto_shash_alg(desc->tfm)->final(desc, out); } EXPORT_SYMBOL_GPL(crypto_shash_final); @@ -99,20 +71,7 @@ static int shash_default_finup(struct shash_desc *desc, const u8 *data, int crypto_shash_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - int err; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_hash *istat = shash_get_stat(shash); - - atomic64_inc(&istat->hash_cnt); - atomic64_add(len, &istat->hash_tlen); - } - - err = shash->finup(desc, data, len, out); - - return crypto_shash_errstat(shash, err); + return crypto_shash_alg(desc->tfm)->finup(desc, data, len, out); } EXPORT_SYMBOL_GPL(crypto_shash_finup); @@ -129,22 +88,11 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - int err; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_hash *istat = shash_get_stat(shash); - - atomic64_inc(&istat->hash_cnt); - atomic64_add(len, &istat->hash_tlen); - } if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - err = -ENOKEY; - else - err = shash->digest(desc, data, len, out); + return -ENOKEY; - return crypto_shash_errstat(shash, err); + return crypto_shash_alg(desc->tfm)->digest(desc, data, len, out); } EXPORT_SYMBOL_GPL(crypto_shash_digest); @@ -265,12 +213,6 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "digestsize : %u\n", salg->digestsize); } -static int __maybe_unused crypto_shash_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - return crypto_hash_report_stat(skb, alg, "shash"); -} - const struct crypto_type crypto_shash_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_shash_init_tfm, @@ -280,9 +222,6 @@ const struct crypto_type crypto_shash_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_shash_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_shash_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -350,7 +289,6 @@ EXPORT_SYMBOL_GPL(crypto_clone_shash); int hash_prepare_alg(struct hash_alg_common *alg) { - struct crypto_istat_hash *istat = hash_get_stat(alg); struct crypto_alg *base = &alg->base; if (alg->digestsize > HASH_MAX_DIGESTSIZE) @@ -362,9 +300,6 @@ int hash_prepare_alg(struct hash_alg_common *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); - return 0; } diff --git a/crypto/sig.c b/crypto/sig.c index 224c47019297..7645bedf3a1f 100644 --- a/crypto/sig.c +++ b/crypto/sig.c @@ -45,16 +45,6 @@ static int __maybe_unused crypto_sig_report(struct sk_buff *skb, return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rsig), &rsig); } -static int __maybe_unused crypto_sig_report_stat(struct sk_buff *skb, - struct crypto_alg *alg) -{ - struct crypto_stat_akcipher rsig = {}; - - strscpy(rsig.type, "sig", sizeof(rsig.type)); - - return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, sizeof(rsig), &rsig); -} - static const struct crypto_type crypto_sig_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_sig_init_tfm, @@ -63,9 +53,6 @@ static const struct crypto_type crypto_sig_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_sig_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_sig_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_SIG_MASK, diff --git a/crypto/skcipher.c b/crypto/skcipher.c index bc70e159d27d..ceed7f33a67b 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -89,25 +89,6 @@ static inline struct skcipher_alg *__crypto_skcipher_alg( return container_of(alg, struct skcipher_alg, base); } -static inline struct crypto_istat_cipher *skcipher_get_stat( - struct skcipher_alg *alg) -{ - return skcipher_get_stat_common(&alg->co); -} - -static inline int crypto_skcipher_errstat(struct skcipher_alg *alg, int err) -{ - struct crypto_istat_cipher *istat = skcipher_get_stat(alg); - - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&istat->err_cnt); - - return err; -} - static int skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) { u8 *addr; @@ -654,23 +635,12 @@ int crypto_skcipher_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct skcipher_alg *alg = crypto_skcipher_alg(tfm); - int ret; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_cipher *istat = skcipher_get_stat(alg); - - atomic64_inc(&istat->encrypt_cnt); - atomic64_add(req->cryptlen, &istat->encrypt_tlen); - } if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - ret = -ENOKEY; - else if (alg->co.base.cra_type != &crypto_skcipher_type) - ret = crypto_lskcipher_encrypt_sg(req); - else - ret = alg->encrypt(req); - - return crypto_skcipher_errstat(alg, ret); + return -ENOKEY; + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_encrypt_sg(req); + return alg->encrypt(req); } EXPORT_SYMBOL_GPL(crypto_skcipher_encrypt); @@ -678,23 +648,12 @@ int crypto_skcipher_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct skcipher_alg *alg = crypto_skcipher_alg(tfm); - int ret; - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_cipher *istat = skcipher_get_stat(alg); - - atomic64_inc(&istat->decrypt_cnt); - atomic64_add(req->cryptlen, &istat->decrypt_tlen); - } if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - ret = -ENOKEY; - else if (alg->co.base.cra_type != &crypto_skcipher_type) - ret = crypto_lskcipher_decrypt_sg(req); - else - ret = alg->decrypt(req); - - return crypto_skcipher_errstat(alg, ret); + return -ENOKEY; + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_decrypt_sg(req); + return alg->decrypt(req); } EXPORT_SYMBOL_GPL(crypto_skcipher_decrypt); @@ -846,28 +805,6 @@ static int __maybe_unused crypto_skcipher_report( sizeof(rblkcipher), &rblkcipher); } -static int __maybe_unused crypto_skcipher_report_stat( - struct sk_buff *skb, struct crypto_alg *alg) -{ - struct skcipher_alg *skcipher = __crypto_skcipher_alg(alg); - struct crypto_istat_cipher *istat; - struct crypto_stat_cipher rcipher; - - istat = skcipher_get_stat(skcipher); - - memset(&rcipher, 0, sizeof(rcipher)); - - strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); - - rcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); - rcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); - rcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); - rcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); - rcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); - - return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); -} - static const struct crypto_type crypto_skcipher_type = { .extsize = crypto_skcipher_extsize, .init_tfm = crypto_skcipher_init_tfm, @@ -877,9 +814,6 @@ static const struct crypto_type crypto_skcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_skcipher_report, -#endif -#ifdef CONFIG_CRYPTO_STATS - .report_stat = crypto_skcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_SKCIPHER_MASK, @@ -935,7 +869,6 @@ EXPORT_SYMBOL_GPL(crypto_has_skcipher); int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) { - struct crypto_istat_cipher *istat = skcipher_get_stat_common(alg); struct crypto_alg *base = &alg->base; if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8 || @@ -948,9 +881,6 @@ int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - memset(istat, 0, sizeof(*istat)); - return 0; } diff --git a/crypto/skcipher.h b/crypto/skcipher.h index 16c9484360da..703651367dd8 100644 --- a/crypto/skcipher.h +++ b/crypto/skcipher.h @@ -10,16 +10,6 @@ #include #include "internal.h" -static inline struct crypto_istat_cipher *skcipher_get_stat_common( - struct skcipher_alg_common *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - int crypto_lskcipher_encrypt_sg(struct skcipher_request *req); int crypto_lskcipher_decrypt_sg(struct skcipher_request *req); int crypto_init_lskcipher_ops_sg(struct crypto_tfm *tfm); diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h index 574cffc90730..d042c90e0907 100644 --- a/include/crypto/acompress.h +++ b/include/crypto/acompress.h @@ -56,35 +56,6 @@ struct crypto_acomp { struct crypto_tfm base; }; -/* - * struct crypto_istat_compress - statistics for compress algorithm - * @compress_cnt: number of compress requests - * @compress_tlen: total data size handled by compress requests - * @decompress_cnt: number of decompress requests - * @decompress_tlen: total data size handled by decompress requests - * @err_cnt: number of error for compress requests - */ -struct crypto_istat_compress { - atomic64_t compress_cnt; - atomic64_t compress_tlen; - atomic64_t decompress_cnt; - atomic64_t decompress_tlen; - atomic64_t err_cnt; -}; - -#ifdef CONFIG_CRYPTO_STATS -#define COMP_ALG_COMMON_STATS struct crypto_istat_compress stat; -#else -#define COMP_ALG_COMMON_STATS -#endif - -#define COMP_ALG_COMMON { \ - COMP_ALG_COMMON_STATS \ - \ - struct crypto_alg base; \ -} -struct comp_alg_common COMP_ALG_COMMON; - /** * DOC: Asynchronous Compression API * @@ -132,23 +103,11 @@ static inline struct crypto_tfm *crypto_acomp_tfm(struct crypto_acomp *tfm) return &tfm->base; } -static inline struct comp_alg_common *__crypto_comp_alg_common( - struct crypto_alg *alg) -{ - return container_of(alg, struct comp_alg_common, base); -} - static inline struct crypto_acomp *__crypto_acomp_tfm(struct crypto_tfm *tfm) { return container_of(tfm, struct crypto_acomp, base); } -static inline struct comp_alg_common *crypto_comp_alg_common( - struct crypto_acomp *tfm) -{ - return __crypto_comp_alg_common(crypto_acomp_tfm(tfm)->__crt_alg); -} - static inline unsigned int crypto_acomp_reqsize(struct crypto_acomp *tfm) { return tfm->reqsize; @@ -255,27 +214,6 @@ static inline void acomp_request_set_params(struct acomp_req *req, req->flags |= CRYPTO_ACOMP_ALLOC_OUTPUT; } -static inline struct crypto_istat_compress *comp_get_stat( - struct comp_alg_common *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - -static inline int crypto_comp_errstat(struct comp_alg_common *alg, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&comp_get_stat(alg)->err_cnt); - - return err; -} - /** * crypto_acomp_compress() -- Invoke asynchronous compress operation * @@ -287,19 +225,7 @@ static inline int crypto_comp_errstat(struct comp_alg_common *alg, int err) */ static inline int crypto_acomp_compress(struct acomp_req *req) { - struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); - struct comp_alg_common *alg; - - alg = crypto_comp_alg_common(tfm); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_compress *istat = comp_get_stat(alg); - - atomic64_inc(&istat->compress_cnt); - atomic64_add(req->slen, &istat->compress_tlen); - } - - return crypto_comp_errstat(alg, tfm->compress(req)); + return crypto_acomp_reqtfm(req)->compress(req); } /** @@ -313,19 +239,7 @@ static inline int crypto_acomp_compress(struct acomp_req *req) */ static inline int crypto_acomp_decompress(struct acomp_req *req) { - struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); - struct comp_alg_common *alg; - - alg = crypto_comp_alg_common(tfm); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_compress *istat = comp_get_stat(alg); - - atomic64_inc(&istat->decompress_cnt); - atomic64_add(req->slen, &istat->decompress_tlen); - } - - return crypto_comp_errstat(alg, tfm->decompress(req)); + return crypto_acomp_reqtfm(req)->decompress(req); } #endif diff --git a/include/crypto/aead.h b/include/crypto/aead.h index 51382befbe37..0e8a41638678 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -101,22 +101,6 @@ struct aead_request { void *__ctx[] CRYPTO_MINALIGN_ATTR; }; -/* - * struct crypto_istat_aead - statistics for AEAD algorithm - * @encrypt_cnt: number of encrypt requests - * @encrypt_tlen: total data size handled by encrypt requests - * @decrypt_cnt: number of decrypt requests - * @decrypt_tlen: total data size handled by decrypt requests - * @err_cnt: number of error for AEAD requests - */ -struct crypto_istat_aead { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t err_cnt; -}; - /** * struct aead_alg - AEAD cipher definition * @maxauthsize: Set the maximum authentication tag size supported by the @@ -135,7 +119,6 @@ struct crypto_istat_aead { * @setkey: see struct skcipher_alg * @encrypt: see struct skcipher_alg * @decrypt: see struct skcipher_alg - * @stat: statistics for AEAD algorithm * @ivsize: see struct skcipher_alg * @chunksize: see struct skcipher_alg * @init: Initialize the cryptographic transformation object. This function @@ -162,10 +145,6 @@ struct aead_alg { int (*init)(struct crypto_aead *tfm); void (*exit)(struct crypto_aead *tfm); -#ifdef CONFIG_CRYPTO_STATS - struct crypto_istat_aead stat; -#endif - unsigned int ivsize; unsigned int maxauthsize; unsigned int chunksize; diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 31c111bebb68..18a10cad07aa 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -54,26 +54,6 @@ struct crypto_akcipher { struct crypto_tfm base; }; -/* - * struct crypto_istat_akcipher - statistics for akcipher algorithm - * @encrypt_cnt: number of encrypt requests - * @encrypt_tlen: total data size handled by encrypt requests - * @decrypt_cnt: number of decrypt requests - * @decrypt_tlen: total data size handled by decrypt requests - * @verify_cnt: number of verify operation - * @sign_cnt: number of sign requests - * @err_cnt: number of error for akcipher requests - */ -struct crypto_istat_akcipher { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t verify_cnt; - atomic64_t sign_cnt; - atomic64_t err_cnt; -}; - /** * struct akcipher_alg - generic public key algorithm * @@ -110,7 +90,6 @@ struct crypto_istat_akcipher { * @exit: Deinitialize the cryptographic transformation object. This is a * counterpart to @init, used to remove various changes set in * @init. - * @stat: Statistics for akcipher algorithm * * @base: Common crypto API algorithm data structure */ @@ -127,10 +106,6 @@ struct akcipher_alg { int (*init)(struct crypto_akcipher *tfm); void (*exit)(struct crypto_akcipher *tfm); -#ifdef CONFIG_CRYPTO_STATS - struct crypto_istat_akcipher stat; -#endif - struct crypto_alg base; }; @@ -302,27 +277,6 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm) return alg->max_size(tfm); } -static inline struct crypto_istat_akcipher *akcipher_get_stat( - struct akcipher_alg *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - -static inline int crypto_akcipher_errstat(struct akcipher_alg *alg, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&akcipher_get_stat(alg)->err_cnt); - - return err; -} - /** * crypto_akcipher_encrypt() - Invoke public key encrypt operation * @@ -336,16 +290,8 @@ static inline int crypto_akcipher_errstat(struct akcipher_alg *alg, int err) static inline int crypto_akcipher_encrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); - - atomic64_inc(&istat->encrypt_cnt); - atomic64_add(req->src_len, &istat->encrypt_tlen); - } - - return crypto_akcipher_errstat(alg, alg->encrypt(req)); + return crypto_akcipher_alg(tfm)->encrypt(req); } /** @@ -361,16 +307,8 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req) static inline int crypto_akcipher_decrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); - - atomic64_inc(&istat->decrypt_cnt); - atomic64_add(req->src_len, &istat->decrypt_tlen); - } - - return crypto_akcipher_errstat(alg, alg->decrypt(req)); + return crypto_akcipher_alg(tfm)->decrypt(req); } /** @@ -422,12 +360,8 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, static inline int crypto_akcipher_sign(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&akcipher_get_stat(alg)->sign_cnt); - - return crypto_akcipher_errstat(alg, alg->sign(req)); + return crypto_akcipher_alg(tfm)->sign(req); } /** @@ -447,12 +381,8 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req) static inline int crypto_akcipher_verify(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&akcipher_get_stat(alg)->verify_cnt); - - return crypto_akcipher_errstat(alg, alg->verify(req)); + return crypto_akcipher_alg(tfm)->verify(req); } /** diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 7a4a71af653f..156de41ca760 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -61,9 +61,6 @@ struct crypto_type { void (*show)(struct seq_file *m, struct crypto_alg *alg); int (*report)(struct sk_buff *skb, struct crypto_alg *alg); void (*free)(struct crypto_instance *inst); -#ifdef CONFIG_CRYPTO_STATS - int (*report_stat)(struct sk_buff *skb, struct crypto_alg *alg); -#endif unsigned int type; unsigned int maskclear; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 5d61f576cfc8..0014bdd81ab7 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -23,27 +23,8 @@ struct crypto_ahash; * crypto_unregister_shash(). */ -/* - * struct crypto_istat_hash - statistics for has algorithm - * @hash_cnt: number of hash requests - * @hash_tlen: total data size hashed - * @err_cnt: number of error for hash requests - */ -struct crypto_istat_hash { - atomic64_t hash_cnt; - atomic64_t hash_tlen; - atomic64_t err_cnt; -}; - -#ifdef CONFIG_CRYPTO_STATS -#define HASH_ALG_COMMON_STAT struct crypto_istat_hash stat; -#else -#define HASH_ALG_COMMON_STAT -#endif - /* * struct hash_alg_common - define properties of message digest - * @stat: Statistics for hash algorithm. * @digestsize: Size of the result of the transformation. A buffer of this size * must be available to the @final and @finup calls, so they can * store the resulting hash into it. For various predefined sizes, @@ -60,8 +41,6 @@ struct crypto_istat_hash { * information. */ #define HASH_ALG_COMMON { \ - HASH_ALG_COMMON_STAT \ - \ unsigned int digestsize; \ unsigned int statesize; \ \ @@ -243,7 +222,6 @@ struct shash_alg { }; }; #undef HASH_ALG_COMMON -#undef HASH_ALG_COMMON_STAT struct crypto_ahash { bool using_shash; /* Underlying algorithm is shash, not ahash */ diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h index 4ac46bafba9d..475e60a9f9ea 100644 --- a/include/crypto/internal/acompress.h +++ b/include/crypto/internal/acompress.h @@ -31,9 +31,7 @@ * @init. * * @reqsize: Context size for (de)compression requests - * @stat: Statistics for compress algorithm * @base: Common crypto API algorithm data structure - * @calg: Cmonn algorithm data structure shared with scomp */ struct acomp_alg { int (*compress)(struct acomp_req *req); @@ -44,10 +42,7 @@ struct acomp_alg { unsigned int reqsize; - union { - struct COMP_ALG_COMMON; - struct comp_alg_common calg; - }; + struct crypto_alg base; }; /* diff --git a/include/crypto/internal/cryptouser.h b/include/crypto/internal/cryptouser.h deleted file mode 100644 index fd54074332f5..000000000000 --- a/include/crypto/internal/cryptouser.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include - -struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact); - -#ifdef CONFIG_CRYPTO_STATS -int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs); -#else -static inline int crypto_reportstat(struct sk_buff *in_skb, - struct nlmsghdr *in_nlh, - struct nlattr **attrs) -{ - return -ENOTSUPP; -} -#endif diff --git a/include/crypto/internal/scompress.h b/include/crypto/internal/scompress.h index 858fe3965ae3..5a75f2db18ce 100644 --- a/include/crypto/internal/scompress.h +++ b/include/crypto/internal/scompress.h @@ -27,9 +27,7 @@ struct crypto_scomp { * @free_ctx: Function frees context allocated with alloc_ctx * @compress: Function performs a compress operation * @decompress: Function performs a de-compress operation - * @stat: Statistics for compress algorithm * @base: Common crypto API algorithm data structure - * @calg: Cmonn algorithm data structure shared with acomp */ struct scomp_alg { void *(*alloc_ctx)(struct crypto_scomp *tfm); @@ -40,11 +38,7 @@ struct scomp_alg { int (*decompress)(struct crypto_scomp *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen, void *ctx); - - union { - struct COMP_ALG_COMMON; - struct comp_alg_common calg; - }; + struct crypto_alg base; }; static inline struct scomp_alg *__crypto_scomp_alg(struct crypto_alg *alg) diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h index 1988e24a0d1d..2d9c4de57b69 100644 --- a/include/crypto/kpp.h +++ b/include/crypto/kpp.h @@ -51,20 +51,6 @@ struct crypto_kpp { struct crypto_tfm base; }; -/* - * struct crypto_istat_kpp - statistics for KPP algorithm - * @setsecret_cnt: number of setsecrey operation - * @generate_public_key_cnt: number of generate_public_key operation - * @compute_shared_secret_cnt: number of compute_shared_secret operation - * @err_cnt: number of error for KPP requests - */ -struct crypto_istat_kpp { - atomic64_t setsecret_cnt; - atomic64_t generate_public_key_cnt; - atomic64_t compute_shared_secret_cnt; - atomic64_t err_cnt; -}; - /** * struct kpp_alg - generic key-agreement protocol primitives * @@ -87,7 +73,6 @@ struct crypto_istat_kpp { * @exit: Undo everything @init did. * * @base: Common crypto API algorithm data structure - * @stat: Statistics for KPP algorithm */ struct kpp_alg { int (*set_secret)(struct crypto_kpp *tfm, const void *buffer, @@ -100,10 +85,6 @@ struct kpp_alg { int (*init)(struct crypto_kpp *tfm); void (*exit)(struct crypto_kpp *tfm); -#ifdef CONFIG_CRYPTO_STATS - struct crypto_istat_kpp stat; -#endif - struct crypto_alg base; }; @@ -291,26 +272,6 @@ struct kpp_secret { unsigned short len; }; -static inline struct crypto_istat_kpp *kpp_get_stat(struct kpp_alg *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - -static inline int crypto_kpp_errstat(struct kpp_alg *alg, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&kpp_get_stat(alg)->err_cnt); - - return err; -} - /** * crypto_kpp_set_secret() - Invoke kpp operation * @@ -329,12 +290,7 @@ static inline int crypto_kpp_errstat(struct kpp_alg *alg, int err) static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, const void *buffer, unsigned int len) { - struct kpp_alg *alg = crypto_kpp_alg(tfm); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&kpp_get_stat(alg)->setsecret_cnt); - - return crypto_kpp_errstat(alg, alg->set_secret(tfm, buffer, len)); + return crypto_kpp_alg(tfm)->set_secret(tfm, buffer, len); } /** @@ -353,12 +309,8 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, static inline int crypto_kpp_generate_public_key(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); - struct kpp_alg *alg = crypto_kpp_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&kpp_get_stat(alg)->generate_public_key_cnt); - - return crypto_kpp_errstat(alg, alg->generate_public_key(req)); + return crypto_kpp_alg(tfm)->generate_public_key(req); } /** @@ -374,12 +326,8 @@ static inline int crypto_kpp_generate_public_key(struct kpp_request *req) static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); - struct kpp_alg *alg = crypto_kpp_alg(tfm); - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) - atomic64_inc(&kpp_get_stat(alg)->compute_shared_secret_cnt); - - return crypto_kpp_errstat(alg, alg->compute_shared_secret(req)); + return crypto_kpp_alg(tfm)->compute_shared_secret(req); } /** diff --git a/include/crypto/rng.h b/include/crypto/rng.h index 6abe5102e5fb..5ac4388f50e1 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -15,20 +15,6 @@ struct crypto_rng; -/* - * struct crypto_istat_rng: statistics for RNG algorithm - * @generate_cnt: number of RNG generate requests - * @generate_tlen: total data size of generated data by the RNG - * @seed_cnt: number of times the RNG was seeded - * @err_cnt: number of error for RNG requests - */ -struct crypto_istat_rng { - atomic64_t generate_cnt; - atomic64_t generate_tlen; - atomic64_t seed_cnt; - atomic64_t err_cnt; -}; - /** * struct rng_alg - random number generator definition * @@ -46,7 +32,6 @@ struct crypto_istat_rng { * size of the seed is defined with @seedsize . * @set_ent: Set entropy that would otherwise be obtained from * entropy source. Internal use only. - * @stat: Statistics for rng algorithm * @seedsize: The seed size required for a random number generator * initialization defined with this variable. Some * random number generators does not require a seed @@ -63,10 +48,6 @@ struct rng_alg { void (*set_ent)(struct crypto_rng *tfm, const u8 *data, unsigned int len); -#ifdef CONFIG_CRYPTO_STATS - struct crypto_istat_rng stat; -#endif - unsigned int seedsize; struct crypto_alg base; @@ -144,26 +125,6 @@ static inline void crypto_free_rng(struct crypto_rng *tfm) crypto_destroy_tfm(tfm, crypto_rng_tfm(tfm)); } -static inline struct crypto_istat_rng *rng_get_stat(struct rng_alg *alg) -{ -#ifdef CONFIG_CRYPTO_STATS - return &alg->stat; -#else - return NULL; -#endif -} - -static inline int crypto_rng_errstat(struct rng_alg *alg, int err) -{ - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) - atomic64_inc(&rng_get_stat(alg)->err_cnt); - - return err; -} - /** * crypto_rng_generate() - get random number * @tfm: cipher handle @@ -182,17 +143,7 @@ static inline int crypto_rng_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { - struct rng_alg *alg = crypto_rng_alg(tfm); - - if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { - struct crypto_istat_rng *istat = rng_get_stat(alg); - - atomic64_inc(&istat->generate_cnt); - atomic64_add(dlen, &istat->generate_tlen); - } - - return crypto_rng_errstat(alg, - alg->generate(tfm, src, slen, dst, dlen)); + return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); } /** diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index c8857d7bdb37..74d47e23374e 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -64,28 +64,6 @@ struct crypto_lskcipher { struct crypto_tfm base; }; -/* - * struct crypto_istat_cipher - statistics for cipher algorithm - * @encrypt_cnt: number of encrypt requests - * @encrypt_tlen: total data size handled by encrypt requests - * @decrypt_cnt: number of decrypt requests - * @decrypt_tlen: total data size handled by decrypt requests - * @err_cnt: number of error for cipher requests - */ -struct crypto_istat_cipher { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t err_cnt; -}; - -#ifdef CONFIG_CRYPTO_STATS -#define SKCIPHER_ALG_COMMON_STAT struct crypto_istat_cipher stat; -#else -#define SKCIPHER_ALG_COMMON_STAT -#endif - /* * struct skcipher_alg_common - common properties of skcipher_alg * @min_keysize: Minimum key size supported by the transformation. This is the @@ -103,7 +81,6 @@ struct crypto_istat_cipher { * @chunksize: Equal to the block size except for stream ciphers such as * CTR where it is set to the underlying block size. * @statesize: Size of the internal state for the algorithm. - * @stat: Statistics for cipher algorithm * @base: Definition of a generic crypto algorithm. */ #define SKCIPHER_ALG_COMMON { \ @@ -113,8 +90,6 @@ struct crypto_istat_cipher { unsigned int chunksize; \ unsigned int statesize; \ \ - SKCIPHER_ALG_COMMON_STAT \ - \ struct crypto_alg base; \ } struct skcipher_alg_common SKCIPHER_ALG_COMMON; diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h index 5730c67f0617..e163670d60f7 100644 --- a/include/uapi/linux/cryptouser.h +++ b/include/uapi/linux/cryptouser.h @@ -54,16 +54,16 @@ enum crypto_attr_type_t { CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */ - CRYPTOCFGA_STAT_LARVAL, /* struct crypto_stat */ - CRYPTOCFGA_STAT_HASH, /* struct crypto_stat */ - CRYPTOCFGA_STAT_BLKCIPHER, /* struct crypto_stat */ - CRYPTOCFGA_STAT_AEAD, /* struct crypto_stat */ - CRYPTOCFGA_STAT_COMPRESS, /* struct crypto_stat */ - CRYPTOCFGA_STAT_RNG, /* struct crypto_stat */ - CRYPTOCFGA_STAT_CIPHER, /* struct crypto_stat */ - CRYPTOCFGA_STAT_AKCIPHER, /* struct crypto_stat */ - CRYPTOCFGA_STAT_KPP, /* struct crypto_stat */ - CRYPTOCFGA_STAT_ACOMP, /* struct crypto_stat */ + CRYPTOCFGA_STAT_LARVAL, /* No longer supported */ + CRYPTOCFGA_STAT_HASH, /* No longer supported */ + CRYPTOCFGA_STAT_BLKCIPHER, /* No longer supported */ + CRYPTOCFGA_STAT_AEAD, /* No longer supported */ + CRYPTOCFGA_STAT_COMPRESS, /* No longer supported */ + CRYPTOCFGA_STAT_RNG, /* No longer supported */ + CRYPTOCFGA_STAT_CIPHER, /* No longer supported */ + CRYPTOCFGA_STAT_AKCIPHER, /* No longer supported */ + CRYPTOCFGA_STAT_KPP, /* No longer supported */ + CRYPTOCFGA_STAT_ACOMP, /* No longer supported */ __CRYPTOCFGA_MAX #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) @@ -79,6 +79,7 @@ struct crypto_user_alg { __u32 cru_flags; }; +/* No longer supported, do not use. */ struct crypto_stat_aead { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -88,6 +89,7 @@ struct crypto_stat_aead { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_akcipher { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -99,6 +101,7 @@ struct crypto_stat_akcipher { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_cipher { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -108,6 +111,7 @@ struct crypto_stat_cipher { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_compress { char type[CRYPTO_MAX_NAME]; __u64 stat_compress_cnt; @@ -117,6 +121,7 @@ struct crypto_stat_compress { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_hash { char type[CRYPTO_MAX_NAME]; __u64 stat_hash_cnt; @@ -124,6 +129,7 @@ struct crypto_stat_hash { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_kpp { char type[CRYPTO_MAX_NAME]; __u64 stat_setsecret_cnt; @@ -132,6 +138,7 @@ struct crypto_stat_kpp { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_rng { char type[CRYPTO_MAX_NAME]; __u64 stat_generate_cnt; @@ -140,6 +147,7 @@ struct crypto_stat_rng { __u64 stat_err_cnt; }; +/* No longer supported, do not use. */ struct crypto_stat_larval { char type[CRYPTO_MAX_NAME]; }; From 7bb9f42d9e588837e7b5683f58d6fa2e92a945ea Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:53:10 +0530 Subject: [PATCH 591/814] dt-bindings: crypto: add sam9x7 in Atmel AES Add DT bindings for atmel AES. Signed-off-by: Varshini Rajendran Acked-by: Rob Herring Reviewed-by: Tudor Ambarus Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml index 0b7383b3106b..7dc0748444fd 100644 --- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml +++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml @@ -12,7 +12,11 @@ maintainers: properties: compatible: - const: atmel,at91sam9g46-aes + oneOf: + - const: atmel,at91sam9g46-aes + - items: + - const: microchip,sam9x7-aes + - const: atmel,at91sam9g46-aes reg: maxItems: 1 From 4234f365ebd2657296ab135ecacda476905b4425 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:53:58 +0530 Subject: [PATCH 592/814] dt-bindings: crypto: add sam9x7 in Atmel SHA Add DT bindings for atmel SHA. Signed-off-by: Varshini Rajendran Acked-by: Rob Herring Reviewed-by: Tudor Ambarus Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml index ee2ffb034325..d378c53314dd 100644 --- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml +++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml @@ -12,7 +12,11 @@ maintainers: properties: compatible: - const: atmel,at91sam9g46-sha + oneOf: + - const: atmel,at91sam9g46-sha + - items: + - const: microchip,sam9x7-sha + - const: atmel,at91sam9g46-sha reg: maxItems: 1 From 1e45f6051f2c83e61d59c6a19cf4b6a54af7093b Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:54:45 +0530 Subject: [PATCH 593/814] dt-bindings: crypto: add sam9x7 in Atmel TDES Add DT bindings for atmel TDES. Signed-off-by: Varshini Rajendran Acked-by: Nicolas Ferre Acked-by: Conor Dooley Reviewed-by: Tudor Ambarus Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml index 3d6ed24b1b00..6a441f79efea 100644 --- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml +++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml @@ -12,7 +12,11 @@ maintainers: properties: compatible: - const: atmel,at91sam9g46-tdes + oneOf: + - const: atmel,at91sam9g46-tdes + - items: + - const: microchip,sam9x7-tdes + - const: atmel,at91sam9g46-tdes reg: maxItems: 1 From 7248e523a0d5a0eb06a710d79fc649e30616b890 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:55:40 +0530 Subject: [PATCH 594/814] dt-bindings: rng: atmel,at91-trng: add sam9x7 TRNG Add compatbile for Microchip sam9x7 TRNG. Signed-off-by: Varshini Rajendran Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml index 3ce45456d867..b38f8252342e 100644 --- a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml +++ b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml @@ -21,6 +21,10 @@ properties: - enum: - microchip,sama7g5-trng - const: atmel,at91sam9g45-trng + - items: + - enum: + - microchip,sam9x7-trng + - const: microchip,sam9x60-trng clocks: maxItems: 1 From 262534ddc88dfea7474ed18adfecf856e4fbe054 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 25 Feb 2024 14:11:33 -0600 Subject: [PATCH 595/814] crypto: iaa - Fix async_disable descriptor leak The disable_async paths of iaa_compress/decompress() don't free idxd descriptors in the async_disable case. Currently this only happens in the testcases where req->dst is set to null. Add a test to free them in those paths. Signed-off-by: Tom Zanussi Signed-off-by: Herbert Xu --- drivers/crypto/intel/iaa/iaa_crypto_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index 39a5fc905c4d..85ee4c965ccf 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -1222,7 +1222,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req, *compression_crc = idxd_desc->iax_completion->crc; - if (!ctx->async_mode) + if (!ctx->async_mode || disable_async) idxd_free_desc(wq, idxd_desc); out: return ret; @@ -1468,7 +1468,7 @@ static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req, *dlen = req->dlen; - if (!ctx->async_mode) + if (!ctx->async_mode || disable_async) idxd_free_desc(wq, idxd_desc); /* Update stats */ From cdb083e73d632afcc5a931d31bb37445580f4bfb Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 25 Feb 2024 14:11:34 -0600 Subject: [PATCH 596/814] crypto: iaa - Fix comp/decomp delay statistics The comp/decomp delay statistics currently have no callers; somehow they were dropped during refactoring. There originally were also two sets, one for the async algorithm, the other for the synchronous version. Because the synchronous algorithm was dropped, one set should be removed. To keep it consistent with the rest of the stats, and since there's no ambiguity, remove the acomp/adecomp versions. Also add back the callers. Reported-by: Rex Zhang Signed-off-by: Tom Zanussi Signed-off-by: Herbert Xu --- drivers/crypto/intel/iaa/iaa_crypto_main.c | 9 +++++++ drivers/crypto/intel/iaa/iaa_crypto_stats.c | 28 --------------------- drivers/crypto/intel/iaa/iaa_crypto_stats.h | 8 +++--- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index 85ee4c965ccf..b54f93c64033 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -1494,6 +1494,7 @@ static int iaa_comp_acompress(struct acomp_req *req) u32 compression_crc; struct idxd_wq *wq; struct device *dev; + u64 start_time_ns; int order = -1; compression_ctx = crypto_tfm_ctx(tfm); @@ -1567,8 +1568,10 @@ static int iaa_comp_acompress(struct acomp_req *req) " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, req->dst, req->dlen, sg_dma_len(req->dst)); + start_time_ns = iaa_get_ts(); ret = iaa_compress(tfm, req, wq, src_addr, req->slen, dst_addr, &req->dlen, &compression_crc, disable_async); + update_max_comp_delay_ns(start_time_ns); if (ret == -EINPROGRESS) return ret; @@ -1615,6 +1618,7 @@ static int iaa_comp_adecompress_alloc_dest(struct acomp_req *req) struct iaa_wq *iaa_wq; struct device *dev; struct idxd_wq *wq; + u64 start_time_ns; int order = -1; cpu = get_cpu(); @@ -1671,8 +1675,10 @@ alloc_dest: dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p," " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, req->dst, req->dlen, sg_dma_len(req->dst)); + start_time_ns = iaa_get_ts(); ret = iaa_decompress(tfm, req, wq, src_addr, req->slen, dst_addr, &req->dlen, true); + update_max_decomp_delay_ns(start_time_ns); if (ret == -EOVERFLOW) { dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); req->dlen *= 2; @@ -1703,6 +1709,7 @@ static int iaa_comp_adecompress(struct acomp_req *req) int nr_sgs, cpu, ret = 0; struct iaa_wq *iaa_wq; struct device *dev; + u64 start_time_ns; struct idxd_wq *wq; if (!iaa_crypto_enabled) { @@ -1762,8 +1769,10 @@ static int iaa_comp_adecompress(struct acomp_req *req) " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, req->dst, req->dlen, sg_dma_len(req->dst)); + start_time_ns = iaa_get_ts(); ret = iaa_decompress(tfm, req, wq, src_addr, req->slen, dst_addr, &req->dlen, false); + update_max_decomp_delay_ns(start_time_ns); if (ret == -EINPROGRESS) return ret; diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.c b/drivers/crypto/intel/iaa/iaa_crypto_stats.c index cbf87d0effe3..c9f83af4b307 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_stats.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.c @@ -22,8 +22,6 @@ static u64 total_decomp_calls; static u64 total_sw_decomp_calls; static u64 max_comp_delay_ns; static u64 max_decomp_delay_ns; -static u64 max_acomp_delay_ns; -static u64 max_adecomp_delay_ns; static u64 total_comp_bytes_out; static u64 total_decomp_bytes_in; static u64 total_completion_einval_errors; @@ -92,26 +90,6 @@ void update_max_decomp_delay_ns(u64 start_time_ns) max_decomp_delay_ns = time_diff; } -void update_max_acomp_delay_ns(u64 start_time_ns) -{ - u64 time_diff; - - time_diff = ktime_get_ns() - start_time_ns; - - if (time_diff > max_acomp_delay_ns) - max_acomp_delay_ns = time_diff; -} - -void update_max_adecomp_delay_ns(u64 start_time_ns) -{ - u64 time_diff; - - time_diff = ktime_get_ns() - start_time_ns; - - if (time_diff > max_adecomp_delay_ns) - max_adecomp_delay_ns = time_diff; -} - void update_wq_comp_calls(struct idxd_wq *idxd_wq) { struct iaa_wq *wq = idxd_wq_get_private(idxd_wq); @@ -151,8 +129,6 @@ static void reset_iaa_crypto_stats(void) total_sw_decomp_calls = 0; max_comp_delay_ns = 0; max_decomp_delay_ns = 0; - max_acomp_delay_ns = 0; - max_adecomp_delay_ns = 0; total_comp_bytes_out = 0; total_decomp_bytes_in = 0; total_completion_einval_errors = 0; @@ -280,10 +256,6 @@ int __init iaa_crypto_debugfs_init(void) iaa_crypto_debugfs_root, &max_comp_delay_ns); debugfs_create_u64("max_decomp_delay_ns", 0644, iaa_crypto_debugfs_root, &max_decomp_delay_ns); - debugfs_create_u64("max_acomp_delay_ns", 0644, - iaa_crypto_debugfs_root, &max_comp_delay_ns); - debugfs_create_u64("max_adecomp_delay_ns", 0644, - iaa_crypto_debugfs_root, &max_decomp_delay_ns); debugfs_create_u64("total_comp_calls", 0644, iaa_crypto_debugfs_root, &total_comp_calls); debugfs_create_u64("total_decomp_calls", 0644, diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.h b/drivers/crypto/intel/iaa/iaa_crypto_stats.h index c10b87b86fa4..c916ca83f070 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_stats.h +++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.h @@ -15,8 +15,6 @@ void update_total_sw_decomp_calls(void); void update_total_decomp_bytes_in(int n); void update_max_comp_delay_ns(u64 start_time_ns); void update_max_decomp_delay_ns(u64 start_time_ns); -void update_max_acomp_delay_ns(u64 start_time_ns); -void update_max_adecomp_delay_ns(u64 start_time_ns); void update_completion_einval_errs(void); void update_completion_timeout_errs(void); void update_completion_comp_buf_overflow_errs(void); @@ -26,6 +24,8 @@ void update_wq_comp_bytes(struct idxd_wq *idxd_wq, int n); void update_wq_decomp_calls(struct idxd_wq *idxd_wq); void update_wq_decomp_bytes(struct idxd_wq *idxd_wq, int n); +static inline u64 iaa_get_ts(void) { return ktime_get_ns(); } + #else static inline int iaa_crypto_debugfs_init(void) { return 0; } static inline void iaa_crypto_debugfs_cleanup(void) {} @@ -37,8 +37,6 @@ static inline void update_total_sw_decomp_calls(void) {} static inline void update_total_decomp_bytes_in(int n) {} static inline void update_max_comp_delay_ns(u64 start_time_ns) {} static inline void update_max_decomp_delay_ns(u64 start_time_ns) {} -static inline void update_max_acomp_delay_ns(u64 start_time_ns) {} -static inline void update_max_adecomp_delay_ns(u64 start_time_ns) {} static inline void update_completion_einval_errs(void) {} static inline void update_completion_timeout_errs(void) {} static inline void update_completion_comp_buf_overflow_errs(void) {} @@ -48,6 +46,8 @@ static inline void update_wq_comp_bytes(struct idxd_wq *idxd_wq, int n) {} static inline void update_wq_decomp_calls(struct idxd_wq *idxd_wq) {} static inline void update_wq_decomp_bytes(struct idxd_wq *idxd_wq, int n) {} +static inline u64 iaa_get_ts(void) { return 0; } + #endif // CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS #endif From 9a3bfb27ef65ad41d994765c031ca18217afb058 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 29 Feb 2024 14:54:17 +0000 Subject: [PATCH 597/814] KVM: arm64: Fix TRFCR_EL1/PMSCR_EL1 access in hVHE mode When running in hVHE mode, EL1 accesses are performed with the EL12 accessor, as we run with HCR_EL2.E2H=1. Unfortunately, both PMSCR_EL1 and TRFCR_EL1 are used with the EL1 accessor, meaning that we actually affect the EL2 state. Duh. Switch to using the {read,write}_sysreg_el1() helpers that will do the right thing in all circumstances. Note that the 'Fixes:' tag doesn't represent the point where the bug was introduced (there is no such point), but the first practical point where the hVHE feature is usable. Cc: James Clark Cc: Anshuman Khandual Fixes: 38cba55008e5 ("KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set") Signed-off-by: Marc Zyngier Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20240229145417.3606279-1-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/debug-sr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c index 4558c02eb352..7746ea507b6f 100644 --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c @@ -31,8 +31,8 @@ static void __debug_save_spe(u64 *pmscr_el1) return; /* Yes; save the control register and disable data generation */ - *pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1); - write_sysreg_s(0, SYS_PMSCR_EL1); + *pmscr_el1 = read_sysreg_el1(SYS_PMSCR); + write_sysreg_el1(0, SYS_PMSCR); isb(); /* Now drain all buffered data to memory */ @@ -48,7 +48,7 @@ static void __debug_restore_spe(u64 pmscr_el1) isb(); /* Re-enable data generation */ - write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1); + write_sysreg_el1(pmscr_el1, SYS_PMSCR); } static void __debug_save_trace(u64 *trfcr_el1) @@ -63,8 +63,8 @@ static void __debug_save_trace(u64 *trfcr_el1) * Since access to TRFCR_EL1 is trapped, the guest can't * modify the filtering set by the host. */ - *trfcr_el1 = read_sysreg_s(SYS_TRFCR_EL1); - write_sysreg_s(0, SYS_TRFCR_EL1); + *trfcr_el1 = read_sysreg_el1(SYS_TRFCR); + write_sysreg_el1(0, SYS_TRFCR); isb(); /* Drain the trace buffer to memory */ tsb_csync(); @@ -76,7 +76,7 @@ static void __debug_restore_trace(u64 trfcr_el1) return; /* Restore trace filter controls */ - write_sysreg_s(trfcr_el1, SYS_TRFCR_EL1); + write_sysreg_el1(trfcr_el1, SYS_TRFCR); } void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu) From 336157be7e93394901a8752354562449fcd3ee0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 22 Feb 2024 16:31:20 +0100 Subject: [PATCH 598/814] of/platform: Inform about created platform devices using pr_debug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For most nodes with a compatible property a platform device is created. For some an amba device is created instead. For the latter of_amba_device_create() emits a message at debug level about the node the device is created from. Add a similar message to of_platform_device_create_pdata() to inform about the whole list of created devices. This also gives the right context for the following messages that inform about created child devices. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240222153119.2026363-2-u.kleine-koenig@pengutronix.de Signed-off-by: Rob Herring --- drivers/of/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index b7708a06dc78..ba964df6b6db 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -166,6 +166,8 @@ static struct platform_device *of_platform_device_create_pdata( { struct platform_device *dev; + pr_debug("create platform device: %pOF\n", np); + if (!of_device_is_available(np) || of_node_test_and_set_flag(np, OF_POPULATED)) return NULL; From 1238913f24c479cbcfb68040f0a9c7d699525db2 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 23 Feb 2024 09:14:55 -0700 Subject: [PATCH 599/814] dt-bindings: watchdog: qcom-wdt: Update maintainer to Rajendra Nayak The servers for the @codeaurora domain are long retired and any messages sent there will bounce. Sai has left the company and appears no longer active in the community which leaves this binding orphaned. Rajendra Nayak has volunteered to take over as maintainer. Signed-off-by: Jeffrey Hugo Reviewed-by: Guenter Roeck Acked-by: Rajendra Nayak Link: https://lore.kernel.org/r/20240223161455.4009469-1-quic_jhugo@quicinc.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index a4f35c598cdb..47587971fb0b 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Krait Processor Sub-system (KPSS) Watchdog timer maintainers: - - Sai Prakash Ranjan + - Rajendra Nayak properties: $nodename: From 75b737693bd9511a3b79cd8bd10c3af871dca5ec Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Sat, 17 Feb 2024 15:17:15 +0100 Subject: [PATCH 600/814] dt-bindings: watchdog: drop obsolete brcm,bcm2835-pm-wdt bindings These bindings are already (better) described in soc/bcm/brcm,bcm2835-pm.yaml. Drop these obsolete bindings. Signed-off-by: Stanislav Jakubek Acked-by: Conor Dooley Link: https://lore.kernel.org/r/ZdC/624d1c8O3NRG@standask-GA-A55M-S2HP Signed-off-by: Rob Herring --- .../bindings/watchdog/brcm,bcm2835-pm-wdog.txt | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt diff --git a/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt b/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt deleted file mode 100644 index f801d71de1cd..000000000000 --- a/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt +++ /dev/null @@ -1,18 +0,0 @@ -BCM2835 Watchdog timer - -Required properties: - -- compatible : should be "brcm,bcm2835-pm-wdt" -- reg : Specifies base physical address and size of the registers. - -Optional properties: - -- timeout-sec : Contains the watchdog timeout in seconds - -Example: - -watchdog { - compatible = "brcm,bcm2835-pm-wdt"; - reg = <0x7e100000 0x28>; - timeout-sec = <10>; -}; From 835e4cce453f34f323911a836eb669be2d01889d Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 23 Feb 2024 09:20:27 -0700 Subject: [PATCH 601/814] dt-bindings: net: bluetooth: qualcomm: Fix bouncing @codeaurora The servers for the @codeaurora domain are long retired and any messages sent there will bounce. Update the maintainer addresses for this binding to match the entries in .mailmap so that anyone looking in the file for a contact will see a correct address. Signed-off-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20240223162027.4016065-1-quic_jhugo@quicinc.com Signed-off-by: Rob Herring --- .../devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index eba2f3026ab0..528ef3572b62 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -7,8 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Bluetooth Chips maintainers: - - Balakrishna Godavarthi - - Rocky Liao + - Balakrishna Godavarthi + - Rocky Liao description: This binding describes Qualcomm UART-attached bluetooth chips. From abc6b0269197e824deeff3fccb79d84a6a330a1f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 24 Feb 2024 09:44:14 +0100 Subject: [PATCH 602/814] dt-bindings: arm: syna: remove unstable remark Marvell Berlin SoCs (later Syna) bindings were marked as work-in-progress / unstable in 2015 in commit f07b4e49d27e ("Documentation: bindings: berlin: consider our dt bindings as unstable"). Almost nine years is enough, so drop the "unstable" remark and expect usual ABI rules. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240224084414.6264-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/arm/syna.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/syna.txt b/Documentation/devicetree/bindings/arm/syna.txt index 851f48ead927..f53c430f648c 100644 --- a/Documentation/devicetree/bindings/arm/syna.txt +++ b/Documentation/devicetree/bindings/arm/syna.txt @@ -6,18 +6,6 @@ berlin SoCs are now Synaptics' SoCs now. --------------------------------------------------------------- -Work in progress statement: - -Device tree files and bindings applying to Marvell Berlin SoCs and boards are -considered "unstable". Any Marvell Berlin device tree binding may change at any -time. Be sure to use a device tree binary and a kernel image generated from the -same source tree. - -Please refer to Documentation/devicetree/bindings/ABI.rst for a definition of a -stable binding/ABI. - ---------------------------------------------------------------- - Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500 shall have the following properties: From c583953557888459cd6419cc1fd5dfcc8df5ddc3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 22 Feb 2024 10:43:42 -0700 Subject: [PATCH 603/814] dt-bindings: i2c: Remove obsolete i2c.txt Everything in i2c.txt is covered by schemas/i2c/i2c-controller.yaml in dtschema project, so remove i2c.txt and update links to it in the tree. Reviewed-by: Wolfram Sang Acked-by: Mark Brown Link: https://lore.kernel.org/r/20240222174343.3482354-2-robh@kernel.org Signed-off-by: Rob Herring --- .../bindings/gpio/gateworks,pld-gpio.txt | 3 +- Documentation/devicetree/bindings/i2c/i2c.txt | 151 ------------------ .../i2c/nvidia,tegra186-bpmp-i2c.yaml | 3 +- .../devicetree/bindings/i3c/i3c.yaml | 2 +- .../devicetree/bindings/sound/cs4341.txt | 2 +- MAINTAINERS | 1 - 6 files changed, 4 insertions(+), 158 deletions(-) delete mode 100644 Documentation/devicetree/bindings/i2c/i2c.txt diff --git a/Documentation/devicetree/bindings/gpio/gateworks,pld-gpio.txt b/Documentation/devicetree/bindings/gpio/gateworks,pld-gpio.txt index 6e81f8b755c5..d543fd1b8b23 100644 --- a/Documentation/devicetree/bindings/gpio/gateworks,pld-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gateworks,pld-gpio.txt @@ -1,7 +1,6 @@ Gateworks PLD GPIO controller bindings -The GPIO controller should be a child node on an I2C bus, -see: i2c/i2c.txt for details. +The GPIO controller should be a child node on an I2C bus. Required properties: - compatible: Should be "gateworks,pld-gpio" diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt deleted file mode 100644 index fc3dd7ec0445..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ /dev/null @@ -1,151 +0,0 @@ -Generic device tree bindings for I2C busses -=========================================== - -This document describes generic bindings which can be used to describe I2C -busses and their child devices in a device tree. - -Required properties (per bus) ------------------------------ - -- #address-cells - should be <1>. Read more about addresses below. -- #size-cells - should be <0>. -- compatible - name of I2C bus controller - -For other required properties e.g. to describe register sets, -clocks, etc. check the binding documentation of the specific driver. - -The cells properties above define that an address of children of an I2C bus -are described by a single value. - -Optional properties (per bus) ------------------------------ - -These properties may not be supported by all drivers. However, if a driver -wants to support one of the below features, it should adapt these bindings. - -- clock-frequency - frequency of bus clock in Hz. - -- i2c-bus - For I2C adapters that have child nodes that are a mixture of both I2C - devices and non-I2C devices, the 'i2c-bus' subnode can be used for - populating I2C devices. If the 'i2c-bus' subnode is present, only - subnodes of this will be considered as I2C slaves. The properties, - '#address-cells' and '#size-cells' must be defined under this subnode - if present. - -- i2c-scl-falling-time-ns - Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C - specification. - -- i2c-scl-internal-delay-ns - Number of nanoseconds the IP core additionally needs to setup SCL. - -- i2c-scl-rising-time-ns - Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C - specification. - -- i2c-sda-falling-time-ns - Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C - specification. - -- i2c-analog-filter - Enable analog filter for i2c lines. - -- i2c-digital-filter - Enable digital filter for i2c lines. - -- i2c-digital-filter-width-ns - Width of spikes which can be filtered by digital filter - (i2c-digital-filter). This width is specified in nanoseconds. - -- i2c-analog-filter-cutoff-frequency - Frequency that the analog filter (i2c-analog-filter) uses to distinguish - which signal to filter. Signal with higher frequency than specified will - be filtered out. Only lower frequency will pass (this is applicable to - a low-pass analog filter). Typical value should be above the normal - i2c bus clock frequency (clock-frequency). - Specified in Hz. - -- multi-master - states that there is another master active on this bus. The OS can use - this information to adapt power management to keep the arbitration awake - all the time, for example. Can not be combined with 'single-master'. - -- pinctrl - add extra pinctrl to configure SCL/SDA pins to GPIO function for bus - recovery, call it "gpio" or "recovery" (deprecated) state - -- scl-gpios - specify the gpio related to SCL pin. Used for GPIO bus recovery. - -- sda-gpios - specify the gpio related to SDA pin. Optional for GPIO bus recovery. - -- single-master - states that there is no other master active on this bus. The OS can use - this information to detect a stalled bus more reliably, for example. - Can not be combined with 'multi-master'. - -- smbus - states that additional SMBus restrictions and features apply to this bus. - An example of feature is SMBusHostNotify. Examples of restrictions are - more reserved addresses and timeout definitions. - -- smbus-alert - states that the optional SMBus-Alert feature apply to this bus. - -- mctp-controller - indicates that the system is accessible via this bus as an endpoint for - MCTP over I2C transport. - -Required properties (per child device) --------------------------------------- - -- compatible - name of I2C slave device - -- reg - One or many I2C slave addresses. These are usually a 7 bit addresses. - However, flags can be attached to an address. I2C_TEN_BIT_ADDRESS is - used to mark a 10 bit address. It is needed to avoid the ambiguity - between e.g. a 7 bit address of 0x50 and a 10 bit address of 0x050 - which, in theory, can be on the same bus. - Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we - listen to be devices ourselves. - -Optional properties (per child device) --------------------------------------- - -These properties may not be supported by all drivers. However, if a driver -wants to support one of the below features, it should adapt these bindings. - -- host-notify - device uses SMBus host notify protocol instead of interrupt line. - -- interrupts - interrupts used by the device. - -- interrupt-names - "irq", "wakeup" and "smbus_alert" names are recognized by I2C core, - other names are left to individual drivers. - -- reg-names - Names of map programmable addresses. - It can contain any map needing another address than default one. - -- wakeup-source - device can be used as a wakeup source. - -Binding may contain optional "interrupts" property, describing interrupts -used by the device. I2C core will assign "irq" interrupt (or the very first -interrupt if not using interrupt names) as primary interrupt for the slave. - -Alternatively, devices supporting SMBus Host Notify, and connected to -adapters that support this feature, may use "host-notify" property. I2C -core will create a virtual interrupt for Host Notify and assign it as -primary interrupt for the slave. - -Also, if device is marked as a wakeup source, I2C core will set up "wakeup" -interrupt for the device. If "wakeup" interrupt name is not present in the -binding, then primary interrupt will be used as wakeup interrupt. diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.yaml b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.yaml index b8319dcf3d8a..8676335e9e94 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.yaml @@ -21,8 +21,7 @@ description: | See ../firmware/nvidia,tegra186-bpmp.yaml for details of the BPMP binding. - This node represents an I2C controller. See ../i2c/i2c.txt for details - of the core I2C binding. + This node represents an I2C controller. properties: compatible: diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml index c816e295d565..87cadbcdc61c 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.yaml +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml @@ -71,7 +71,7 @@ patternProperties: description: | I2C child, should be named: @ - All properties described in Documentation/devicetree/bindings/i2c/i2c.txt + All properties described in dtschema schemas/i2c/i2c-controller.yaml are valid here, except the reg property whose content is changed. properties: diff --git a/Documentation/devicetree/bindings/sound/cs4341.txt b/Documentation/devicetree/bindings/sound/cs4341.txt index 12b4aa8ef0db..c1d5c8ad1a36 100644 --- a/Documentation/devicetree/bindings/sound/cs4341.txt +++ b/Documentation/devicetree/bindings/sound/cs4341.txt @@ -9,7 +9,7 @@ Required properties: number for SPI. For required properties on I2C-bus, please consult -Documentation/devicetree/bindings/i2c/i2c.txt +dtschema schemas/i2c/i2c-controller.yaml For required properties on SPI-bus, please consult Documentation/devicetree/bindings/spi/spi-bus.txt diff --git a/MAINTAINERS b/MAINTAINERS index 45c6c13b4edf..50a906eb8dfd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10074,7 +10074,6 @@ S: Maintained W: https://i2c.wiki.kernel.org/ Q: https://patchwork.ozlabs.org/project/linux-i2c/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git -F: Documentation/devicetree/bindings/i2c/i2c.txt F: Documentation/i2c/ F: drivers/i2c/* F: include/dt-bindings/i2c/i2c.h From 8512ed256334f6637fc0699ce794792c357544ec Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Tue, 27 Feb 2024 16:32:04 -0800 Subject: [PATCH 604/814] vfio/pds: Always clear the save/restore FDs on reset After reset the VFIO device state will always be put in VFIO_DEVICE_STATE_RUNNING, but the save/restore files will only be cleared if the previous state was VFIO_DEVICE_STATE_ERROR. This can/will cause the restore/save files to be leaked if/when the migration state machine transitions through the states that re-allocates these files. Fix this by always clearing the restore/save files for resets. Fixes: 7dabb1bcd177 ("vfio/pds: Add support for firmware recovery") Cc: stable@vger.kernel.org Signed-off-by: Brett Creeley Reviewed-by: Shannon Nelson Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240228003205.47311-2-brett.creeley@amd.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/pds/vfio_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/pci/pds/vfio_dev.c b/drivers/vfio/pci/pds/vfio_dev.c index 4c351c59d05a..a286ebcc7112 100644 --- a/drivers/vfio/pci/pds/vfio_dev.c +++ b/drivers/vfio/pci/pds/vfio_dev.c @@ -32,9 +32,9 @@ again: mutex_lock(&pds_vfio->reset_mutex); if (pds_vfio->deferred_reset) { pds_vfio->deferred_reset = false; + pds_vfio_put_restore_file(pds_vfio); + pds_vfio_put_save_file(pds_vfio); if (pds_vfio->state == VFIO_DEVICE_STATE_ERROR) { - pds_vfio_put_restore_file(pds_vfio); - pds_vfio_put_save_file(pds_vfio); pds_vfio_dirty_disable(pds_vfio, false); } pds_vfio->state = pds_vfio->deferred_reset_state; From 3c8016e681c5e0f5f3ad15edb4569727cd32eaff Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 11:17:33 +0100 Subject: [PATCH 605/814] powerpc: Refactor __kernel_map_pages() __kernel_map_pages() is almost identical for PPC32 and RADIX. Refactor it. On PPC32 it is not needed for KFENCE, but to keep it simple just make it similar to PPC64. Move the prototype of hash__kernel_map_pages() into mmu_decl.h to allow IS_ENABLED() to work on 32-bit. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/3656d47c53bff577739dac536dbae31fff52f6d8.1708078640.git.christophe.leroy@csgroup.eu --- arch/powerpc/include/asm/book3s/64/hash.h | 2 -- arch/powerpc/include/asm/book3s/64/pgtable.h | 10 ---------- arch/powerpc/include/asm/book3s/64/radix.h | 2 -- arch/powerpc/mm/book3s64/radix_pgtable.c | 14 -------------- arch/powerpc/mm/mmu_decl.h | 2 ++ arch/powerpc/mm/pageattr.c | 20 ++++++++++++++++++++ arch/powerpc/mm/pgtable_32.c | 15 --------------- 7 files changed, 22 insertions(+), 43 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h index 6e70ae511631..faf3e3b4e4b2 100644 --- a/arch/powerpc/include/asm/book3s/64/hash.h +++ b/arch/powerpc/include/asm/book3s/64/hash.h @@ -269,8 +269,6 @@ int hash__create_section_mapping(unsigned long start, unsigned long end, int nid, pgprot_t prot); int hash__remove_section_mapping(unsigned long start, unsigned long end); -void hash__kernel_map_pages(struct page *page, int numpages, int enable); - #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_H */ diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 927d585652bc..62c43d3d80ec 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1027,16 +1027,6 @@ static inline void vmemmap_remove_mapping(unsigned long start, } #endif -#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) -static inline void __kernel_map_pages(struct page *page, int numpages, int enable) -{ - if (radix_enabled()) - radix__kernel_map_pages(page, numpages, enable); - else - hash__kernel_map_pages(page, numpages, enable); -} -#endif - static inline pte_t pmd_pte(pmd_t pmd) { return __pte_raw(pmd_raw(pmd)); diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index 357e23a403d3..8f55ff74bb68 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -362,8 +362,6 @@ int radix__create_section_mapping(unsigned long start, unsigned long end, int radix__remove_section_mapping(unsigned long start, unsigned long end); #endif /* CONFIG_MEMORY_HOTPLUG */ -void radix__kernel_map_pages(struct page *page, int numpages, int enable); - #ifdef CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP #define vmemmap_can_optimize vmemmap_can_optimize bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap); diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index c6a4ac766b2b..e16e2fd104c5 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -1339,20 +1339,6 @@ void __ref radix__vmemmap_free(unsigned long start, unsigned long end, #endif #endif -#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) -void radix__kernel_map_pages(struct page *page, int numpages, int enable) -{ - unsigned long addr; - - addr = (unsigned long)page_address(page); - - if (enable) - set_memory_p(addr, numpages); - else - set_memory_np(addr, numpages); -} -#endif - #ifdef CONFIG_TRANSPARENT_HUGEPAGE unsigned long radix__pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 72341b9fb552..4eb62bb51d49 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -186,3 +186,5 @@ static inline bool debug_pagealloc_enabled_or_kfence(void) int create_section_mapping(unsigned long start, unsigned long end, int nid, pgprot_t prot); #endif + +void hash__kernel_map_pages(struct page *page, int numpages, int enable); diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c index 421db7c4f2a4..8a9d24218b74 100644 --- a/arch/powerpc/mm/pageattr.c +++ b/arch/powerpc/mm/pageattr.c @@ -14,6 +14,7 @@ #include #include +#include static pte_basic_t pte_update_delta(pte_t *ptep, unsigned long addr, unsigned long old, unsigned long new) @@ -101,3 +102,22 @@ int change_memory_attr(unsigned long addr, int numpages, long action) return apply_to_existing_page_range(&init_mm, start, size, change_page_attr, (void *)action); } + +#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) +#ifdef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC +void __kernel_map_pages(struct page *page, int numpages, int enable) +{ + unsigned long addr = (unsigned long)page_address(page); + + if (PageHighMem(page)) + return; + + if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !radix_enabled()) + hash__kernel_map_pages(page, numpages, enable); + else if (enable) + set_memory_p(addr, numpages); + else + set_memory_np(addr, numpages); +} +#endif +#endif diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 5c02fd08d61e..04aec716aa0e 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -171,18 +171,3 @@ void mark_rodata_ro(void) ptdump_check_wx(); } #endif - -#if defined(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC) && defined(CONFIG_DEBUG_PAGEALLOC) -void __kernel_map_pages(struct page *page, int numpages, int enable) -{ - unsigned long addr = (unsigned long)page_address(page); - - if (PageHighMem(page)) - return; - - if (enable) - set_memory_p(addr, numpages); - else - set_memory_np(addr, numpages); -} -#endif /* CONFIG_DEBUG_PAGEALLOC */ From 9cbacb834b4afcb55eb8ac5115fa82fc7ede5c83 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 16 Feb 2024 11:17:34 +0100 Subject: [PATCH 606/814] powerpc: Don't ignore errors from set_memory_{n}p() in __kernel_map_pages() set_memory_p() and set_memory_np() can fail. As mentioned in linux/mm.h: /* * To support DEBUG_PAGEALLOC architecture must ensure that * __kernel_map_pages() never fails */ So panic in case set_memory_p() or set_memory_np() fail in __kernel_map_pages(). Link: https://github.com/KSPP/linux/issues/7 Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/20ef75884aa6a636e8298736f3d1056b0793d3d9.1708078640.git.christophe.leroy@csgroup.eu --- arch/powerpc/mm/book3s64/hash_utils.c | 3 ++- arch/powerpc/mm/mmu_decl.h | 2 +- arch/powerpc/mm/pageattr.c | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index 0626a25b0d72..01c3b4b65241 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -2172,7 +2172,7 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) mmu_kernel_ssize, 0); } -void hash__kernel_map_pages(struct page *page, int numpages, int enable) +int hash__kernel_map_pages(struct page *page, int numpages, int enable) { unsigned long flags, vaddr, lmi; int i; @@ -2189,6 +2189,7 @@ void hash__kernel_map_pages(struct page *page, int numpages, int enable) kernel_unmap_linear_page(vaddr, lmi); } local_irq_restore(flags); + return 0; } #endif /* CONFIG_DEBUG_PAGEALLOC || CONFIG_KFENCE */ diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 4eb62bb51d49..b4b662a61485 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -187,4 +187,4 @@ int create_section_mapping(unsigned long start, unsigned long end, int nid, pgprot_t prot); #endif -void hash__kernel_map_pages(struct page *page, int numpages, int enable); +int hash__kernel_map_pages(struct page *page, int numpages, int enable); diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c index 8a9d24218b74..ac22bf28086f 100644 --- a/arch/powerpc/mm/pageattr.c +++ b/arch/powerpc/mm/pageattr.c @@ -107,17 +107,21 @@ int change_memory_attr(unsigned long addr, int numpages, long action) #ifdef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC void __kernel_map_pages(struct page *page, int numpages, int enable) { + int err; unsigned long addr = (unsigned long)page_address(page); if (PageHighMem(page)) return; if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !radix_enabled()) - hash__kernel_map_pages(page, numpages, enable); + err = hash__kernel_map_pages(page, numpages, enable); else if (enable) - set_memory_p(addr, numpages); + err = set_memory_p(addr, numpages); else - set_memory_np(addr, numpages); + err = set_memory_np(addr, numpages); + + if (err) + panic("%s: changing memory protections failed\n", __func__); } #endif #endif From b997bf240ebdfb36de5a138e94b77c3228507f07 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 17 Jan 2024 15:46:32 -0600 Subject: [PATCH 607/814] powerpc: Enable support for 32 bit MSI-X vectors Some devices are not capable of addressing 64 bits via DMA, which includes MSI-X vectors. This allows us to ensure these devices use MSI-X vectors in 32 bit space. Signed-off-by: Brian King Signed-off-by: Michael Ellerman Link: https://msgid.link/20240117214632.134539-1-brking@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/msi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 423ee1d5bd94..6dfb55b52d36 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -26,6 +26,7 @@ static int query_token, change_token; #define RTAS_CHANGE_MSI_FN 3 #define RTAS_CHANGE_MSIX_FN 4 #define RTAS_CHANGE_32MSI_FN 5 +#define RTAS_CHANGE_32MSIX_FN 6 /* RTAS Helpers */ @@ -41,7 +42,7 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) seq_num = 1; do { if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN || - func == RTAS_CHANGE_32MSI_FN) + func == RTAS_CHANGE_32MSI_FN || func == RTAS_CHANGE_32MSIX_FN) rc = rtas_call(change_token, 6, 4, rtas_ret, addr, BUID_HI(buid), BUID_LO(buid), func, num_irqs, seq_num); @@ -406,8 +407,12 @@ again: if (use_32bit_msi_hack && rc > 0) rtas_hack_32bit_msi_gen2(pdev); - } else - rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); + } else { + if (pdev->no_64bit_msi) + rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSIX_FN, nvec); + else + rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); + } if (rc != nvec) { if (nvec != nvec_in) { From b72c066ba85a131091498a15a62d6068997278a4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 11 Feb 2024 14:16:23 -0800 Subject: [PATCH 608/814] powerpc/32: fix ADB_CUDA kconfig warning Fix a (randconfig) kconfig warning by correcting the select statement: WARNING: unmet direct dependencies detected for ADB_CUDA Depends on [n]: MACINTOSH_DRIVERS [=n] && (ADB [=n] || PPC_PMAC [=y]) && !PPC_PMAC64 [=n] Selected by [y]: - PPC_PMAC [=y] && PPC_BOOK3S [=y] && CPU_BIG_ENDIAN [=y] && POWER_RESET [=y] && PPC32 [=y] The PPC32 isn't needed because ADB depends on (PPC_PMAC && PPC32). Fixes: a3ef2fef198c ("powerpc/32: Add dependencies of POWER_RESET for pmac32") Signed-off-by: Randy Dunlap Tested: Randy Dunlap Signed-off-by: Michael Ellerman Link: https://msgid.link/20240211221623.31112-1-rdunlap@infradead.org --- arch/powerpc/platforms/powermac/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index 8bdae0caf21e..84f101ec53a9 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig @@ -2,7 +2,7 @@ config PPC_PMAC bool "Apple PowerMac based machines" depends on PPC_BOOK3S && CPU_BIG_ENDIAN - select ADB_CUDA if POWER_RESET && PPC32 + select ADB_CUDA if POWER_RESET && ADB select MPIC select FORCE_PCI select PPC_INDIRECT_PCI if PPC32 From 6035e7e35482653d6d93f35f01e1a320573d58f0 Mon Sep 17 00:00:00 2001 From: Sathvika Vasireddy Date: Thu, 15 Dec 2022 17:22:58 +0530 Subject: [PATCH 609/814] powerpc/32: Curb objtool unannotated intra-function call warning objtool throws the following warning: arch/powerpc/kexec/relocate_32.o: warning: objtool: .text+0x2bc: unannotated intra-function call Fix this warning by annotating intra-function call, using ANNOTATE_INTRA_FUNCTION_CALL macro, to indicate that the branch target is valid. Reported-by: kernel test robot Signed-off-by: Sathvika Vasireddy Signed-off-by: Michael Ellerman Link: https://msgid.link/20221215115258.80810-1-sv@linux.ibm.com --- arch/powerpc/kexec/relocate_32.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kexec/relocate_32.S b/arch/powerpc/kexec/relocate_32.S index d9f0dd9b34ff..104c9911f406 100644 --- a/arch/powerpc/kexec/relocate_32.S +++ b/arch/powerpc/kexec/relocate_32.S @@ -8,6 +8,7 @@ * Author: Suzuki Poulose */ +#include #include #include #include @@ -349,6 +350,7 @@ write_utlb: cmpwi r10, PPC47x_TLB0_4K bne 0f li r10, 0x1000 /* r10 = 4k */ + ANNOTATE_INTRA_FUNCTION_CALL bl 1f 0: From cda9c0d556283e2d4adaa9960b2dc19b16156bae Mon Sep 17 00:00:00 2001 From: Qiheng Lin Date: Thu, 8 Dec 2022 21:34:49 +0800 Subject: [PATCH 610/814] powerpc/pseries: Fix potential memleak in papr_get_attr() `buf` is allocated in papr_get_attr(), and krealloc() of `buf` could fail. We need to free the original `buf` in the case of failure. Fixes: 3c14b73454cf ("powerpc/pseries: Interface to represent PAPR firmware attributes") Signed-off-by: Qiheng Lin Signed-off-by: Michael Ellerman Link: https://msgid.link/20221208133449.16284-1-linqiheng@huawei.com --- arch/powerpc/platforms/pseries/papr_platform_attributes.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/pseries/papr_platform_attributes.c b/arch/powerpc/platforms/pseries/papr_platform_attributes.c index 526c621b098b..eea2041b270b 100644 --- a/arch/powerpc/platforms/pseries/papr_platform_attributes.c +++ b/arch/powerpc/platforms/pseries/papr_platform_attributes.c @@ -101,10 +101,12 @@ retry: esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * max_esi_attrs); temp_buf = krealloc(buf, esi_buf_size, GFP_KERNEL); - if (temp_buf) + if (temp_buf) { buf = temp_buf; - else - return -ENOMEM; + } else { + ret = -ENOMEM; + goto out_buf; + } goto retry; } From 69b0194ccec033c208b071e019032c1919c2822d Mon Sep 17 00:00:00 2001 From: Li zeming Date: Mon, 19 Dec 2022 10:18:16 +0800 Subject: [PATCH 611/814] powerpc/boot: Handle allocation failure in simple_realloc() simple_malloc() will return NULL when there is not enough memory left. Check pointer 'new' before using it to copy the old data. Signed-off-by: Li zeming [mpe: Reword subject, use change log from Christophe] Signed-off-by: Michael Ellerman Link: https://msgid.link/20221219021816.3012-1-zeming@nfschina.com --- arch/powerpc/boot/simple_alloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c index 267d6524caac..db9aaa5face3 100644 --- a/arch/powerpc/boot/simple_alloc.c +++ b/arch/powerpc/boot/simple_alloc.c @@ -112,7 +112,9 @@ static void *simple_realloc(void *ptr, unsigned long size) return ptr; new = simple_malloc(size); - memcpy(new, ptr, p->size); + if (new) + memcpy(new, ptr, p->size); + simple_free(ptr); return new; } From f2d5bccaca3e8c09c9b9c8485375f7bdbb2631d2 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 22:51:49 +1100 Subject: [PATCH 612/814] powerpc/boot: Only free if realloc() succeeds simple_realloc() frees the original buffer (ptr) even if the reallocation failed. Fix it to behave like standard realloc() and only free the original buffer if the reallocation succeeded. Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229115149.749264-1-mpe@ellerman.id.au --- arch/powerpc/boot/simple_alloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c index db9aaa5face3..d07796fdf91a 100644 --- a/arch/powerpc/boot/simple_alloc.c +++ b/arch/powerpc/boot/simple_alloc.c @@ -112,10 +112,11 @@ static void *simple_realloc(void *ptr, unsigned long size) return ptr; new = simple_malloc(size); - if (new) + if (new) { memcpy(new, ptr, p->size); + simple_free(ptr); + } - simple_free(ptr); return new; } From 3f9f3557aca2bc5335747f0ac613661fb573be54 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 22:42:16 +1100 Subject: [PATCH 613/814] powerpc/85xx: Make some pic_init functions static These functions can all be static, make them so, which also fixes no previous prototype warnings. Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229114216.744502-1-mpe@ellerman.id.au --- arch/powerpc/platforms/85xx/bsc913x_qds.c | 2 +- arch/powerpc/platforms/85xx/bsc913x_rdb.c | 2 +- arch/powerpc/platforms/85xx/ge_imp3a.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/85xx/bsc913x_qds.c b/arch/powerpc/platforms/85xx/bsc913x_qds.c index 2eb62bff86d4..3ad8096fcf16 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_qds.c +++ b/arch/powerpc/platforms/85xx/bsc913x_qds.c @@ -19,7 +19,7 @@ #include "mpc85xx.h" #include "smp.h" -void __init bsc913x_qds_pic_init(void) +static void __init bsc913x_qds_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/bsc913x_rdb.c b/arch/powerpc/platforms/85xx/bsc913x_rdb.c index 161f006cb3bb..dcd358c28201 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_rdb.c +++ b/arch/powerpc/platforms/85xx/bsc913x_rdb.c @@ -15,7 +15,7 @@ #include "mpc85xx.h" -void __init bsc913x_rdb_pic_init(void) +static void __init bsc913x_rdb_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c index 9c3b44a1952e..477852f1a726 100644 --- a/arch/powerpc/platforms/85xx/ge_imp3a.c +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -38,7 +38,7 @@ void __iomem *imp3a_regs; -void __init ge_imp3a_pic_init(void) +static void __init ge_imp3a_pic_init(void) { struct mpic *mpic; struct device_node *np; From af1ebca503f4c5bb9345dd251faaa825431ce972 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 22:41:08 +1100 Subject: [PATCH 614/814] powerpc: Add allmodconfig for all 32-bit sub-arches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 32-bit powerpc kernels can be built for one of 5 sub-arches, see Kconfig.cputype: PPC_BOOK3S_32: "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx" PPC_85xx: "Freescale 85xx" PPC_8xx: "Freescale 8xx" 40x: "AMCC 40x" 44x: "AMCC 44x, 46x or 47x" By default none of these are built for a plain allmodconfig build, because it selects PPC64 which builds a 64-bit kernel. There is already a ppc32_allmodconfig, which enables PPC_BOOK3S_32. Add similar targets for the other 32-bit sub-arches to increase build coverage: ppc40x_allmodconfig ppc44x_allmodconfig ppc8xx_allmodconfig ppc85xx_allmodconfig Acked-by: Uwe Kleine-König Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229114108.743810-1-mpe@ellerman.id.au --- arch/powerpc/Makefile | 20 ++++++++++++++++++++ arch/powerpc/configs/40x.config | 2 ++ arch/powerpc/configs/44x.config | 2 ++ arch/powerpc/configs/85xx-32bit.config | 1 + arch/powerpc/configs/8xx.config | 2 ++ 5 files changed, 27 insertions(+) create mode 100644 arch/powerpc/configs/40x.config create mode 100644 arch/powerpc/configs/44x.config create mode 100644 arch/powerpc/configs/8xx.config diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 051247027da0..4b8c9ff79d0f 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -314,6 +314,26 @@ ppc32_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/book3s_32.config \ -f $(srctree)/Makefile allmodconfig +generated_configs += ppc40x_allmodconfig +ppc40x_allmodconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/40x.config \ + -f $(srctree)/Makefile allmodconfig + +generated_configs += ppc44x_allmodconfig +ppc44x_allmodconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/44x.config \ + -f $(srctree)/Makefile allmodconfig + +generated_configs += ppc8xx_allmodconfig +ppc8xx_allmodconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/8xx.config \ + -f $(srctree)/Makefile allmodconfig + +generated_configs += ppc85xx_allmodconfig +ppc85xx_allmodconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/85xx-32bit.config \ + -f $(srctree)/Makefile allmodconfig + generated_configs += ppc_defconfig ppc_defconfig: $(call merge_into_defconfig,book3s_32.config,) diff --git a/arch/powerpc/configs/40x.config b/arch/powerpc/configs/40x.config new file mode 100644 index 000000000000..82a9d58ddb81 --- /dev/null +++ b/arch/powerpc/configs/40x.config @@ -0,0 +1,2 @@ +CONFIG_PPC64=n +CONFIG_40x=y diff --git a/arch/powerpc/configs/44x.config b/arch/powerpc/configs/44x.config new file mode 100644 index 000000000000..79b7b1962995 --- /dev/null +++ b/arch/powerpc/configs/44x.config @@ -0,0 +1,2 @@ +CONFIG_PPC64=n +CONFIG_44x=y diff --git a/arch/powerpc/configs/85xx-32bit.config b/arch/powerpc/configs/85xx-32bit.config index 6b8894d727a2..a85310bcb1fd 100644 --- a/arch/powerpc/configs/85xx-32bit.config +++ b/arch/powerpc/configs/85xx-32bit.config @@ -1,3 +1,4 @@ +CONFIG_PPC64=n CONFIG_HIGHMEM=y CONFIG_KEXEC=y CONFIG_PPC_85xx=y diff --git a/arch/powerpc/configs/8xx.config b/arch/powerpc/configs/8xx.config new file mode 100644 index 000000000000..7eb3ffbbd667 --- /dev/null +++ b/arch/powerpc/configs/8xx.config @@ -0,0 +1,2 @@ +CONFIG_PPC64=n +CONFIG_PPC_8xx=y From c029b22f8a98e14988f800d5c0176a9eaec3c8db Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Dec 2023 21:31:48 +1100 Subject: [PATCH 615/814] of: Add of_machine_compatible_match() We have of_machine_is_compatible() to check if a machine is compatible with a single compatible string. However some code is able to support multiple compatible boards, and so wants to check for one of many compatible strings. So add of_machine_compatible_match() which takes a NULL terminated array of compatible strings to check against the root node's compatible property. Compared to an open coded match this is slightly more self documenting, and also avoids the caller needing to juggle the root node either directly or via of_find_node_by_path(). Signed-off-by: Christophe Leroy Reviewed-by: Rob Herring Signed-off-by: Michael Ellerman Link: https://msgid.link/20231214103152.12269-1-mpe@ellerman.id.au --- drivers/of/base.c | 21 +++++++++++++++++++++ include/linux/of.h | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index b0ad8fc06e80..3c85afb2697c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -394,6 +394,27 @@ int of_device_compatible_match(const struct device_node *device, } EXPORT_SYMBOL_GPL(of_device_compatible_match); +/** + * of_machine_compatible_match - Test root of device tree against a compatible array + * @compats: NULL terminated array of compatible strings to look for in root node's compatible property. + * + * Returns true if the root node has any of the given compatible values in its + * compatible property. + */ +bool of_machine_compatible_match(const char *const *compats) +{ + struct device_node *root; + int rc = 0; + + root = of_find_node_by_path("/"); + if (root) { + rc = of_device_compatible_match(root, compats); + of_node_put(root); + } + + return rc != 0; +} + /** * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. diff --git a/include/linux/of.h b/include/linux/of.h index 6a9ddf20e79a..e3418babc203 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -403,6 +403,7 @@ extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_highest_id(const char *stem); extern int of_machine_is_compatible(const char *compat); +bool of_machine_compatible_match(const char *const *compats); extern int of_add_property(struct device_node *np, struct property *prop); extern int of_remove_property(struct device_node *np, struct property *prop); @@ -808,6 +809,11 @@ static inline int of_remove_property(struct device_node *np, struct property *pr return 0; } +static inline bool of_machine_compatible_match(const char *const *compats) +{ + return false; +} + static inline bool of_console_check(const struct device_node *dn, const char *name, int index) { return false; From cefdb366dcbe97908b6055595a15bf7689556bf8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Dec 2023 21:31:49 +1100 Subject: [PATCH 616/814] of: Change of_machine_is_compatible() to return bool of_machine_is_compatible() currently returns a positive integer if it finds a match. However none of the callers ever check the value, they all treat it as a true/false. So change of_machine_is_compatible() to return bool, which will allow the implementation to be changed in a subsequent patch. Suggested-by: Rob Herring Signed-off-by: Michael Ellerman Link: https://msgid.link/20231214103152.12269-2-mpe@ellerman.id.au --- drivers/of/base.c | 5 ++--- include/linux/of.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 3c85afb2697c..faa88eb518a9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -419,10 +419,9 @@ bool of_machine_compatible_match(const char *const *compats) * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. * - * Return: A positive integer if the root node has the given value in its - * compatible property. + * Return: true if the root node has the given value in its compatible property. */ -int of_machine_is_compatible(const char *compat) +bool of_machine_is_compatible(const char *compat) { struct device_node *root; int rc = 0; diff --git a/include/linux/of.h b/include/linux/of.h index e3418babc203..c5c663a7fb77 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -402,7 +402,7 @@ extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)); extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_highest_id(const char *stem); -extern int of_machine_is_compatible(const char *compat); +extern bool of_machine_is_compatible(const char *compat); bool of_machine_compatible_match(const char *const *compats); extern int of_add_property(struct device_node *np, struct property *prop); From 1ac8205f907517a306b661212496fedce79d7cc5 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 14 Dec 2023 21:31:50 +1100 Subject: [PATCH 617/814] of: Reimplement of_machine_is_compatible() using of_machine_compatible_match() of_machine_compatible_match() works with a table of strings. of_machine_is_compatible() is a simplier version with only one string. Re-implement of_machine_is_compatible() by setting a table of strings with a single string then using of_machine_compatible_match(). Suggested-by: Rob Herring Signed-off-by: Christophe Leroy Reviewed-by: Rob Herring Signed-off-by: Michael Ellerman Link: https://msgid.link/20231214103152.12269-3-mpe@ellerman.id.au --- drivers/of/base.c | 21 +-------------------- include/linux/of.h | 14 +++++++++++++- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index faa88eb518a9..df8d9733b054 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -414,26 +414,7 @@ bool of_machine_compatible_match(const char *const *compats) return rc != 0; } - -/** - * of_machine_is_compatible - Test root of device tree for a given compatible value - * @compat: compatible string to look for in root node's compatible property. - * - * Return: true if the root node has the given value in its compatible property. - */ -bool of_machine_is_compatible(const char *compat) -{ - struct device_node *root; - int rc = 0; - - root = of_find_node_by_path("/"); - if (root) { - rc = of_device_is_compatible(root, compat); - of_node_put(root); - } - return rc; -} -EXPORT_SYMBOL(of_machine_is_compatible); +EXPORT_SYMBOL(of_machine_compatible_match); /** * __of_device_is_available - check if a device is available for use diff --git a/include/linux/of.h b/include/linux/of.h index c5c663a7fb77..03ed4e37ca57 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -402,9 +402,21 @@ extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)); extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_highest_id(const char *stem); -extern bool of_machine_is_compatible(const char *compat); bool of_machine_compatible_match(const char *const *compats); +/** + * of_machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node's compatible property. + * + * Return: true if the root node has the given value in its compatible property. + */ +static inline bool of_machine_is_compatible(const char *compat) +{ + const char *compats[] = { compat, NULL }; + + return of_machine_compatible_match(compats); +} + extern int of_add_property(struct device_node *np, struct property *prop); extern int of_remove_property(struct device_node *np, struct property *prop); extern int of_update_property(struct device_node *np, struct property *newprop); From 28da734d58c8d0113d0ac4f59880d94c9f249564 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 14 Dec 2023 21:31:51 +1100 Subject: [PATCH 618/814] powerpc/machdep: Define 'compatibles' property in ppc_md and use it Most probe functions that do not use the 'compatible' string do nothing else than checking whether the machine is compatible with one of the strings in a NULL terminated table of strings. Define that table of strings in ppc_md structure and check it directly from probe_machine() instead of using ppc_md.probe() for that. Keep checking in ppc_md.probe() only for more complex probing. All .compatible could be replaced with a single element NULL terminated list but that's not worth the churn. Can be do incrementaly in follow-up patches. Signed-off-by: Christophe Leroy Reviewed-by: Rob Herring Signed-off-by: Michael Ellerman Link: https://msgid.link/20231214103152.12269-4-mpe@ellerman.id.au --- arch/powerpc/include/asm/machdep.h | 1 + arch/powerpc/kernel/setup-common.c | 2 ++ arch/powerpc/platforms/40x/ppc40x_simple.c | 9 +++------ arch/powerpc/platforms/512x/mpc512x_generic.c | 4 +--- arch/powerpc/platforms/52xx/lite5200.c | 10 +--------- arch/powerpc/platforms/52xx/mpc5200_simple.c | 10 +--------- arch/powerpc/platforms/83xx/mpc830x_rdb.c | 10 +--------- arch/powerpc/platforms/83xx/mpc831x_rdb.c | 10 +--------- arch/powerpc/platforms/83xx/mpc837x_rdb.c | 10 +--------- arch/powerpc/platforms/85xx/corenet_generic.c | 2 +- arch/powerpc/platforms/85xx/tqm85xx.c | 10 +--------- 11 files changed, 14 insertions(+), 64 deletions(-) diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index d31a5ec1550d..1862f94335ee 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -22,6 +22,7 @@ struct pci_host_bridge; struct machdep_calls { const char *name; const char *compatible; + const char * const *compatibles; #ifdef CONFIG_PPC64 #ifdef CONFIG_PM void (*iommu_restore)(void); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 6fe68aa93268..0c41098bdc35 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -640,6 +640,8 @@ static __init void probe_machine(void) DBG(" %s ...\n", machine_id->name); if (machine_id->compatible && !of_machine_is_compatible(machine_id->compatible)) continue; + if (machine_id->compatibles && !of_machine_compatible_match(machine_id->compatibles)) + continue; memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls)); if (ppc_md.probe && !ppc_md.probe()) continue; diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index e454e9d2eff1..294ab2728588 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -59,16 +59,13 @@ static const char * const board[] __initconst = { static int __init ppc40x_probe(void) { - if (of_device_compatible_match(of_root, board)) { - pci_set_flags(PCI_REASSIGN_ALL_RSRC); - return 1; - } - - return 0; + pci_set_flags(PCI_REASSIGN_ALL_RSRC); + return 1; } define_machine(ppc40x_simple) { .name = "PowerPC 40x Platform", + .compatibles = board, .probe = ppc40x_probe, .progress = udbg_progress, .init_IRQ = uic_init_tree, diff --git a/arch/powerpc/platforms/512x/mpc512x_generic.c b/arch/powerpc/platforms/512x/mpc512x_generic.c index 0d58ab257cd9..d4fa6c302ccf 100644 --- a/arch/powerpc/platforms/512x/mpc512x_generic.c +++ b/arch/powerpc/platforms/512x/mpc512x_generic.c @@ -32,9 +32,6 @@ static const char * const board[] __initconst = { */ static int __init mpc512x_generic_probe(void) { - if (!of_device_compatible_match(of_root, board)) - return 0; - mpc512x_init_early(); return 1; @@ -42,6 +39,7 @@ static int __init mpc512x_generic_probe(void) define_machine(mpc512x_generic) { .name = "MPC512x generic", + .compatibles = board, .probe = mpc512x_generic_probe, .init = mpc512x_init, .setup_arch = mpc512x_setup_arch, diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 0fd67b3ffc3e..0a161d82a3a8 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -172,17 +172,9 @@ static const char * const board[] __initconst = { NULL, }; -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init lite5200_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - define_machine(lite5200) { .name = "lite5200", - .probe = lite5200_probe, + .compatibles = board, .setup_arch = lite5200_setup_arch, .discover_phbs = mpc52xx_setup_pci, .init = mpc52xx_declare_of_platform_devices, diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index f1e85e86f5e5..7e0e4c34a40b 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -59,17 +59,9 @@ static const char *board[] __initdata = { NULL }; -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc5200_simple_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - define_machine(mpc5200_simple_platform) { .name = "mpc5200-simple-platform", - .probe = mpc5200_simple_probe, + .compatibles = board, .setup_arch = mpc5200_simple_setup_arch, .discover_phbs = mpc52xx_setup_pci, .init = mpc52xx_declare_of_platform_devices, diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index 534bb227480d..63b6d213726a 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -34,19 +34,11 @@ static const char *board[] __initdata = { NULL }; -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc830x_rdb_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - machine_device_initcall(mpc830x_rdb, mpc83xx_declare_of_platform_devices); define_machine(mpc830x_rdb) { .name = "MPC830x RDB", - .probe = mpc830x_rdb_probe, + .compatibles = board, .setup_arch = mpc830x_rdb_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index 7b901ab3b864..5c39966762e4 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -34,19 +34,11 @@ static const char *board[] __initdata = { NULL }; -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc831x_rdb_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - machine_device_initcall(mpc831x_rdb, mpc83xx_declare_of_platform_devices); define_machine(mpc831x_rdb) { .name = "MPC831x RDB", - .probe = mpc831x_rdb_probe, + .compatibles = board, .setup_arch = mpc831x_rdb_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 39e78018dd0b..45823e147933 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -61,17 +61,9 @@ static const char * const board[] __initconst = { NULL }; -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc837x_rdb_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - define_machine(mpc837x_rdb) { .name = "MPC837x RDB/WLAN", - .probe = mpc837x_rdb_probe, + .compatibles = board, .setup_arch = mpc837x_rdb_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index 645fcca77cde..c44400e95f55 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -149,7 +149,7 @@ static int __init corenet_generic_probe(void) extern struct smp_ops_t smp_85xx_ops; #endif - if (of_device_compatible_match(of_root, boards)) + if (of_machine_compatible_match(boards)) return 1; /* Check if we're running under the Freescale hypervisor */ diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 6be1b9809db6..f74d446c53f0 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -112,17 +112,9 @@ static const char * const board[] __initconst = { NULL }; -/* - * Called very early, device-tree isn't unflattened - */ -static int __init tqm85xx_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - define_machine(tqm85xx) { .name = "TQM85xx", - .probe = tqm85xx_probe, + .compatibles = board, .setup_arch = tqm85xx_setup_arch, .init_IRQ = tqm85xx_pic_init, .show_cpuinfo = tqm85xx_show_cpuinfo, From 2a066ae11861257223500d7515e1541199cb7832 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 14 Dec 2023 21:31:52 +1100 Subject: [PATCH 619/814] powerpc: Stop using of_root Replace all usages of of_root by of_find_node_by_path("/") Signed-off-by: Christophe Leroy Reviewed-by: Rob Herring Signed-off-by: Michael Ellerman Link: https://msgid.link/20231214103152.12269-5-mpe@ellerman.id.au --- arch/powerpc/kernel/secure_boot.c | 8 ++++++-- arch/powerpc/kexec/ranges.c | 8 +++++--- arch/powerpc/mm/drmem.c | 10 +++++----- arch/powerpc/mm/numa.c | 6 ++++-- arch/powerpc/platforms/52xx/efika.c | 4 +++- arch/powerpc/platforms/pasemi/pci.c | 4 +++- arch/powerpc/platforms/pseries/lparcfg.c | 6 +++++- arch/powerpc/platforms/pseries/setup.c | 12 +++++++++--- 8 files changed, 40 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kernel/secure_boot.c b/arch/powerpc/kernel/secure_boot.c index f9af305d9579..9e0efb657f39 100644 --- a/arch/powerpc/kernel/secure_boot.c +++ b/arch/powerpc/kernel/secure_boot.c @@ -32,8 +32,10 @@ bool is_ppc_secureboot_enabled(void) if (enabled) goto out; - if (!of_property_read_u32(of_root, "ibm,secure-boot", &secureboot)) + node = of_find_node_by_path("/"); + if (!of_property_read_u32(node, "ibm,secure-boot", &secureboot)) enabled = (secureboot > 1); + of_node_put(node); out: pr_info("Secure boot mode %s\n", enabled ? "enabled" : "disabled"); @@ -54,8 +56,10 @@ bool is_ppc_trustedboot_enabled(void) if (enabled) goto out; - if (!of_property_read_u32(of_root, "ibm,trusted-boot", &trustedboot)) + node = of_find_node_by_path("/"); + if (!of_property_read_u32(node, "ibm,trusted-boot", &trustedboot)) enabled = (trustedboot > 0); + of_node_put(node); out: pr_info("Trusted boot mode %s\n", enabled ? "enabled" : "disabled"); diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c index fb3e12f15214..33b780049aaf 100644 --- a/arch/powerpc/kexec/ranges.c +++ b/arch/powerpc/kexec/ranges.c @@ -385,14 +385,16 @@ int add_opal_mem_range(struct crash_mem **mem_ranges) int add_reserved_mem_ranges(struct crash_mem **mem_ranges) { int n_mem_addr_cells, n_mem_size_cells, i, len, cells, ret = 0; + struct device_node *root = of_find_node_by_path("/"); const __be32 *prop; - prop = of_get_property(of_root, "reserved-ranges", &len); + prop = of_get_property(root, "reserved-ranges", &len); + n_mem_addr_cells = of_n_addr_cells(root); + n_mem_size_cells = of_n_size_cells(root); + of_node_put(root); if (!prop) return 0; - n_mem_addr_cells = of_n_addr_cells(of_root); - n_mem_size_cells = of_n_size_cells(of_root); cells = n_mem_addr_cells + n_mem_size_cells; /* Each reserved range is an (address,size) pair */ diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c index fde7790277f7..c110ab8fa8a3 100644 --- a/arch/powerpc/mm/drmem.c +++ b/arch/powerpc/mm/drmem.c @@ -393,17 +393,17 @@ static const __be32 *of_get_usable_memory(struct device_node *dn) int walk_drmem_lmbs(struct device_node *dn, void *data, int (*func)(struct drmem_lmb *, const __be32 **, void *)) { + struct device_node *root = of_find_node_by_path("/"); const __be32 *prop, *usm; int ret = -ENODEV; - if (!of_root) + if (!root) return ret; /* Get the address & size cells */ - of_node_get(of_root); - n_root_addr_cells = of_n_addr_cells(of_root); - n_root_size_cells = of_n_size_cells(of_root); - of_node_put(of_root); + n_root_addr_cells = of_n_addr_cells(root); + n_root_size_cells = of_n_size_cells(root); + of_node_put(root); if (init_drmem_lmb_size(dn)) return ret; diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index f6c4ace3b221..a490724e84ad 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1111,7 +1111,7 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) static void __init find_possible_nodes(void) { - struct device_node *rtas; + struct device_node *rtas, *root; const __be32 *domains = NULL; int prop_length, max_nodes; u32 i; @@ -1132,10 +1132,12 @@ static void __init find_possible_nodes(void) * If the LPAR is migratable, new nodes might be activated after a LPM, * so we should consider the max number in that case. */ - if (!of_get_property(of_root, "ibm,migratable-partition", NULL)) + root = of_find_node_by_path("/"); + if (!of_get_property(root, "ibm,migratable-partition", NULL)) domains = of_get_property(rtas, "ibm,current-associativity-domains", &prop_length); + of_node_put(root); if (!domains) { domains = of_get_property(rtas, "ibm,max-associativity-domains", &prop_length); diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index aa82e6b437f3..37a67120f257 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -195,8 +195,10 @@ static void __init efika_setup_arch(void) static int __init efika_probe(void) { - const char *model = of_get_property(of_root, "model", NULL); + struct device_node *root = of_find_node_by_path("/"); + const char *model = of_get_property(root, "model", NULL); + of_node_put(root); if (model == NULL) return 0; if (strcmp(model, "EFIKA5K2")) diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index f27d31414737..60f990a336c4 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -270,16 +270,18 @@ static int __init pas_add_bridge(struct device_node *dev) void __init pas_pci_init(void) { + struct device_node *root = of_find_node_by_path("/"); struct device_node *np; int res; pci_set_flags(PCI_SCAN_ALL_PCIE_DEVS); - np = of_find_compatible_node(of_root, NULL, "pasemi,rootbus"); + np = of_find_compatible_node(root, NULL, "pasemi,rootbus"); if (np) { res = pas_add_bridge(np); of_node_put(np); } + of_node_put(root); } void __iomem *__init pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index 1c151d77e74b..f73c4d1c26af 100644 --- a/arch/powerpc/platforms/pseries/lparcfg.c +++ b/arch/powerpc/platforms/pseries/lparcfg.c @@ -346,9 +346,13 @@ static int read_rtas_lpar_name(struct seq_file *m) */ static int read_dt_lpar_name(struct seq_file *m) { + struct device_node *root = of_find_node_by_path("/"); const char *name; + int ret; - if (of_property_read_string(of_root, "ibm,partition-name", &name)) + ret = of_property_read_string(root, "ibm,partition-name", &name); + of_node_put(root); + if (ret) return -ENOENT; seq_printf(m, "partition_name=%s\n", name); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ecea85c74c43..284a6fa04b0c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -1029,9 +1029,11 @@ static void __init pseries_add_hw_description(void) return; } - if (of_property_read_bool(of_root, "ibm,powervm-partition") || - of_property_read_bool(of_root, "ibm,fw-net-version")) + dn = of_find_node_by_path("/"); + if (of_property_read_bool(dn, "ibm,powervm-partition") || + of_property_read_bool(dn, "ibm,fw-net-version")) seq_buf_printf(&ppc_hw_desc, "hv:phyp "); + of_node_put(dn); } /* @@ -1091,7 +1093,11 @@ static void pseries_power_off(void) static int __init pSeries_probe(void) { - if (!of_node_is_type(of_root, "chrp")) + struct device_node *root = of_find_node_by_path("/"); + bool ret = of_node_is_type(root, "chrp"); + + of_node_put(root); + if (!ret) return 0; /* Cell blades firmware claims to be chrp while it's not. Until this From 4eb20bf34ea296f648971a8528e32cd80efcbe89 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 30 Nov 2023 23:50:45 +1100 Subject: [PATCH 620/814] powerpc/irq: Allow softirq to hardirq stack transition Allow a transition from the softirq stack to the hardirq stack when handling a hardirq. Doing so means a hardirq received while deep in softirq processing is less likely to cause a stack overflow of the softirq stack. Previously it wasn't safe to do so because irq_exit() (which initiates softirq processing) was called on the hardirq stack. That was changed in commit 1b1b6a6f4cc0 ("powerpc: handle irq_enter/ irq_exit in interrupt handler wrappers") and 1346d00e1bdf ("powerpc: Don't select HAVE_IRQ_EXIT_ON_IRQ_STACK"). The allowed transitions are now: - process stack -> hardirq stack - process stack -> softirq stack - process stack -> softirq stack -> hardirq stack Reviewed-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/20231130125045.3080961-1-mpe@ellerman.id.au --- arch/powerpc/kernel/irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 6f7d4edaa0bc..7504ceec5c58 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -284,15 +284,14 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) void __do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - void *cursp, *irqsp, *sirqsp; + void *cursp, *irqsp; /* Switch to the irq stack to handle this */ cursp = (void *)(current_stack_pointer & ~(THREAD_SIZE - 1)); irqsp = hardirq_ctx[raw_smp_processor_id()]; - sirqsp = softirq_ctx[raw_smp_processor_id()]; /* Already there ? If not switch stack and call */ - if (unlikely(cursp == irqsp || cursp == sirqsp)) + if (unlikely(cursp == irqsp)) __do_irq(regs, current_stack_pointer); else call_do_irq(regs, irqsp); From ad86d7ee43b22aa2ed60fb982ae94b285c1be671 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Thu, 29 Feb 2024 17:58:47 +0530 Subject: [PATCH 621/814] powerpc/hv-gpci: Fix the H_GET_PERF_COUNTER_INFO hcall return value checks Running event hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ in one of the system throws below error: ---Logs--- # perf list | grep hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=?/[Kernel PMU event] # perf stat -v -e hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ sleep 2 Using CPUID 00800200 Control descriptor is not initialized Warning: hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ event is not supported by the kernel. failed to read counter hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ Performance counter stats for 'system wide': hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ 2.000700771 seconds time elapsed The above error is because of the hcall failure as required permission "Enable Performance Information Collection" is not set. Based on current code, single_gpci_request function did not check the error type incase hcall fails and by default returns EINVAL. But we can have other reasons for hcall failures like H_AUTHORITY/H_PARAMETER with detail_rc as GEN_BUF_TOO_SMALL, for which we need to act accordingly. Fix this issue by adding new checks in the single_gpci_request and h_gpci_event_init functions. Result after fix patch changes: # perf stat -e hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ sleep 2 Error: No permission to enable hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ event. Fixes: 220a0c609ad1 ("powerpc/perf: Add support for the hv gpci (get performance counter info) interface") Reported-by: Akanksha J N Signed-off-by: Kajol Jain Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122847.101162-1-kjain@linux.ibm.com --- arch/powerpc/perf/hv-gpci.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c index 27f18119fda1..241551d1282f 100644 --- a/arch/powerpc/perf/hv-gpci.c +++ b/arch/powerpc/perf/hv-gpci.c @@ -695,6 +695,20 @@ static unsigned long single_gpci_request(u32 req, u32 starting_index, ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE); + + /* + * ret value as 'H_PARAMETER' with detail_rc as 'GEN_BUF_TOO_SMALL', + * specifies that the current buffer size cannot accommodate + * all the information and a partial buffer returned. + * Since in this function we are only accessing data for a given starting index, + * we don't need to accommodate whole data and can get required count by + * accessing first entry data. + * Hence hcall fails only incase the ret value is other than H_SUCCESS or + * H_PARAMETER with detail_rc value as GEN_BUF_TOO_SMALL(0x1B). + */ + if (ret == H_PARAMETER && be32_to_cpu(arg->params.detail_rc) == 0x1B) + ret = 0; + if (ret) { pr_devel("hcall failed: 0x%lx\n", ret); goto out; @@ -759,6 +773,7 @@ static int h_gpci_event_init(struct perf_event *event) { u64 count; u8 length; + unsigned long ret; /* Not our event */ if (event->attr.type != event->pmu->type) @@ -789,13 +804,23 @@ static int h_gpci_event_init(struct perf_event *event) } /* check if the request works... */ - if (single_gpci_request(event_get_request(event), + ret = single_gpci_request(event_get_request(event), event_get_starting_index(event), event_get_secondary_index(event), event_get_counter_info_version(event), event_get_offset(event), length, - &count)) { + &count); + + /* + * ret value as H_AUTHORITY implies that partition is not permitted to retrieve + * performance information, and required to set + * "Enable Performance Information Collection" option. + */ + if (ret == H_AUTHORITY) + return -EPERM; + + if (ret) { pr_devel("gpci hcall failed\n"); return -EINVAL; } From d9cf600ecb7b053345aa76c1988cf374260cfdaf Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Fri, 1 Mar 2024 16:58:34 +0800 Subject: [PATCH 622/814] powerpc/mm: Code cleanup for __hash_page_thp This part was commented from commit 6d492ecc6489 ("powerpc/THP: Add code to handle HPTE faults for hugepages") in about 11 years before. If there are no plans to enable this part code in the future, we can remove this dead code and replace with a comment explaining what the dead code was trying to say. Signed-off-by: Kunwu Chan Suggested-by: Michael Ellerman Suggested-by: "Aneesh Kumar K.V" Signed-off-by: Michael Ellerman Link: https://msgid.link/20240301085834.1512921-1-chentao@kylinos.cn --- arch/powerpc/mm/book3s64/hash_hugepage.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/mm/book3s64/hash_hugepage.c b/arch/powerpc/mm/book3s64/hash_hugepage.c index c0fabe6c5a12..15d6f3ea7178 100644 --- a/arch/powerpc/mm/book3s64/hash_hugepage.c +++ b/arch/powerpc/mm/book3s64/hash_hugepage.c @@ -59,16 +59,13 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, rflags = htab_convert_pte_flags(new_pmd, flags); -#if 0 - if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) { + /* + * THPs are only supported on platforms that can do mixed page size + * segments (MPSS) and all such platforms have coherent icache. Hence we + * don't need to do lazy icache flush (hash_page_do_lazy_icache()) on + * noexecute fault. + */ - /* - * No CPU has hugepages but lacks no execute, so we - * don't need to worry about that case - */ - rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap); - } -#endif /* * Find the slot index details for this ea, using base page size. */ From 8488cdcb00fd5f238754005a43a3a7445860d344 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 23:25:17 +1100 Subject: [PATCH 623/814] powerpc/64s: Move dcbt/dcbtst sequence into a macro There's an almost identical code sequence to specify load/store access hints in __copy_tofrom_user_power7(), copypage_power7() and memcpy_power7(). Move the sequence into a common macro, which is passed the registers to use as they differ slightly. There also needs to be a copy in the selftests, it could be shared in future if the headers are cleaned up / refactored. Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122521.762431-1-mpe@ellerman.id.au --- arch/powerpc/include/asm/ppc_asm.h | 12 ++++++++++++ arch/powerpc/lib/copypage_power7.S | 12 +----------- arch/powerpc/lib/copyuser_power7.S | 12 +----------- arch/powerpc/lib/memcpy_power7.S | 10 +--------- .../selftests/powerpc/copyloops/asm/ppc_asm.h | 12 ++++++++++++ 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 041ee2595520..78c7548eac1e 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -510,6 +510,18 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) lis scratch,0x60000000@h; \ dcbt 0,scratch,0b01010 +#define DCBT_SETUP_STREAMS(from, from_parms, to, to_parms, scratch) \ + lis scratch,0x8000; /* GO=1 */ \ + clrldi scratch,scratch,32; \ + /* setup read stream 0 */ \ + dcbt 0,from,0b01000; /* addr from */ \ + dcbt 0,from_parms,0b01010; /* length and depth from */ \ + /* setup write stream 1 */ \ + dcbtst 0,to,0b01000; /* addr to */ \ + dcbtst 0,to_parms,0b01010; /* length and depth to */ \ + eieio; \ + dcbt 0,scratch,0b01010; /* all streams GO */ + /* * toreal/fromreal/tophys/tovirt macros. 32-bit BookE makes them * keep the address intact to be compatible with code shared with diff --git a/arch/powerpc/lib/copypage_power7.S b/arch/powerpc/lib/copypage_power7.S index a783973f1215..07e7cec4d135 100644 --- a/arch/powerpc/lib/copypage_power7.S +++ b/arch/powerpc/lib/copypage_power7.S @@ -27,17 +27,7 @@ _GLOBAL(copypage_power7) #endif ori r10,r7,1 /* stream=1 */ - lis r8,0x8000 /* GO=1 */ - clrldi r8,r8,32 - - /* setup read stream 0 */ - dcbt 0,r4,0b01000 /* addr from */ - dcbt 0,r7,0b01010 /* length and depth from */ - /* setup write stream 1 */ - dcbtst 0,r9,0b01000 /* addr to */ - dcbtst 0,r10,0b01010 /* length and depth to */ - eieio - dcbt 0,r8,0b01010 /* all streams GO */ + DCBT_SETUP_STREAMS(r4, r7, r9, r10, r8) #ifdef CONFIG_ALTIVEC mflr r0 diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S index ac41053c3a5a..8474c682a178 100644 --- a/arch/powerpc/lib/copyuser_power7.S +++ b/arch/powerpc/lib/copyuser_power7.S @@ -298,17 +298,7 @@ err1; stb r0,0(r3) or r7,r7,r0 ori r10,r7,1 /* stream=1 */ - lis r8,0x8000 /* GO=1 */ - clrldi r8,r8,32 - - /* setup read stream 0 */ - dcbt 0,r6,0b01000 /* addr from */ - dcbt 0,r7,0b01010 /* length and depth from */ - /* setup write stream 1 */ - dcbtst 0,r9,0b01000 /* addr to */ - dcbtst 0,r10,0b01010 /* length and depth to */ - eieio - dcbt 0,r8,0b01010 /* all streams GO */ + DCBT_SETUP_STREAMS(r6, r7, r9, r10, r8) beq cr1,.Lunwind_stack_nonvmx_copy diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index 9398b2b746c4..b7c5e7fca8b9 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -244,15 +244,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) or r7,r7,r0 ori r10,r7,1 /* stream=1 */ - lis r8,0x8000 /* GO=1 */ - clrldi r8,r8,32 - - dcbt 0,r6,0b01000 - dcbt 0,r7,0b01010 - dcbtst 0,r9,0b01000 - dcbtst 0,r10,0b01010 - eieio - dcbt 0,r8,0b01010 /* GO */ + DCBT_SETUP_STREAMS(r6, r7, r9, r10, r8) beq cr1,.Lunwind_stack_nonvmx_copy diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index a89f1fbf86ec..1d293ab77185 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -47,4 +47,16 @@ /* Default to taking the first of any alternative feature sections */ test_feature = 1 +#define DCBT_SETUP_STREAMS(from, from_parms, to, to_parms, scratch) \ + lis scratch,0x8000; /* GO=1 */ \ + clrldi scratch,scratch,32; \ + /* setup read stream 0 */ \ + dcbt 0,from,0b01000; /* addr from */ \ + dcbt 0,from_parms,0b01010; /* length and depth from */ \ + /* setup write stream 1 */ \ + dcbtst 0,to,0b01000; /* addr to */ \ + dcbtst 0,to_parms,0b01010; /* length and depth to */ \ + eieio; \ + dcbt 0,scratch,0b01010; /* all streams GO */ + #endif /* __SELFTESTS_POWERPC_PPC_ASM_H */ From 4e284e38ed586edeb8bdb2b0c544273a7f72021c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 23:25:18 +1100 Subject: [PATCH 624/814] powerpc/64s: Use .machine power4 around dcbt There are multiple decodings for the "dcbt" mnemonic, so the assembler has to pick one. That requires passing -many to the assembler, which is not recommended. Without -many the clang 14 / binutils 2.38 build fails with: arch/powerpc/kernel/exceptions-64s.S:2976: Error: junk at end of line: `0b01010' clang: error: assembler command failed with exit code 1 (use -v to see invocation) Fix it by adding .machine directives around the use of dcbt to specify which encoding is desired. Acked-by: Segher Boessenkool Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122521.762431-2-mpe@ellerman.id.au --- arch/powerpc/include/asm/ppc_asm.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 78c7548eac1e..1d1018c1e482 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -508,11 +508,16 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) */ #define DCBT_BOOK3S_STOP_ALL_STREAM_IDS(scratch) \ lis scratch,0x60000000@h; \ - dcbt 0,scratch,0b01010 + .machine push; \ + .machine power4; \ + dcbt 0,scratch,0b01010; \ + .machine pop; #define DCBT_SETUP_STREAMS(from, from_parms, to, to_parms, scratch) \ lis scratch,0x8000; /* GO=1 */ \ clrldi scratch,scratch,32; \ + .machine push; \ + .machine power4; \ /* setup read stream 0 */ \ dcbt 0,from,0b01000; /* addr from */ \ dcbt 0,from_parms,0b01010; /* length and depth from */ \ @@ -520,7 +525,8 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) dcbtst 0,to,0b01000; /* addr to */ \ dcbtst 0,to_parms,0b01010; /* length and depth to */ \ eieio; \ - dcbt 0,scratch,0b01010; /* all streams GO */ + dcbt 0,scratch,0b01010; /* all streams GO */ \ + .machine pop; /* * toreal/fromreal/tophys/tovirt macros. 32-bit BookE makes them From 5f491356b7149564ab22323ccce79c8d595bfd0c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 23:25:19 +1100 Subject: [PATCH 625/814] powerpc/fsl: Fix mfpmr build errors with newer binutils Binutils 2.38 complains about the use of mfpmr when building ppc6xx_defconfig: CC arch/powerpc/kernel/pmc.o {standard input}: Assembler messages: {standard input}:45: Error: unrecognized opcode: `mfpmr' {standard input}:56: Error: unrecognized opcode: `mtpmr' This is because by default the kernel is built with -mcpu=powerpc, and the mt/mfpmr instructions are not defined. It can be avoided by enabling CONFIG_E300C3_CPU, but just adding that to the defconfig will leave open the possibility of randconfig failures. So add machine directives around the mt/mfpmr instructions to tell binutils how to assemble them. Cc: stable@vger.kernel.org Reported-by: Jan-Benedict Glaw Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122521.762431-3-mpe@ellerman.id.au --- arch/powerpc/include/asm/reg_fsl_emb.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h index a21f529c43d9..8359c06d92d9 100644 --- a/arch/powerpc/include/asm/reg_fsl_emb.h +++ b/arch/powerpc/include/asm/reg_fsl_emb.h @@ -12,9 +12,16 @@ #ifndef __ASSEMBLY__ /* Performance Monitor Registers */ #define mfpmr(rn) ({unsigned int rval; \ - asm volatile("mfpmr %0," __stringify(rn) \ + asm volatile(".machine push; " \ + ".machine e300; " \ + "mfpmr %0," __stringify(rn) ";" \ + ".machine pop; " \ : "=r" (rval)); rval;}) -#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v)) +#define mtpmr(rn, v) asm volatile(".machine push; " \ + ".machine e300; " \ + "mtpmr " __stringify(rn) ",%0; " \ + ".machine pop; " \ + : : "r" (v)) #endif /* __ASSEMBLY__ */ /* Freescale Book E Performance Monitor APU Registers */ From f01dbd73ccf122486ad4b52e74f5505985dd6af4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 29 Feb 2024 23:25:20 +1100 Subject: [PATCH 626/814] powerpc/fsl: Modernise mt/mfpmr With the addition of the machine directives, these are no longer simple 1-2 liner macros. So modernise them to be static inlines and use named asm parameters. Acked-by: Segher Boessenkool Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122521.762431-4-mpe@ellerman.id.au --- arch/powerpc/include/asm/reg_fsl_emb.h | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h index 8359c06d92d9..b0563c30b062 100644 --- a/arch/powerpc/include/asm/reg_fsl_emb.h +++ b/arch/powerpc/include/asm/reg_fsl_emb.h @@ -11,17 +11,27 @@ #ifndef __ASSEMBLY__ /* Performance Monitor Registers */ -#define mfpmr(rn) ({unsigned int rval; \ - asm volatile(".machine push; " \ - ".machine e300; " \ - "mfpmr %0," __stringify(rn) ";" \ - ".machine pop; " \ - : "=r" (rval)); rval;}) -#define mtpmr(rn, v) asm volatile(".machine push; " \ - ".machine e300; " \ - "mtpmr " __stringify(rn) ",%0; " \ - ".machine pop; " \ - : : "r" (v)) +static inline unsigned int mfpmr(unsigned int rn) +{ + unsigned int rval; + + asm (".machine push; " + ".machine e300; " + "mfpmr %[rval], %[rn];" + ".machine pop;" + : [rval] "=r" (rval) : [rn] "i" (rn)); + + return rval; +} + +static inline void mtpmr(unsigned int rn, unsigned int val) +{ + asm (".machine push; " + ".machine e300; " + "mtpmr %[rn], %[val];" + ".machine pop;" + : [val] "=r" (val) : [rn] "i" (rn)); +} #endif /* __ASSEMBLY__ */ /* Freescale Book E Performance Monitor APU Registers */ From ca3d3aa14e7673f1b15e862b71998a4664d50ebe Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 29 Feb 2024 23:25:21 +1100 Subject: [PATCH 627/814] powerpc: Remove cpu-as-y completely cpu-as-y is there to force assembler building options. But there is no need for that. GCC is passed the necessary options and it automatically pass the appropriate option to GAS. GCC is given -maltivec when relevant, so no need for -Wa,-maltivec either. And -Wa,-many is wrong as it will hide innapropriate instructions. Better to detect them and handle them on a case by case basis. The setting of -Wa,-many was added by commit 960e30029863 ("powerpc/Makefile: Fix PPC_BOOK3S_64 ASFLAGS") in order to fix an issue with clang and the passed -Wa,-mpower4 option. But we have now removed it expecting the compiler to automatically pass the proper options and instructions based on -mcpu=power4. Signed-off-by: Christophe Leroy Acked-by: Segher Boessenkool Signed-off-by: Michael Ellerman Link: https://msgid.link/20240229122521.762431-5-mpe@ellerman.id.au --- arch/powerpc/Makefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 4b8c9ff79d0f..4bd3a1bd02fc 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -219,18 +219,6 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables # often slow when they are implemented at all KBUILD_CFLAGS += $(call cc-option,-mno-string) -cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) - -# When using '-many -mpower4' gas will first try and find a matching power4 -# mnemonic and failing that it will allow any valid mnemonic that GAS knows -# about. GCC will pass -many to GAS when assembling, clang does not. -# LLVM IAS doesn't understand either flag: https://github.com/ClangBuiltLinux/linux/issues/675 -# but LLVM IAS only supports ISA >= 2.06 for Book3S 64 anyway... -cpu-as-$(CONFIG_PPC_BOOK3S_64) += $(call as-option,-Wa$(comma)-mpower4) $(call as-option,-Wa$(comma)-many) - -KBUILD_AFLAGS += $(cpu-as-y) -KBUILD_CFLAGS += $(cpu-as-y) - KBUILD_AFLAGS += $(aflags-y) KBUILD_CFLAGS += $(cflags-y) From b568b1504d04491d77de463d14212f5941cff825 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 11 Jan 2024 22:38:25 +0100 Subject: [PATCH 628/814] watchdog: core: Remove usage of the deprecated ida_simple_xx() API ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove(). Note that the upper limit of ida_simple_get() is exclusive, but the one of ida_alloc_range()/ida_alloc_max() is inclusive. So a -1 has been added when needed. Signed-off-by: Christophe JAILLET Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/bc5b82db59ccac69f2612ba104e2f5100401a862.1705009009.git.christophe.jaillet@wanadoo.fr Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 5b55ccae06d4..aff2c3912ead 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -260,12 +260,12 @@ static int __watchdog_register_device(struct watchdog_device *wdd) if (wdd->parent) { ret = of_alias_get_id(wdd->parent->of_node, "watchdog"); if (ret >= 0) - id = ida_simple_get(&watchdog_ida, ret, - ret + 1, GFP_KERNEL); + id = ida_alloc_range(&watchdog_ida, ret, ret, + GFP_KERNEL); } if (id < 0) - id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL); + id = ida_alloc_max(&watchdog_ida, MAX_DOGS - 1, GFP_KERNEL); if (id < 0) return id; @@ -273,19 +273,20 @@ static int __watchdog_register_device(struct watchdog_device *wdd) ret = watchdog_dev_register(wdd); if (ret) { - ida_simple_remove(&watchdog_ida, id); + ida_free(&watchdog_ida, id); if (!(id == 0 && ret == -EBUSY)) return ret; /* Retry in case a legacy watchdog module exists */ - id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL); + id = ida_alloc_range(&watchdog_ida, 1, MAX_DOGS - 1, + GFP_KERNEL); if (id < 0) return id; wdd->id = id; ret = watchdog_dev_register(wdd); if (ret) { - ida_simple_remove(&watchdog_ida, id); + ida_free(&watchdog_ida, id); return ret; } } @@ -309,7 +310,7 @@ static int __watchdog_register_device(struct watchdog_device *wdd) pr_err("watchdog%d: Cannot register reboot notifier (%d)\n", wdd->id, ret); watchdog_dev_unregister(wdd); - ida_simple_remove(&watchdog_ida, id); + ida_free(&watchdog_ida, id); return ret; } } @@ -382,7 +383,7 @@ static void __watchdog_unregister_device(struct watchdog_device *wdd) unregister_reboot_notifier(&wdd->reboot_nb); watchdog_dev_unregister(wdd); - ida_simple_remove(&watchdog_ida, wdd->id); + ida_free(&watchdog_ida, wdd->id); } /** From d2f656dc4969e765de2db8564c4c38d135d9152b Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 6 Feb 2024 17:38:57 +0800 Subject: [PATCH 629/814] watchdog: Add kernel-doc for wdt_set_timeout() The wdt_set_timeout function lacked a complete kernel-doc description. This patch adds missing parameter and return value descriptions in accordance with kernel-doc standards. Signed-off-by: Yang Li Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240206093857.62444-1-yang.lee@linux.alibaba.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/it87_wdt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index 9297a5891912..3e8c15138edd 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -213,12 +213,16 @@ static int wdt_stop(struct watchdog_device *wdd) /** * wdt_set_timeout - set a new timeout value with watchdog ioctl + * @wdd: pointer to the watchdog_device structure * @t: timeout value in seconds * * The hardware device has a 8 or 16 bit watchdog timer (depends on * chip version) that can be configured to count seconds or minutes. * * Used within WDIOC_SETTIMEOUT watchdog device ioctl. + * + * Return: 0 if the timeout was set successfully, or a negative error code on + * failure. */ static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) From 975e4b273ed2c801a0354a7cdd7d89e1fe1aa842 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Tue, 16 Jan 2024 13:52:43 +0530 Subject: [PATCH 630/814] watchdog: qcom: fine tune the max timeout value calculation To determine the max_timeout value, the below calculation is used. max_timeout = 0x10000000 / clk_rate cat /sys/devices/platform/soc@0/b017000.watchdog/watchdog/watchdog0/max_timeout 8388 However, this is not valid for all the platforms. IPQ SoCs starting from IPQ40xx and recent Snapdragron SoCs also has the bark and bite time field length of 20bits, which can hold max up to 32 seconds if the clk_rate is 32KHz. If the user tries to configure the timeout more than 32s, then the value will be truncated and the actual value will not be reflected in the HW. To avoid this, lets add a variable called max_tick_count in the device data, which defines max counter value of the WDT controller. Using this, max-timeout will be calculated in runtime for various WDT contorllers. With this change, we get the proper max_timeout as below and restricts the user from configuring the timeout higher than this. cat /sys/devices/platform/soc@0/b017000.watchdog/watchdog/watchdog0/max_timeout 32 Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240116-wdt-v2-1-501c7694c3f0@quicinc.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/qcom-wdt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 9e790f0c2096..006f9c61aa64 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -41,6 +41,7 @@ static const u32 reg_offset_data_kpss[] = { struct qcom_wdt_match_data { const u32 *offset; bool pretimeout; + u32 max_tick_count; }; struct qcom_wdt { @@ -177,11 +178,13 @@ static const struct watchdog_info qcom_wdt_pt_info = { static const struct qcom_wdt_match_data match_data_apcs_tmr = { .offset = reg_offset_data_apcs_tmr, .pretimeout = false, + .max_tick_count = 0x10000000U, }; static const struct qcom_wdt_match_data match_data_kpss = { .offset = reg_offset_data_kpss, .pretimeout = true, + .max_tick_count = 0xFFFFFU, }; static int qcom_wdt_probe(struct platform_device *pdev) @@ -236,7 +239,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) */ wdt->rate = clk_get_rate(clk); if (wdt->rate == 0 || - wdt->rate > 0x10000000U) { + wdt->rate > data->max_tick_count) { dev_err(dev, "invalid clock rate\n"); return -EINVAL; } @@ -260,7 +263,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.ops = &qcom_wdt_ops; wdt->wdd.min_timeout = 1; - wdt->wdd.max_timeout = 0x10000000U / wdt->rate; + wdt->wdd.max_timeout = data->max_tick_count / wdt->rate; wdt->wdd.parent = dev; wdt->layout = data->offset; From 8bc22a2f1bf0f402029087fcb53130233a544fed Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Fri, 19 Jan 2024 16:27:21 +0800 Subject: [PATCH 631/814] watchdog: starfive: Check pm_runtime_enabled() before decrementing usage counter In the probe function, pm_runtime_put_sync() will fail on platform with runtime PM disabled. Check if runtime PM is enabled before calling pm_runtime_put_sync() to fix it. Fixes: db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver") Signed-off-by: Xingyu Wu Signed-off-by: Ley Foon Tan Signed-off-by: Ji Sheng Teoh Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240119082722.1133024-1-jisheng.teoh@starfivetech.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/starfive-wdt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index e28ead24c520..df68ae4acbd7 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -494,8 +494,13 @@ static int starfive_wdt_probe(struct platform_device *pdev) if (ret) goto err_exit; - if (!early_enable) - pm_runtime_put_sync(&pdev->dev); + if (!early_enable) { + if (pm_runtime_enabled(&pdev->dev)) { + ret = pm_runtime_put_sync(&pdev->dev); + if (ret) + goto err_exit; + } + } return 0; From d869d6352a5c2b13e76c19ba8f7243f422cf3fd0 Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Tue, 30 Jan 2024 13:51:18 +0800 Subject: [PATCH 632/814] watchdog: starfive: check watchdog status before enabling in system resume System resume will start and enable watchdog regardless of whether the watchdog is enabled/disabled during a system suspend. Add a check to the watchdog status and only start and enable the watchdog if the watchdog status is running/active. Signed-off-by: Sia Jee Heng Signed-off-by: Ji Sheng Teoh Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240130055118.1917086-1-jisheng.teoh@starfivetech.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/starfive-wdt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index df68ae4acbd7..b4b059883618 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -559,7 +559,10 @@ static int starfive_wdt_resume(struct device *dev) starfive_wdt_set_reload_count(wdt, wdt->reload); starfive_wdt_lock(wdt); - return starfive_wdt_start(wdt); + if (watchdog_active(&wdt->wdd)) + return starfive_wdt_start(wdt); + + return 0; } static int starfive_wdt_runtime_suspend(struct device *dev) From 588b82546d585e8b6ab9c2af06a8ac1d4e5731ab Mon Sep 17 00:00:00 2001 From: Minh Le Date: Thu, 1 Feb 2024 13:19:59 +0100 Subject: [PATCH 633/814] dt-bindings: watchdog: renesas-wdt: Add support for R-Car V4M Add documentation for r8a779h0 compatible string to Renesas watchdog device tree bindings documentation. Signed-off-by: Minh Le Signed-off-by: Geert Uytterhoeven Acked-by: Conor Dooley Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/8c2eaad577513a519c518698a45083afb65b16f0.1706789940.git.geert+renesas@glider.be Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml index 951a7d54135a..ffb17add491a 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml @@ -71,6 +71,7 @@ properties: - renesas,r8a779a0-wdt # R-Car V3U - renesas,r8a779f0-wdt # R-Car S4-8 - renesas,r8a779g0-wdt # R-Car V4H + - renesas,r8a779h0-wdt # R-Car V4M - const: renesas,rcar-gen4-wdt # R-Car Gen4 reg: From 12b8ab42e1c509121a8d4fae1ba57d3d0f22f571 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 14 Feb 2024 09:49:40 -0700 Subject: [PATCH 634/814] watchdog/hpwdt: Support Suspend and Resume Add call backs to support suspend and resume. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240214164941.630775-2-jerry.hoemann@hpe.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 138dc8d8ca3d..ae30e394d176 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -378,11 +378,36 @@ static void hpwdt_exit(struct pci_dev *dev) pci_disable_device(dev); } +static int hpwdt_suspend(struct device *dev) +{ + if (watchdog_active(&hpwdt_dev)) + hpwdt_stop(); + + return 0; +} + +static int hpwdt_resume(struct device *dev) +{ + if (watchdog_active(&hpwdt_dev)) + hpwdt_start(&hpwdt_dev); + + return 0; +} + +static const struct dev_pm_ops hpwdt_pm_ops = { + LATE_SYSTEM_SLEEP_PM_OPS(hpwdt_suspend, hpwdt_resume) +}; + static struct pci_driver hpwdt_driver = { .name = "hpwdt", .id_table = hpwdt_devices, .probe = hpwdt_init_one, .remove = hpwdt_exit, + + .driver = { + .name = "hpwdt", + .pm = &hpwdt_pm_ops, + } }; MODULE_AUTHOR("Tom Mingarelli"); From 575f100c1cce1486f581baefa97dde15b48728c7 Mon Sep 17 00:00:00 2001 From: Yang Xiwen Date: Wed, 21 Feb 2024 19:56:41 +0800 Subject: [PATCH 635/814] watchdog: sp805_wdt: deassert the reset if available According to the datasheet, the core has an WDOGRESn input signal that needs to be deasserted before being operational. Implement it in the driver. Signed-off-by: Yang Xiwen Reviewed-by: Philipp Zabel Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240221-hisi-wdt-v3-1-9642613dc2e6@outlook.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sp805_wdt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 2756ed54ca3d..109e2e37e8f0 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,7 @@ static int sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) { struct sp805_wdt *wdt; + struct reset_control *rst; u64 rate = 0; int ret = 0; @@ -264,6 +266,12 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) return -ENODEV; } + rst = devm_reset_control_get_optional_exclusive(&adev->dev, NULL); + if (IS_ERR(rst)) + return dev_err_probe(&adev->dev, PTR_ERR(rst), "Can not get reset\n"); + + reset_control_deassert(rst); + wdt->adev = adev; wdt->wdd.info = &wdt_info; wdt->wdd.ops = &wdt_ops; From f4c53582530991fe5dedd124932cf06b955a0b8a Mon Sep 17 00:00:00 2001 From: Yang Xiwen Date: Wed, 21 Feb 2024 19:56:42 +0800 Subject: [PATCH 636/814] dt-bindings: watchdog: arm,sp805: document the reset signal The reset signal needs to be deasserted before operation of sp805 module. Document in the binding. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yang Xiwen Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240221-hisi-wdt-v3-2-9642613dc2e6@outlook.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/arm,sp805.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml b/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml index 7aea255b301b..bd7c09ed1938 100644 --- a/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml @@ -50,6 +50,10 @@ properties: - const: wdog_clk - const: apb_pclk + resets: + maxItems: 1 + description: WDOGRESn input reset signal for sp805 module. + required: - compatible - reg @@ -67,4 +71,5 @@ examples: interrupts = ; clocks = <&wdt_clk>, <&apb_pclk>; clock-names = "wdog_clk", "apb_pclk"; + resets = <&wdt_rst>; }; From dbd7c0088b7f44aa0b9276ed3449df075a7b5b54 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Wed, 28 Feb 2024 13:27:23 -0500 Subject: [PATCH 637/814] watchdog: stm32_iwdg: initialize default timeout The driver never sets a default timeout value, therefore it is initialized to zero. When CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is enabled, the watchdog is started during probe. The kernel is supposed to automatically ping the watchdog from this point until userspace takes over, but this does not happen if the configured timeout is zero. A zero timeout causes watchdog_need_worker() to return false, so the heartbeat worker does not run and the system therefore resets soon after the driver is probed. This patch fixes this by setting an arbitrary non-zero default timeout. The default could be read from the hardware instead, but I didn't see any reason to add this complexity. This has been tested on an STM32F746. Fixes: 85fdc63fe256 ("drivers: watchdog: stm32_iwdg: set WDOG_HW_RUNNING at probe") Signed-off-by: Ben Wolsieffer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240228182723.12855-1-ben.wolsieffer@hefring.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/stm32_iwdg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index d9fd50df9802..5404e0387620 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -20,6 +20,8 @@ #include #include +#define DEFAULT_TIMEOUT 10 + /* IWDG registers */ #define IWDG_KR 0x00 /* Key register */ #define IWDG_PR 0x04 /* Prescaler Register */ @@ -248,6 +250,7 @@ static int stm32_iwdg_probe(struct platform_device *pdev) wdd->parent = dev; wdd->info = &stm32_iwdg_info; wdd->ops = &stm32_iwdg_ops; + wdd->timeout = DEFAULT_TIMEOUT; wdd->min_timeout = DIV_ROUND_UP((RLR_MIN + 1) * PR_MIN, wdt->rate); wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * wdt->data->max_prescaler * 1000) / wdt->rate; From 6e6f320282b95da5171b664ad4eb4e84446dfc1d Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Thu, 21 Dec 2023 16:43:57 +0800 Subject: [PATCH 638/814] dt-bindings: watchdog: starfive,jh7100-wdt: Add compatible for JH8100 Add "starfive,jh8100-wdt" compatible string for StarFive's JH8100 watchdog. Since JH8100 watchdog only has 1 reset signal, update binding document to support one reset for "starfive,jh8100-wdt" compatible. Signed-off-by: Ley Foon Tan Signed-off-by: Ji Sheng Teoh Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20231221084358.3458713-2-jisheng.teoh@starfivetech.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../watchdog/starfive,jh7100-wdt.yaml | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml b/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml index 68f3f6fd08a6..e21f807b0b69 100644 --- a/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml @@ -19,14 +19,16 @@ description: isn't cleared, the watchdog will reset the system unless the watchdog reset is disabled. -allOf: - - $ref: watchdog.yaml# - properties: compatible: - enum: - - starfive,jh7100-wdt - - starfive,jh7110-wdt + oneOf: + - enum: + - starfive,jh7100-wdt + - starfive,jh7110-wdt + - items: + - enum: + - starfive,jh8100-wdt + - const: starfive,jh7110-wdt reg: maxItems: 1 @@ -45,9 +47,8 @@ properties: - const: core resets: - items: - - description: APB reset - - description: Core reset + minItems: 1 + maxItems: 2 required: - compatible @@ -56,6 +57,27 @@ required: - clock-names - resets +allOf: + - $ref: watchdog.yaml# + + - if: + properties: + compatible: + contains: + enum: + - starfive,jh8100-wdt + then: + properties: + resets: + items: + - description: Core reset + else: + properties: + resets: + items: + - description: APB reset + - description: Core reset + unevaluatedProperties: false examples: From 2351837b234c4ac08de98d1ed503447959b23ab0 Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Sat, 17 Feb 2024 16:45:24 +0100 Subject: [PATCH 639/814] dt-bindings: watchdog: sprd,sp9860-wdt: convert to YAML Convert Spreadtrum SP9860 watchdog timer bindings to DT schema. Adjust file name to match compatible. Signed-off-by: Stanislav Jakubek Acked-by: Chunyan Zhang Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/ZdDUlGdqH7Qv3SDu@standask-GA-A55M-S2HP Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/sprd,sp9860-wdt.yaml | 64 +++++++++++++++++++ .../devicetree/bindings/watchdog/sprd-wdt.txt | 19 ------ 2 files changed, 64 insertions(+), 19 deletions(-) create mode 100644 Documentation/devicetree/bindings/watchdog/sprd,sp9860-wdt.yaml delete mode 100644 Documentation/devicetree/bindings/watchdog/sprd-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/sprd,sp9860-wdt.yaml b/Documentation/devicetree/bindings/watchdog/sprd,sp9860-wdt.yaml new file mode 100644 index 000000000000..730d9a3a3cc5 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/sprd,sp9860-wdt.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/sprd,sp9860-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SP9860 watchdog timer + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: sprd,sp9860-wdt + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: enable + - const: rtc_enable + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - timeout-sec + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + watchdog@40310000 { + compatible = "sprd,sp9860-wdt"; + reg = <0 0x40310000 0 0x1000>; + interrupts = ; + clocks = <&aon_gate CLK_APCPU_WDG_EB>, <&aon_gate CLK_AP_WDG_RTC_EB>; + clock-names = "enable", "rtc_enable"; + timeout-sec = <12>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt b/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt deleted file mode 100644 index aeaf3e0caf47..000000000000 --- a/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt +++ /dev/null @@ -1,19 +0,0 @@ -Spreadtrum SoCs Watchdog timer - -Required properties: -- compatible : Should be "sprd,sp9860-wdt". -- reg : Specifies base physical address and size of the registers. -- interrupts : Exactly one interrupt specifier. -- timeout-sec : Contain the default watchdog timeout in seconds. -- clock-names : Contain the input clock names. -- clocks : Phandles to input clocks. - -Example: - watchdog: watchdog@40310000 { - compatible = "sprd,sp9860-wdt"; - reg = <0 0x40310000 0 0x1000>; - interrupts = ; - timeout-sec = <12>; - clock-names = "enable", "rtc_enable"; - clocks = <&clk_aon_apb_gates1 8>, <&clk_aon_apb_rtc_gates 9>; - }; From cd2aa8779db00de45d72445f963346644dca0673 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:56:27 +0530 Subject: [PATCH 640/814] dt-bindings: watchdog: sama5d4-wdt: add compatible for sam9x7-wdt Add compatible microchip,sam9x7-wdt to DT bindings documentation. Signed-off-by: Varshini Rajendran Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240223172627.672316-1-varshini.rajendran@microchip.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/atmel,sama5d4-wdt.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml index 816f85ee2c77..cdf87db36183 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml @@ -14,10 +14,14 @@ allOf: properties: compatible: - enum: - - atmel,sama5d4-wdt - - microchip,sam9x60-wdt - - microchip,sama7g5-wdt + oneOf: + - enum: + - atmel,sama5d4-wdt + - microchip,sam9x60-wdt + - microchip,sama7g5-wdt + - items: + - const: microchip,sam9x7-wdt + - const: microchip,sam9x60-wdt reg: maxItems: 1 From 849c34e63c0dd8d6ec1e3aed0bf34ffc72fa71e4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 3 Mar 2024 14:32:00 -0800 Subject: [PATCH 641/814] Input: leds - change config symbol dependency for audio mute trigger In a follow-up patch implementation of the LED audio trigger will be moved to sound/core/snd_ctl_led, including removal of config symbol LEDS_AUDIO_TRIGGER. Also as of today the audio mute LED trigger is effectively a no-op w/o config symbol SND_CTL_LED being defined. Therefore switch the dependency to this config symbol. Suggested-by: Dmitry Torokhov Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/6011ca63-187c-42dd-a5fd-7dd733d6257c@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/input-leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index b16fc81940f5..6bbf3806ea37 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -18,7 +18,7 @@ #define VT_TRIGGER(_name) .trigger = NULL #endif -#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO) +#if IS_ENABLED(CONFIG_SND_CTL_LED) #define AUDIO_TRIGGER(_name) .trigger = _name #else #define AUDIO_TRIGGER(_name) .trigger = NULL From 54a62ed17a705ef1ac80ebca2b62136b19243e19 Mon Sep 17 00:00:00 2001 From: Markuss Broks Date: Fri, 1 Mar 2024 17:41:00 +0100 Subject: [PATCH 642/814] input/touchscreen: imagis: Correct the maximum touch area value As specified in downstream IST3038B driver and proved by testing, the correct maximum reported value of touch area is 16. Signed-off-by: Markuss Broks Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240301164659.13240-2-karelb@gimli.ms.mff.cuni.cz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imagis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index 07111ca24455..e67fd3011027 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -210,7 +210,7 @@ static int imagis_init_input_dev(struct imagis_ts *ts) 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_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 16, 0, 0); touchscreen_parse_properties(input_dev, true, &ts->prop); if (!ts->prop.max_x || !ts->prop.max_y) { From c53d309a4299fffde14e281440a25c2355d8b621 Mon Sep 17 00:00:00 2001 From: Markuss Broks Date: Fri, 1 Mar 2024 17:41:01 +0100 Subject: [PATCH 643/814] dt-bindings: input/touchscreen: Add compatible for IST3038B Imagis IST3038B is a variant (firmware?) of Imagis IST3038 IC differing from IST3038C in its register interface. Add the compatible for it to the IST3038C bindings. Signed-off-by: Markuss Broks Acked-by: Conor Dooley [balejk@matfyz.cz: elaborate chip differences in the commit message] Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240301164659.13240-3-karelb@gimli.ms.mff.cuni.cz Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml index 0d6b033fd5fb..b5372c4eae56 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: + - imagis,ist3038b - imagis,ist3038c reg: From 10ad7d7a428f7bb336c3cb226ab8aa0e6a947dac Mon Sep 17 00:00:00 2001 From: Markuss Broks Date: Fri, 1 Mar 2024 17:41:02 +0100 Subject: [PATCH 644/814] input/touchscreen: imagis: Add support for Imagis IST3038B Imagis IST3038B is another variant of Imagis IST3038 IC, which has a different register interface from IST3038C (possibly firmware defined). This should also work for IST3044B (though untested), however other variants using this interface/protocol(IST3026, IST3032, IST3026B, IST3032B) have a different format for coordinates, and they'd need additional effort to be supported by this driver. Signed-off-by: Markuss Broks Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240301164659.13240-4-karelb@gimli.ms.mff.cuni.cz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imagis.c | 58 ++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index e67fd3011027..9af8a6332ae6 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -11,9 +11,13 @@ #include #include +#define IST3038B_REG_STATUS 0x20 +#define IST3038B_REG_CHIPID 0x30 +#define IST3038B_WHOAMI 0x30380b + #define IST3038C_HIB_ACCESS (0x800B << 16) #define IST3038C_DIRECT_ACCESS BIT(31) -#define IST3038C_REG_CHIPID 0x40001000 +#define IST3038C_REG_CHIPID (0x40001000 | IST3038C_DIRECT_ACCESS) #define IST3038C_REG_HIB_BASE 0x30000100 #define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS) #define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8) @@ -31,8 +35,17 @@ #define IST3038C_FINGER_COUNT_SHIFT 12 #define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0) +struct imagis_properties { + unsigned int interrupt_msg_cmd; + unsigned int touch_coord_cmd; + unsigned int whoami_cmd; + unsigned int whoami_val; + bool protocol_b; +}; + struct imagis_ts { struct i2c_client *client; + const struct imagis_properties *tdata; struct input_dev *input_dev; struct touchscreen_properties prop; struct regulator_bulk_data supplies[2]; @@ -84,8 +97,7 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) int i; int error; - error = imagis_i2c_read_reg(ts, IST3038C_REG_INTR_MESSAGE, - &intr_message); + error = imagis_i2c_read_reg(ts, ts->tdata->interrupt_msg_cmd, &intr_message); if (error) { dev_err(&ts->client->dev, "failed to read the interrupt message: %d\n", error); @@ -104,9 +116,13 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK; for (i = 0; i < finger_count; i++) { - error = imagis_i2c_read_reg(ts, - IST3038C_REG_TOUCH_COORD + (i * 4), - &finger_status); + if (ts->tdata->protocol_b) + error = imagis_i2c_read_reg(ts, + ts->tdata->touch_coord_cmd, &finger_status); + else + error = imagis_i2c_read_reg(ts, + ts->tdata->touch_coord_cmd + (i * 4), + &finger_status); if (error) { dev_err(&ts->client->dev, "failed to read coordinates for finger %d: %d\n", @@ -261,6 +277,12 @@ static int imagis_probe(struct i2c_client *i2c) ts->client = i2c; + ts->tdata = device_get_match_data(dev); + if (!ts->tdata) { + dev_err(dev, "missing chip data\n"); + return -EINVAL; + } + error = imagis_init_regulators(ts); if (error) { dev_err(dev, "regulator init error: %d\n", error); @@ -279,15 +301,13 @@ static int imagis_probe(struct i2c_client *i2c) return error; } - error = imagis_i2c_read_reg(ts, - IST3038C_REG_CHIPID | IST3038C_DIRECT_ACCESS, - &chip_id); + error = imagis_i2c_read_reg(ts, ts->tdata->whoami_cmd, &chip_id); if (error) { dev_err(dev, "chip ID read failure: %d\n", error); return error; } - if (chip_id != IST3038C_WHOAMI) { + if (chip_id != ts->tdata->whoami_val) { dev_err(dev, "unknown chip ID: 0x%x\n", chip_id); return -EINVAL; } @@ -343,9 +363,25 @@ static int imagis_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume); +static const struct imagis_properties imagis_3038b_data = { + .interrupt_msg_cmd = IST3038B_REG_STATUS, + .touch_coord_cmd = IST3038B_REG_STATUS, + .whoami_cmd = IST3038B_REG_CHIPID, + .whoami_val = IST3038B_WHOAMI, + .protocol_b = true, +}; + +static const struct imagis_properties imagis_3038c_data = { + .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE, + .touch_coord_cmd = IST3038C_REG_TOUCH_COORD, + .whoami_cmd = IST3038C_REG_CHIPID, + .whoami_val = IST3038C_WHOAMI, +}; + #ifdef CONFIG_OF static const struct of_device_id imagis_of_match[] = { - { .compatible = "imagis,ist3038c", }, + { .compatible = "imagis,ist3038b", .data = &imagis_3038b_data }, + { .compatible = "imagis,ist3038c", .data = &imagis_3038c_data }, { }, }; MODULE_DEVICE_TABLE(of, imagis_of_match); From d88f84bfccd2a17a81fbf404eaae77208e827c31 Mon Sep 17 00:00:00 2001 From: Karel Balej Date: Fri, 1 Mar 2024 17:41:03 +0100 Subject: [PATCH 645/814] dt-bindings: input/touchscreen: imagis: add compatible for IST3032C IST3032C is a touchscreen IC which seems mostly compatible with IST3038C except that it reports a different chip ID value. Acked-by: Rob Herring Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240301164659.13240-5-karelb@gimli.ms.mff.cuni.cz Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml index b5372c4eae56..2af71cbcc97d 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: + - imagis,ist3032c - imagis,ist3038b - imagis,ist3038c From 90cb57a6c5717b83a110c0da720a03ee32ed255e Mon Sep 17 00:00:00 2001 From: Karel Balej Date: Fri, 1 Mar 2024 17:41:04 +0100 Subject: [PATCH 646/814] input/touchscreen: imagis: add support for IST3032C IST3032C is a touchscreen chip used for instance in the samsung,coreprimevelte smartphone, with which this was tested. Add the chip specific information to the driver. Reviewed-by: Markuss Broks Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240301164659.13240-6-karelb@gimli.ms.mff.cuni.cz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imagis.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index 9af8a6332ae6..e1fafa561ee3 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -11,6 +11,8 @@ #include #include +#define IST3032C_WHOAMI 0x32c + #define IST3038B_REG_STATUS 0x20 #define IST3038B_REG_CHIPID 0x30 #define IST3038B_WHOAMI 0x30380b @@ -363,6 +365,13 @@ static int imagis_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume); +static const struct imagis_properties imagis_3032c_data = { + .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE, + .touch_coord_cmd = IST3038C_REG_TOUCH_COORD, + .whoami_cmd = IST3038C_REG_CHIPID, + .whoami_val = IST3032C_WHOAMI, +}; + static const struct imagis_properties imagis_3038b_data = { .interrupt_msg_cmd = IST3038B_REG_STATUS, .touch_coord_cmd = IST3038B_REG_STATUS, @@ -380,6 +389,7 @@ static const struct imagis_properties imagis_3038c_data = { #ifdef CONFIG_OF static const struct of_device_id imagis_of_match[] = { + { .compatible = "imagis,ist3032c", .data = &imagis_3032c_data }, { .compatible = "imagis,ist3038b", .data = &imagis_3038b_data }, { .compatible = "imagis,ist3038c", .data = &imagis_3038c_data }, { }, From d49193be636ab2b6e35727541bbdcdc1eab2d676 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sun, 3 Mar 2024 15:02:08 -0800 Subject: [PATCH 647/814] Input: xilinx_ps2 - fix kernel-doc for xps2_of_probe function The existing comment block above the xps2_of_probe function does not conform to the kernel-doc standard. This patch fixes the documentation to match the expected kernel-doc format, which includes a structured documentation header with param and return value. Signed-off-by: Yang Li Reviewed-by: Michal Simek Link: https://lore.kernel.org/r/20240301092115.123092-1-yang.lee@linux.alibaba.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/xilinx_ps2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index d8f9faf2b529..bb758346a33d 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -219,8 +219,7 @@ static void sxps2_close(struct serio *pserio) /** * xps2_of_probe - probe method for the PS/2 device. - * @of_dev: pointer to OF device structure - * @match: pointer to the structure used for matching a device + * @ofdev: pointer to OF device structure * * This function probes the PS/2 device in the device tree. * It initializes the driver data structure and the hardware. From d1278c91fec3e1d27d6e06d00a67a5a314341344 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 3 Mar 2024 15:05:23 -0800 Subject: [PATCH 648/814] Input: synaptics-rmi4 - make rmi_bus_type const Now that the driver core can properly handle constant struct bus_type, move the variable rmi_bus_type to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240210-bus_cleanup-input2-v1-1-0daef7e034e0@marliere.net Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_bus.c | 2 +- drivers/input/rmi4/rmi_bus.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 1b45b1d3077d..343030290d78 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -344,7 +344,7 @@ static int rmi_bus_match(struct device *dev, struct device_driver *drv) return physical || rmi_function_match(dev, drv); } -struct bus_type rmi_bus_type = { +const struct bus_type rmi_bus_type = { .match = rmi_bus_match, .name = "rmi4", }; diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h index 25df6320f9f1..ea46ad9447ec 100644 --- a/drivers/input/rmi4/rmi_bus.h +++ b/drivers/input/rmi4/rmi_bus.h @@ -185,7 +185,7 @@ static inline int rmi_write_block(struct rmi_device *d, u16 addr, int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data)); -extern struct bus_type rmi_bus_type; +extern const struct bus_type rmi_bus_type; int rmi_of_property_read_u32(struct device *dev, u32 *result, const char *prop, bool optional); From fbd5f5008fab2203fa21e82579b9b48a7256b8fd Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 3 Mar 2024 15:05:42 -0800 Subject: [PATCH 649/814] Input: serio - make serio_bus const Now that the driver core can properly handle constant struct bus_type, move the serio_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240210-bus_cleanup-input2-v1-2-0daef7e034e0@marliere.net Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 2 +- include/linux/serio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 767fc9efb4a8..a8838b522627 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -1007,7 +1007,7 @@ irqreturn_t serio_interrupt(struct serio *serio, } EXPORT_SYMBOL(serio_interrupt); -struct bus_type serio_bus = { +const struct bus_type serio_bus = { .name = "serio", .drv_groups = serio_driver_groups, .match = serio_bus_match, diff --git a/include/linux/serio.h b/include/linux/serio.h index 6c27d413da92..7ca41af93b37 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -15,7 +15,7 @@ #include #include -extern struct bus_type serio_bus; +extern const struct bus_type serio_bus; struct serio { void *port_data; From 78a0eda0ef4f3ed5e15bb8dfacc8c3366dfd937c Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 22 Feb 2024 15:33:12 +0100 Subject: [PATCH 650/814] MAINTAINERS: remove entry to non-existing file in MOBILEYE MIPS SOCS Commit f34158edd249 ("MAINTAINERS: Add entry for Mobileye MIPS SoCs") adds the section MOBILEYE MIPS SOCS with a file entry to the non-existing file include/dt-bindings/soc/mobileye,eyeq5.h. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Possibly, this file was part of an early patch series, but in the final patch series, this file does not appear anymore. Delete this file entry in the MOBILEYE MIPS SOCS section. Signed-off-by: Lukas Bulwahn Acked-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1c45074b4dce..4769f84e738b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14808,7 +14808,6 @@ F: Documentation/devicetree/bindings/mips/mobileye.yaml F: arch/mips/boot/dts/mobileye/ F: arch/mips/configs/eyeq5_defconfig F: arch/mips/mobileye/board-epm5.its.S -F: include/dt-bindings/soc/mobileye,eyeq5.h MODULE SUPPORT M: Luis Chamberlain From fdf0df8c936c0822570e067009dee6824ff3a2be Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 26 Feb 2024 10:09:27 +0800 Subject: [PATCH 651/814] bus: bt1-apb: Remove duplicate include ./drivers/bus/bt1-apb.c: linux/clk.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8312 Signed-off-by: Jiapeng Chong Acked-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- drivers/bus/bt1-apb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bus/bt1-apb.c b/drivers/bus/bt1-apb.c index e97c1d1c7578..595fb22b73e0 100644 --- a/drivers/bus/bt1-apb.c +++ b/drivers/bus/bt1-apb.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #define APB_EHB_ISR 0x00 From aaef9cdc4bdcf45db729a4ce7ebf3fda3336e092 Mon Sep 17 00:00:00 2001 From: Dharma Balasubiramani Date: Thu, 22 Feb 2024 14:37:38 +0530 Subject: [PATCH 652/814] dt-bindings: interrupt-controller: Convert Atmel AIC to json-schema Convert the Atmel AIC binding document to DT schema format using json-schema. Signed-off-by: Dharma Balasubiramani Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240222090738.41628-1-dharma.b@microchip.com Signed-off-by: Rob Herring --- .../interrupt-controller/atmel,aic.txt | 43 --------- .../interrupt-controller/atmel,aic.yaml | 89 +++++++++++++++++++ 2 files changed, 89 insertions(+), 43 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt deleted file mode 100644 index 7079d44bf3ba..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt +++ /dev/null @@ -1,43 +0,0 @@ -* Advanced Interrupt Controller (AIC) - -Required properties: -- compatible: Should be: - - "atmel,-aic" where can be "at91rm9200", "sama5d2", - "sama5d3" or "sama5d4" - - "microchip,-aic" where can be "sam9x60" - -- interrupt-controller: Identifies the node as an interrupt controller. -- #interrupt-cells: The number of cells to define the interrupts. It should be 3. - The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet). - The second cell is used to specify flags: - bits[3:0] trigger type and level flags: - 1 = low-to-high edge triggered. - 2 = high-to-low edge triggered. - 4 = active high level-sensitive. - 8 = active low level-sensitive. - Valid combinations are 1, 2, 3, 4, 8. - Default flag for internal sources should be set to 4 (active high). - The third cell is used to specify the irq priority from 0 (lowest) to 7 - (highest). -- reg: Should contain AIC registers location and length -- atmel,external-irqs: u32 array of external irqs. - -Examples: - /* - * AIC - */ - aic: interrupt-controller@fffff000 { - compatible = "atmel,at91rm9200-aic"; - interrupt-controller; - #interrupt-cells = <3>; - reg = <0xfffff000 0x200>; - }; - - /* - * An interrupt generating device that is wired to an AIC. - */ - dma: dma-controller@ffffec00 { - compatible = "atmel,at91sam9g45-dma"; - reg = <0xffffec00 0x200>; - interrupts = <21 4 5>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml new file mode 100644 index 000000000000..d4658fe3867c --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/atmel,aic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Advanced Interrupt Controller (AIC) + +maintainers: + - Nicolas Ferre + - Dharma balasubiramani + +description: + The Advanced Interrupt Controller (AIC) is an 8-level priority, individually + maskable, vectored interrupt controller providing handling of up to one + hundred and twenty-eight interrupt sources. + +properties: + compatible: + enum: + - atmel,at91rm9200-aic + - atmel,sama5d2-aic + - atmel,sama5d3-aic + - atmel,sama5d4-aic + - microchip,sam9x60-aic + + reg: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 3 + description: | + The 1st cell is the IRQ number (Peripheral IDentifier on datasheet). + The 2nd cell specifies flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations: 1, 2, 3, 4, 8. + Default for internal sources: 4 (active high). + The 3rd cell specifies irq priority from 0 (lowest) to 7 (highest). + + interrupts: + maxItems: 1 + + atmel,external-irqs: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: u32 array of external irqs. + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + - if: + properties: + compatible: + contains: + const: atmel,at91rm9200-aic + then: + properties: + atmel,external-irqs: + minItems: 1 + maxItems: 7 + else: + properties: + atmel,external-irqs: + minItems: 1 + maxItems: 1 + +required: + - compatible + - reg + - interrupt-controller + - "#interrupt-cells" + - atmel,external-irqs + +unevaluatedProperties: false + +examples: + - | + interrupt-controller@fffff000 { + compatible = "atmel,at91rm9200-aic"; + reg = <0xfffff000 0x200>; + interrupt-controller; + #interrupt-cells = <3>; + atmel,external-irqs = <31>; + }; +... From ad8ee969d7e34dd310a618d798cc6d8fe4f04464 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 3 Mar 2024 11:48:53 +0100 Subject: [PATCH 653/814] of: make for_each_property_of_node() available to to !OF for_each_property_of_node() is a macro and so doesn't have a stub inline function for !OF. Move it out of the relevant #ifdef to make it available to all users. Fixes: 611cad720148 ("dt: add of_alias_scan and of_alias_get_id") Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20240303104853.31511-1-brgl@bgdev.pl Signed-off-by: Rob Herring --- include/linux/of.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/of.h b/include/linux/of.h index 6a9ddf20e79a..a3e8e429ad7f 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -362,9 +362,6 @@ extern struct device_node *of_get_cpu_state_node(struct device_node *cpu_node, int index); extern u64 of_get_cpu_hwid(struct device_node *cpun, unsigned int thread); -#define for_each_property_of_node(dn, pp) \ - for (pp = dn->properties; pp != NULL; pp = pp->next) - extern int of_n_addr_cells(struct device_node *np); extern int of_n_size_cells(struct device_node *np); extern const struct of_device_id *of_match_node( @@ -892,6 +889,9 @@ static inline int of_prop_val_eq(struct property *p1, struct property *p2) !memcmp(p1->value, p2->value, (size_t)p1->length); } +#define for_each_property_of_node(dn, pp) \ + for (pp = dn->properties; pp != NULL; pp = pp->next) + #if defined(CONFIG_OF) && defined(CONFIG_NUMA) extern int of_node_to_nid(struct device_node *np); #else From ec29d22caea85d9b391f9df780a0e61597f18778 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 26 Feb 2024 12:09:26 +0100 Subject: [PATCH 654/814] vfio: amba: Rename pl330_ids[] to vfio_amba_ids[] Obviously drivers/vfio/platform/vfio_amba.c started its life as a simplified copy of drivers/dma/pl330.c, but not all variable names were updated. Signed-off-by: Geert Uytterhoeven Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/1d1b873b59b208547439225aee1f24d6f2512a1f.1708945194.git.geert+renesas@glider.be Signed-off-by: Alex Williamson --- drivers/vfio/platform/vfio_amba.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c index 6464b3939ebc..485c6f9161a9 100644 --- a/drivers/vfio/platform/vfio_amba.c +++ b/drivers/vfio/platform/vfio_amba.c @@ -122,16 +122,16 @@ static const struct vfio_device_ops vfio_amba_ops = { .detach_ioas = vfio_iommufd_physical_detach_ioas, }; -static const struct amba_id pl330_ids[] = { +static const struct amba_id vfio_amba_ids[] = { { 0, 0 }, }; -MODULE_DEVICE_TABLE(amba, pl330_ids); +MODULE_DEVICE_TABLE(amba, vfio_amba_ids); static struct amba_driver vfio_amba_driver = { .probe = vfio_amba_probe, .remove = vfio_amba_remove, - .id_table = pl330_ids, + .id_table = vfio_amba_ids, .drv = { .name = "vfio-amba", .owner = THIS_MODULE, From 81617c17bf58f008a57da74b97e60a0bf8e971fd Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Thu, 29 Feb 2024 19:39:34 +0000 Subject: [PATCH 655/814] vfio/nvgrace-gpu: Convey kvm to map device memory region as noncached The NVIDIA Grace Hopper GPUs have device memory that is supposed to be used as a regular RAM. It is accessible through CPU-GPU chip-to-chip cache coherent interconnect and is present in the system physical address space. The device memory is split into two regions - termed as usemem and resmem - in the system physical address space, with each region mapped and exposed to the VM as a separate fake device BAR [1]. Owing to a hardware defect for Multi-Instance GPU (MIG) feature [2], there is a requirement - as a workaround - for the resmem BAR to display uncached memory characteristics. Based on [3], on system with FWB enabled such as Grace Hopper, the requisite properties (uncached, unaligned access) can be achieved through a VM mapping (S1) of NORMAL_NC and host mapping (S2) of MT_S2_FWB_NORMAL_NC. KVM currently maps the MMIO region in S2 as MT_S2_FWB_DEVICE_nGnRE by default. The fake device BARs thus displays DEVICE_nGnRE behavior in the VM. The following table summarizes the behavior for the various S1 and S2 mapping combinations for systems with FWB enabled [3]. S1 | S2 | Result NORMAL_NC | NORMAL_NC | NORMAL_NC NORMAL_NC | DEVICE_nGnRE | DEVICE_nGnRE Recently a change was added that modifies this default behavior and make KVM map MMIO as MT_S2_FWB_NORMAL_NC when a VMA flag VM_ALLOW_ANY_UNCACHED is set [4]. Setting S2 as MT_S2_FWB_NORMAL_NC provides the desired behavior (uncached, unaligned access) for resmem. To use VM_ALLOW_ANY_UNCACHED flag, the platform must guarantee that no action taken on the MMIO mapping can trigger an uncontained failure. The Grace Hopper satisfies this requirement. So set the VM_ALLOW_ANY_UNCACHED flag in the VMA. Applied over next-20240227. base-commit: 22ba90670a51 Link: https://lore.kernel.org/all/20240220115055.23546-4-ankita@nvidia.com/ [1] Link: https://www.nvidia.com/en-in/technologies/multi-instance-gpu/ [2] Link: https://developer.arm.com/documentation/ddi0487/latest/ section D8.5.5 [3] Link: https://lore.kernel.org/all/20240224150546.368-1-ankita@nvidia.com/ [4] Cc: Alex Williamson Cc: Kevin Tian Cc: Jason Gunthorpe Cc: Vikram Sethi Cc: Zhi Wang Signed-off-by: Ankit Agrawal Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20240229193934.2417-1-ankita@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/nvgrace-gpu/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index 25814006352d..a7fd018aa548 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -160,8 +160,17 @@ static int nvgrace_gpu_mmap(struct vfio_device *core_vdev, * The carved out region of the device memory needs the NORMAL_NC * property. Communicate as such to the hypervisor. */ - if (index == RESMEM_REGION_INDEX) + if (index == RESMEM_REGION_INDEX) { + /* + * The nvgrace-gpu module has no issues with uncontained + * failures on NORMAL_NC accesses. VM_ALLOW_ANY_UNCACHED is + * set to communicate to the KVM to S2 map as NORMAL_NC. + * This opens up guest usage of NORMAL_NC for this mapping. + */ + vm_flags_set(vma, VM_ALLOW_ANY_UNCACHED); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + } /* * Perform a PFN map to the memory and back the device BAR by the From 5b992412776cdf2ec88b5b5138112e6b36e47995 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 29 Feb 2024 15:35:40 -0700 Subject: [PATCH 656/814] Revert "vfio/type1: Unpin zero pages" This reverts commit 873aefb376bbc0ed1dd2381ea1d6ec88106fdbd4. This was a heinous workaround and it turns out it's been fixed in mm twice since it was introduced. Most recently, commit c8070b787519 ("mm: Don't pin ZERO_PAGE in pin_user_pages()") would have prevented running up the zeropage refcount, but even before that commit 84209e87c696 ("mm/gup: reliable R/O long-term pinning in COW mappings") avoids the vfio use case from pinning the zeropage at all, instead replacing it with exclusive anonymous pages. Remove this now useless overhead. Suggested-by: David Hildenbrand Reviewed-by: David Hildenbrand Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240229223544.257207-1-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/vfio_iommu_type1.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index b2854d7939ce..b5c15fe8f9fc 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -567,18 +567,6 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, ret = pin_user_pages_remote(mm, vaddr, npages, flags | FOLL_LONGTERM, pages, NULL); if (ret > 0) { - int i; - - /* - * The zero page is always resident, we don't need to pin it - * and it falls into our invalid/reserved test so we don't - * unpin in put_pfn(). Unpin all zero pages in the batch here. - */ - for (i = 0 ; i < ret; i++) { - if (unlikely(is_zero_pfn(page_to_pfn(pages[i])))) - unpin_user_page(pages[i]); - } - *pfn = page_to_pfn(pages[0]); goto done; } From 451a707813aee24b4a734f28d1d414be0360862b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Feb 2024 11:49:15 +0000 Subject: [PATCH 657/814] KVM: x86/xen: improve accuracy of Xen timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A test program such as http://david.woodhou.se/timerlat.c confirms user reports that timers are increasingly inaccurate as the lifetime of a guest increases. Reporting the actual delay observed when asking for 100µs of sleep, it starts off OK on a newly-launched guest but gets worse over time, giving incorrect sleep times: root@ip-10-0-193-21:~# ./timerlat -c -n 5 00000000 latency 103243/100000 (3.2430%) 00000001 latency 103243/100000 (3.2430%) 00000002 latency 103242/100000 (3.2420%) 00000003 latency 103245/100000 (3.2450%) 00000004 latency 103245/100000 (3.2450%) The biggest problem is that get_kvmclock_ns() returns inaccurate values when the guest TSC is scaled. The guest sees a TSC value scaled from the host TSC by a mul/shift conversion (hopefully done in hardware). The guest then converts that guest TSC value into nanoseconds using the mul/shift conversion given to it by the KVM pvclock information. But get_kvmclock_ns() performs only a single conversion directly from host TSC to nanoseconds, giving a different result. A test program at http://david.woodhou.se/tsdrift.c demonstrates the cumulative error over a day. It's non-trivial to fix get_kvmclock_ns(), although I'll come back to that. The actual guest hv_clock is per-CPU, and *theoretically* each vCPU could be running at a *different* frequency. But this patch is needed anyway because... The other issue with Xen timers was that the code would snapshot the host CLOCK_MONOTONIC at some point in time, and then... after a few interrupts may have occurred, some preemption perhaps... would also read the guest's kvmclock. Then it would proceed under the false assumption that those two happened at the *same* time. Any time which *actually* elapsed between reading the two clocks was introduced as inaccuracies in the time at which the timer fired. Fix it to use a variant of kvm_get_time_and_clockread(), which reads the host TSC just *once*, then use the returned TSC value to calculate the kvmclock (making sure to do that the way the guest would instead of making the same mistake get_kvmclock_ns() does). Sadly, hrtimers based on CLOCK_MONOTONIC_RAW are not supported, so Xen timers still have to use CLOCK_MONOTONIC. In practice the difference between the two won't matter over the timescales involved, as the *absolute* values don't matter; just the delta. This does mean a new variant of kvm_get_time_and_clockread() is needed; called kvm_get_monotonic_and_clockread() because that's what it does. Fixes: 536395260582 ("KVM: x86/xen: handle PV timers oneshot mode") Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://lore.kernel.org/r/20240227115648.3104-2-dwmw2@infradead.org [sean: massage moved comment, tweak if statement formatting] Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 61 +++++++++++++++++++-- arch/x86/kvm/x86.h | 1 + arch/x86/kvm/xen.c | 130 +++++++++++++++++++++++++++++++++------------ 3 files changed, 152 insertions(+), 40 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2911e6383fef..89815a887e4d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2862,7 +2862,11 @@ static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, return v * clock->mult; } -static int do_monotonic_raw(s64 *t, u64 *tsc_timestamp) +/* + * As with get_kvmclock_base_ns(), this counts from boot time, at the + * frequency of CLOCK_MONOTONIC_RAW (hence adding gtos->offs_boot). + */ +static int do_kvmclock_base(s64 *t, u64 *tsc_timestamp) { struct pvclock_gtod_data *gtod = &pvclock_gtod_data; unsigned long seq; @@ -2881,6 +2885,29 @@ static int do_monotonic_raw(s64 *t, u64 *tsc_timestamp) return mode; } +/* + * This calculates CLOCK_MONOTONIC at the time of the TSC snapshot, with + * no boot time offset. + */ +static int do_monotonic(s64 *t, u64 *tsc_timestamp) +{ + struct pvclock_gtod_data *gtod = &pvclock_gtod_data; + unsigned long seq; + int mode; + u64 ns; + + do { + seq = read_seqcount_begin(>od->seq); + ns = gtod->clock.base_cycles; + ns += vgettsc(>od->clock, tsc_timestamp, &mode); + ns >>= gtod->clock.shift; + ns += ktime_to_ns(gtod->clock.offset); + } while (unlikely(read_seqcount_retry(>od->seq, seq))); + *t = ns; + + return mode; +} + static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) { struct pvclock_gtod_data *gtod = &pvclock_gtod_data; @@ -2902,18 +2929,42 @@ static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) return mode; } -/* returns true if host is using TSC based clocksource */ +/* + * Calculates the kvmclock_base_ns (CLOCK_MONOTONIC_RAW + boot time) and + * reports the TSC value from which it do so. Returns true if host is + * using TSC based clocksource. + */ static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) { /* checked again under seqlock below */ if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) return false; - return gtod_is_based_on_tsc(do_monotonic_raw(kernel_ns, - tsc_timestamp)); + return gtod_is_based_on_tsc(do_kvmclock_base(kernel_ns, + tsc_timestamp)); } -/* returns true if host is using TSC based clocksource */ +/* + * Calculates CLOCK_MONOTONIC and reports the TSC value from which it did + * so. Returns true if host is using TSC based clocksource. + */ +bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) +{ + /* checked again under seqlock below */ + if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + return false; + + return gtod_is_based_on_tsc(do_monotonic(kernel_ns, + tsc_timestamp)); +} + +/* + * Calculates CLOCK_REALTIME and reports the TSC value from which it did + * so. Returns true if host is using TSC based clocksource. + * + * DO NOT USE this for anything related to migration. You want CLOCK_TAI + * for that. + */ static bool kvm_get_walltime_and_clockread(struct timespec64 *ts, u64 *tsc_timestamp) { diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 2f7e19166658..56b7a78f45bf 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -294,6 +294,7 @@ void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); u64 get_kvmclock_ns(struct kvm *kvm); uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm); +bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp); int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 8a04e0ae9245..8a4c563e2398 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -24,6 +24,7 @@ #include #include +#include #include "cpuid.h" #include "trace.h" @@ -149,8 +150,93 @@ static enum hrtimer_restart xen_timer_callback(struct hrtimer *timer) return HRTIMER_NORESTART; } -static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs, s64 delta_ns) +static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs, + bool linux_wa) { + int64_t kernel_now, delta; + uint64_t guest_now; + + /* + * The guest provides the requested timeout in absolute nanoseconds + * of the KVM clock — as *it* sees it, based on the scaled TSC and + * the pvclock information provided by KVM. + * + * The kernel doesn't support hrtimers based on CLOCK_MONOTONIC_RAW + * so use CLOCK_MONOTONIC. In the timescales covered by timers, the + * difference won't matter much as there is no cumulative effect. + * + * Calculate the time for some arbitrary point in time around "now" + * in terms of both kvmclock and CLOCK_MONOTONIC. Calculate the + * delta between the kvmclock "now" value and the guest's requested + * timeout, apply the "Linux workaround" described below, and add + * the resulting delta to the CLOCK_MONOTONIC "now" value, to get + * the absolute CLOCK_MONOTONIC time at which the timer should + * fire. + */ + if (vcpu->arch.hv_clock.version && vcpu->kvm->arch.use_master_clock && + static_cpu_has(X86_FEATURE_CONSTANT_TSC)) { + uint64_t host_tsc, guest_tsc; + + if (!IS_ENABLED(CONFIG_64BIT) || + !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc)) { + /* + * Don't fall back to get_kvmclock_ns() because it's + * broken; it has a systemic error in its results + * because it scales directly from host TSC to + * nanoseconds, and doesn't scale first to guest TSC + * and *then* to nanoseconds as the guest does. + * + * There is a small error introduced here because time + * continues to elapse between the ktime_get() and the + * subsequent rdtsc(). But not the systemic drift due + * to get_kvmclock_ns(). + */ + kernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */ + host_tsc = rdtsc(); + } + + /* Calculate the guest kvmclock as the guest would do it. */ + guest_tsc = kvm_read_l1_tsc(vcpu, host_tsc); + guest_now = __pvclock_read_cycles(&vcpu->arch.hv_clock, + guest_tsc); + } else { + /* + * Without CONSTANT_TSC, get_kvmclock_ns() is the only option. + * + * Also if the guest PV clock hasn't been set up yet, as is + * likely to be the case during migration when the vCPU has + * not been run yet. It would be possible to calculate the + * scaling factors properly in that case but there's not much + * point in doing so. The get_kvmclock_ns() drift accumulates + * over time, so it's OK to use it at startup. Besides, on + * migration there's going to be a little bit of skew in the + * precise moment at which timers fire anyway. Often they'll + * be in the "past" by the time the VM is running again after + * migration. + */ + guest_now = get_kvmclock_ns(vcpu->kvm); + kernel_now = ktime_get(); + } + + delta = guest_abs - guest_now; + + /* + * Xen has a 'Linux workaround' in do_set_timer_op() which checks for + * negative absolute timeout values (caused by integer overflow), and + * for values about 13 days in the future (2^50ns) which would be + * caused by jiffies overflow. For those cases, Xen sets the timeout + * 100ms in the future (not *too* soon, since if a guest really did + * set a long timeout on purpose we don't want to keep churning CPU + * time by waking it up). Emulate Xen's workaround when starting the + * timer in response to __HYPERVISOR_set_timer_op. + */ + if (linux_wa && + unlikely((int64_t)guest_abs < 0 || + (delta > 0 && (uint32_t) (delta >> 50) != 0))) { + delta = 100 * NSEC_PER_MSEC; + guest_abs = guest_now + delta; + } + /* * Avoid races with the old timer firing. Checking timer_expires * to avoid calling hrtimer_cancel() will only have false positives @@ -162,14 +248,12 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs, s64 delta_ atomic_set(&vcpu->arch.xen.timer_pending, 0); vcpu->arch.xen.timer_expires = guest_abs; - if (delta_ns <= 0) { + if (delta <= 0) xen_timer_callback(&vcpu->arch.xen.timer); - } else { - ktime_t ktime_now = ktime_get(); + else hrtimer_start(&vcpu->arch.xen.timer, - ktime_add_ns(ktime_now, delta_ns), + ktime_add_ns(kernel_now, delta), HRTIMER_MODE_ABS_HARD); - } } static void kvm_xen_stop_timer(struct kvm_vcpu *vcpu) @@ -997,9 +1081,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) /* Start the timer if the new value has a valid vector+expiry. */ if (data->u.timer.port && data->u.timer.expires_ns) - kvm_xen_start_timer(vcpu, data->u.timer.expires_ns, - data->u.timer.expires_ns - - get_kvmclock_ns(vcpu->kvm)); + kvm_xen_start_timer(vcpu, data->u.timer.expires_ns, false); r = 0; break; @@ -1472,7 +1554,6 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd, { struct vcpu_set_singleshot_timer oneshot; struct x86_exception e; - s64 delta; if (!kvm_xen_timer_enabled(vcpu)) return false; @@ -1506,9 +1587,7 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd, return true; } - /* A delta <= 0 results in an immediate callback, which is what we want */ - delta = oneshot.timeout_abs_ns - get_kvmclock_ns(vcpu->kvm); - kvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, delta); + kvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, false); *r = 0; return true; @@ -1531,29 +1610,10 @@ static bool kvm_xen_hcall_set_timer_op(struct kvm_vcpu *vcpu, uint64_t timeout, if (!kvm_xen_timer_enabled(vcpu)) return false; - if (timeout) { - uint64_t guest_now = get_kvmclock_ns(vcpu->kvm); - int64_t delta = timeout - guest_now; - - /* Xen has a 'Linux workaround' in do_set_timer_op() which - * checks for negative absolute timeout values (caused by - * integer overflow), and for values about 13 days in the - * future (2^50ns) which would be caused by jiffies - * overflow. For those cases, it sets the timeout 100ms in - * the future (not *too* soon, since if a guest really did - * set a long timeout on purpose we don't want to keep - * churning CPU time by waking it up). - */ - if (unlikely((int64_t)timeout < 0 || - (delta > 0 && (uint32_t) (delta >> 50) != 0))) { - delta = 100 * NSEC_PER_MSEC; - timeout = guest_now + delta; - } - - kvm_xen_start_timer(vcpu, timeout, delta); - } else { + if (timeout) + kvm_xen_start_timer(vcpu, timeout, true); + else kvm_xen_stop_timer(vcpu); - } *r = 0; return true; From 8e62bf2bfa46367e14d0ffdcde5aada08759497c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Feb 2024 11:49:16 +0000 Subject: [PATCH 658/814] KVM: x86/xen: inject vCPU upcall vector when local APIC is enabled Linux guests since commit b1c3497e604d ("x86/xen: Add support for HVMOP_set_evtchn_upcall_vector") in v6.0 onwards will use the per-vCPU upcall vector when it's advertised in the Xen CPUID leaves. This upcall is injected through the guest's local APIC as an MSI, unlike the older system vector which was merely injected by the hypervisor any time the CPU was able to receive an interrupt and the upcall_pending flags is set in its vcpu_info. Effectively, that makes the per-CPU upcall edge triggered instead of level triggered, which results in the upcall being lost if the MSI is delivered when the local APIC is *disabled*. Xen checks the vcpu_info->evtchn_upcall_pending flag when the local APIC for a vCPU is software enabled (in fact, on any write to the SPIV register which doesn't disable the APIC). Do the same in KVM since KVM doesn't provide a way for userspace to intervene and trap accesses to the SPIV register of a local APIC emulated by KVM. Fixes: fde0451be8fb3 ("KVM: x86/xen: Support per-vCPU event channel upcall via local APIC") Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240227115648.3104-3-dwmw2@infradead.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 5 ++++- arch/x86/kvm/xen.c | 2 +- arch/x86/kvm/xen.h | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 3242f3da2457..75bc7d3f0022 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -41,6 +41,7 @@ #include "ioapic.h" #include "trace.h" #include "x86.h" +#include "xen.h" #include "cpuid.h" #include "hyperv.h" #include "smm.h" @@ -499,8 +500,10 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) } /* Check if there are APF page ready requests pending */ - if (enabled) + if (enabled) { kvm_make_request(KVM_REQ_APF_READY, apic->vcpu); + kvm_xen_sw_enable_lapic(apic->vcpu); + } } static inline void kvm_apic_set_xapic_id(struct kvm_lapic *apic, u8 id) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 8a4c563e2398..5c24c92588cf 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -567,7 +567,7 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) kvm_xen_update_runstate_guest(v, state == RUNSTATE_runnable); } -static void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) +void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) { struct kvm_lapic_irq irq = { }; int r; diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h index f8f1fe22d090..f5841d9000ae 100644 --- a/arch/x86/kvm/xen.h +++ b/arch/x86/kvm/xen.h @@ -18,6 +18,7 @@ extern struct static_key_false_deferred kvm_xen_enabled; int __kvm_xen_has_interrupt(struct kvm_vcpu *vcpu); void kvm_xen_inject_pending_events(struct kvm_vcpu *vcpu); +void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *vcpu); int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data); int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data); int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data); @@ -36,6 +37,19 @@ int kvm_xen_setup_evtchn(struct kvm *kvm, const struct kvm_irq_routing_entry *ue); void kvm_xen_update_tsc_info(struct kvm_vcpu *vcpu); +static inline void kvm_xen_sw_enable_lapic(struct kvm_vcpu *vcpu) +{ + /* + * The local APIC is being enabled. If the per-vCPU upcall vector is + * set and the vCPU's evtchn_upcall_pending flag is set, inject the + * interrupt. + */ + if (static_branch_unlikely(&kvm_xen_enabled.key) && + vcpu->arch.xen.vcpu_info_cache.active && + vcpu->arch.xen.upcall_vector && __kvm_xen_has_interrupt(vcpu)) + kvm_xen_inject_vcpu_vector(vcpu); +} + static inline bool kvm_xen_msr_enabled(struct kvm *kvm) { return static_branch_unlikely(&kvm_xen_enabled.key) && @@ -101,6 +115,10 @@ static inline void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) { } +static inline void kvm_xen_sw_enable_lapic(struct kvm_vcpu *vcpu) +{ +} + static inline bool kvm_xen_msr_enabled(struct kvm *kvm) { return false; From 66e3cf729b1ea017cad643415ade319556862b68 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Feb 2024 11:49:17 +0000 Subject: [PATCH 659/814] KVM: x86/xen: remove WARN_ON_ONCE() with false positives in evtchn delivery The kvm_xen_inject_vcpu_vector() function has a comment saying "the fast version will always work for physical unicast", justifying its use of kvm_irq_delivery_to_apic_fast() and the WARN_ON_ONCE() when that fails. In fact that assumption isn't true if X2APIC isn't in use by the guest and there is (8-bit x)APIC ID aliasing. A single "unicast" destination APIC ID *may* then be delivered to multiple vCPUs. Remove the warning, and in fact it might as well just call kvm_irq_delivery_to_apic(). Reported-by: Michal Luczaj Fixes: fde0451be8fb3 ("KVM: x86/xen: Support per-vCPU event channel upcall via local APIC") Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://lore.kernel.org/r/20240227115648.3104-4-dwmw2@infradead.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 5c24c92588cf..54c4ced96b69 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -10,7 +10,7 @@ #include "x86.h" #include "xen.h" #include "hyperv.h" -#include "lapic.h" +#include "irq.h" #include #include @@ -570,7 +570,6 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) { struct kvm_lapic_irq irq = { }; - int r; irq.dest_id = v->vcpu_id; irq.vector = v->arch.xen.upcall_vector; @@ -579,8 +578,7 @@ void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) irq.delivery_mode = APIC_DM_FIXED; irq.level = 1; - /* The fast version will always work for physical unicast */ - WARN_ON_ONCE(!kvm_irq_delivery_to_apic_fast(v->kvm, NULL, &irq, &r, NULL)); + kvm_irq_delivery_to_apic(v->kvm, NULL, &irq, NULL); } /* From 6addfcf27139da1356493f2a440af1252b5b7dbe Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Feb 2024 11:49:18 +0000 Subject: [PATCH 660/814] KVM: pfncache: simplify locking and make more self-contained MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The locking on the gfn_to_pfn_cache is... interesting. And awful. There is a rwlock in ->lock which readers take to ensure protection against concurrent changes. But __kvm_gpc_refresh() makes assumptions that certain fields will not change even while it drops the write lock and performs MM operations to revalidate the target PFN and kernel mapping. Commit 93984f19e7bc ("KVM: Fully serialize gfn=>pfn cache refresh via mutex") partly addressed that — not by fixing it, but by adding a new mutex, ->refresh_lock. This prevented concurrent __kvm_gpc_refresh() calls on a given gfn_to_pfn_cache, but is still only a partial solution. There is still a theoretical race where __kvm_gpc_refresh() runs in parallel with kvm_gpc_deactivate(). While __kvm_gpc_refresh() has dropped the write lock, kvm_gpc_deactivate() clears the ->active flag and unmaps ->khva. Then __kvm_gpc_refresh() determines that the previous ->pfn and ->khva are still valid, and reinstalls those values into the structure. This leaves the gfn_to_pfn_cache with the ->valid bit set, but ->active clear. And a ->khva which looks like a reasonable kernel address but is actually unmapped. All it takes is a subsequent reactivation to cause that ->khva to be dereferenced. This would theoretically cause an oops which would look something like this: [1724749.564994] BUG: unable to handle page fault for address: ffffaa3540ace0e0 [1724749.565039] RIP: 0010:__kvm_xen_has_interrupt+0x8b/0xb0 I say "theoretically" because theoretically, that oops that was seen in production cannot happen. The code which uses the gfn_to_pfn_cache is supposed to have its *own* locking, to further paper over the fact that the gfn_to_pfn_cache's own papering-over (->refresh_lock) of its own rwlock abuse is not sufficient. For the Xen vcpu_info that external lock is the vcpu->mutex, and for the shared info it's kvm->arch.xen.xen_lock. Those locks ought to protect the gfn_to_pfn_cache against concurrent deactivation vs. refresh in all but the cases where the vcpu or kvm object is being *destroyed*, in which case the subsequent reactivation should never happen. Theoretically. Nevertheless, this locking abuse is awful and should be fixed, even if no clear explanation can be found for how the oops happened. So expand the use of the ->refresh_lock mutex to ensure serialization of activate/deactivate vs. refresh and make the pfncache locking entirely self-sufficient. This means that a future commit can simplify the locking in the callers, such as the Xen emulation code which has an outstanding problem with recursive locking of kvm->arch.xen.xen_lock, which will no longer be necessary. The rwlock abuse described above is still not best practice, although it's harmless now that the ->refresh_lock is held for the entire duration while the offending code drops the write lock, does some other stuff, then takes the write lock again and assumes nothing changed. That can also be fixed^W cleaned up in a subsequent commit, but this commit is a simpler basis for the Xen deadlock fix mentioned above. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://lore.kernel.org/r/20240227115648.3104-5-dwmw2@infradead.org [sean: use guard(mutex) to fix a missed unlock] Signed-off-by: Sean Christopherson --- virt/kvm/pfncache.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 9ac8c9da4eda..4e07112a24c2 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -256,12 +256,7 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned l if (page_offset + len > PAGE_SIZE) return -EINVAL; - /* - * If another task is refreshing the cache, wait for it to complete. - * There is no guarantee that concurrent refreshes will see the same - * gpa, memslots generation, etc..., so they must be fully serialized. - */ - mutex_lock(&gpc->refresh_lock); + lockdep_assert_held(&gpc->refresh_lock); write_lock_irq(&gpc->lock); @@ -347,8 +342,6 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned l out_unlock: write_unlock_irq(&gpc->lock); - mutex_unlock(&gpc->refresh_lock); - if (unmap_old) gpc_unmap(old_pfn, old_khva); @@ -357,13 +350,16 @@ out_unlock: int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, unsigned long len) { + unsigned long uhva; + + guard(mutex)(&gpc->refresh_lock); + /* * If the GPA is valid then ignore the HVA, as a cache can be GPA-based * or HVA-based, not both. For GPA-based caches, the HVA will be * recomputed during refresh if necessary. */ - unsigned long uhva = kvm_is_error_gpa(gpc->gpa) ? gpc->uhva : - KVM_HVA_ERR_BAD; + uhva = kvm_is_error_gpa(gpc->gpa) ? gpc->uhva : KVM_HVA_ERR_BAD; return __kvm_gpc_refresh(gpc, gpc->gpa, uhva, len); } @@ -377,6 +373,7 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm) gpc->pfn = KVM_PFN_ERR_FAULT; gpc->gpa = INVALID_GPA; gpc->uhva = KVM_HVA_ERR_BAD; + gpc->active = gpc->valid = false; } static int __kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long uhva, @@ -384,6 +381,8 @@ static int __kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned { struct kvm *kvm = gpc->kvm; + guard(mutex)(&gpc->refresh_lock); + if (!gpc->active) { if (KVM_BUG_ON(gpc->valid, kvm)) return -EIO; @@ -420,6 +419,8 @@ void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) kvm_pfn_t old_pfn; void *old_khva; + guard(mutex)(&gpc->refresh_lock); + if (gpc->active) { /* * Deactivate the cache before removing it from the list, KVM From 7a36d680658ba5a0d350f2ad275b97156b8d4333 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Feb 2024 11:49:19 +0000 Subject: [PATCH 661/814] KVM: x86/xen: fix recursive deadlock in timer injection The fast-path timer delivery introduced a recursive locking deadlock when userspace configures a timer which has already expired and is delivered immediately. The call to kvm_xen_inject_timer_irqs() can call to kvm_xen_set_evtchn() which may take kvm->arch.xen.xen_lock, which is already held in kvm_xen_vcpu_get_attr(). ============================================ WARNING: possible recursive locking detected 6.8.0-smp--5e10b4d51d77-drs #232 Tainted: G O -------------------------------------------- xen_shinfo_test/250013 is trying to acquire lock: ffff938c9930cc30 (&kvm->arch.xen.xen_lock){+.+.}-{3:3}, at: kvm_xen_set_evtchn+0x74/0x170 [kvm] but task is already holding lock: ffff938c9930cc30 (&kvm->arch.xen.xen_lock){+.+.}-{3:3}, at: kvm_xen_vcpu_get_attr+0x38/0x250 [kvm] Now that the gfn_to_pfn_cache has its own self-sufficient locking, its callers no longer need to ensure serialization, so just stop taking kvm->arch.xen.xen_lock from kvm_xen_set_evtchn(). Fixes: 77c9b9dea4fb ("KVM: x86/xen: Use fast path for Xen timer delivery") Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://lore.kernel.org/r/20240227115648.3104-6-dwmw2@infradead.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 54c4ced96b69..f65b35a05d91 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1862,8 +1862,6 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm) mm_borrowed = true; } - mutex_lock(&kvm->arch.xen.xen_lock); - /* * It is theoretically possible for the page to be unmapped * and the MMU notifier to invalidate the shared_info before @@ -1891,8 +1889,6 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm) srcu_read_unlock(&kvm->srcu, idx); } while(!rc); - mutex_unlock(&kvm->arch.xen.xen_lock); - if (mm_borrowed) kthread_unuse_mm(kvm->mm); From 7cfc8db2c0cc1f79a979a159f0f56bcf25256e81 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 26 Feb 2024 22:26:23 +0100 Subject: [PATCH 662/814] dt-bindings: pinctrl: fsl,imx6ul-pinctrl: convert to YAML Convert i.MX6UL pinctrl bindings to YAML. Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240226212740.2019837-2-sre@kernel.org Signed-off-by: Rob Herring --- .../bindings/pinctrl/fsl,imx6ul-pinctrl.txt | 37 ------ .../bindings/pinctrl/fsl,imx6ul-pinctrl.yaml | 116 ++++++++++++++++++ 2 files changed, 116 insertions(+), 37 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt deleted file mode 100644 index 7ca4f6118d9a..000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt +++ /dev/null @@ -1,37 +0,0 @@ -* Freescale i.MX6 UltraLite IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6ul-iomuxc" for main IOMUX controller or - "fsl,imx6ull-iomuxc-snvs" for i.MX 6ULL's SNVS IOMUX controller. -- fsl,pins: each entry consists of 6 integers and represents the mux and config - setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in - imx6ul-pinfunc.h under device tree source folder. The last integer CONFIG is - the pad setting value like pull-up on this pin. Please refer to i.MX6 UltraLite - Reference Manual for detailed CONFIG settings. - -CONFIG bits definition: -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (0 << 6) -PAD_CTL_SPEED_MED (1 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_260ohm (1 << 3) -PAD_CTL_DSE_130ohm (2 << 3) -PAD_CTL_DSE_87ohm (3 << 3) -PAD_CTL_DSE_65ohm (4 << 3) -PAD_CTL_DSE_52ohm (5 << 3) -PAD_CTL_DSE_43ohm (6 << 3) -PAD_CTL_DSE_37ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml new file mode 100644 index 000000000000..906b264a9e3c --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/fsl,imx6ul-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale IMX6UL IOMUX Controller + +maintainers: + - Dong Aisheng + +description: + Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory + for common binding part and usage. + +allOf: + - $ref: pinctrl.yaml# + +properties: + compatible: + enum: + - fsl,imx6ul-iomuxc + - fsl,imx6ull-iomuxc-snvs + + reg: + maxItems: 1 + +# Client device subnode's properties +patternProperties: + 'grp$': + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + + properties: + fsl,pins: + description: + each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can + be found in . The last integer + CONFIG is the pad setting value like pull-up on this pin. Please + refer to i.MX6UL Reference Manual for detailed CONFIG settings. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: | + "mux_reg" indicates the offset of mux register. + - description: | + "conf_reg" indicates the offset of pad configuration register. + - description: | + "input_reg" indicates the offset of select input register. + - description: | + "mux_val" indicates the mux value to be applied. + - description: | + "input_val" indicates the select input value to be applied. + - description: | + "pad_setting" indicates the pad configuration value to be applied: + PAD_CTL_HYS (1 << 16) + PAD_CTL_PUS_100K_DOWN (0 << 14) + PAD_CTL_PUS_47K_UP (1 << 14) + PAD_CTL_PUS_100K_UP (2 << 14) + PAD_CTL_PUS_22K_UP (3 << 14) + PAD_CTL_PUE (1 << 13) + PAD_CTL_PKE (1 << 12) + PAD_CTL_ODE (1 << 11) + PAD_CTL_SPEED_LOW (0 << 6) + PAD_CTL_SPEED_MED (1 << 6) + PAD_CTL_SPEED_HIGH (3 << 6) + PAD_CTL_DSE_DISABLE (0 << 3) + PAD_CTL_DSE_260ohm (1 << 3) + PAD_CTL_DSE_130ohm (2 << 3) + PAD_CTL_DSE_87ohm (3 << 3) + PAD_CTL_DSE_65ohm (4 << 3) + PAD_CTL_DSE_52ohm (5 << 3) + PAD_CTL_DSE_43ohm (6 << 3) + PAD_CTL_DSE_37ohm (7 << 3) + PAD_CTL_SRE_FAST (1 << 0) + PAD_CTL_SRE_SLOW (0 << 0) + + required: + - fsl,pins + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + iomuxc: pinctrl@20e0000 { + compatible = "fsl,imx6ul-iomuxc"; + reg = <0x020e0000 0x4000>; + + mux_uart: uartgrp { + fsl,pins = < + 0x0084 0x0310 0x0000 0 0 0x1b0b1 + 0x0088 0x0314 0x0624 0 3 0x1b0b1 + >; + }; + }; + - | + iomuxc_snvs: pinctrl@2290000 { + compatible = "fsl,imx6ull-iomuxc-snvs"; + reg = <0x02290000 0x4000>; + + pinctrl_snvs_usbc_det: snvsusbcdetgrp { + fsl,pins = < + 0x0010 0x0054 0x0000 0x5 0x0 0x130b0 + >; + }; + }; From b6376606971a604a3f6ef8a85e21a6aad85000eb Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 26 Feb 2024 22:26:24 +0100 Subject: [PATCH 663/814] dt-bindings: input: touchscreen: fsl,imx6ul-tsc convert to YAML Convert the i.MX6UL touchscreen DT binding to YAML. Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Acked-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20240226212740.2019837-3-sre@kernel.org Signed-off-by: Rob Herring --- .../input/touchscreen/fsl,imx6ul-tsc.yaml | 97 +++++++++++++++++++ .../bindings/input/touchscreen/imx6ul_tsc.txt | 38 -------- 2 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml b/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml new file mode 100644 index 000000000000..678756ad0f92 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/fsl,imx6ul-tsc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX6UL Touch Controller + +maintainers: + - Haibo Chen + - Shawn Guo + - Sascha Hauer + +properties: + compatible: + const: fsl,imx6ul-tsc + + reg: + items: + - description: touch controller address + - description: ADC2 address + + interrupts: + items: + - description: touch controller address + - description: ADC2 address + + clocks: + maxItems: 2 + + clock-names: + items: + - const: tsc + - const: adc + + xnur-gpios: + maxItems: 1 + description: + The X- gpio this controller connect to. This xnur-gpio returns to + low once the finger leave the touch screen (The last touch event + the touch controller capture). + + measure-delay-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The value of measure delay time. Before X-axis or Y-axis measurement, + the screen need some time before even potential distribution ready. + default: 0xffff + minimum: 0 + maximum: 0xffffff + + pre-charge-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The touch screen need some time to precharge. + default: 0xfff + minimum: 0 + maximum: 0xffffffff + + touchscreen-average-samples: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of data samples which are averaged for each read. + enum: [ 1, 4, 8, 16, 32 ] + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - xnur-gpios + +allOf: + - $ref: touchscreen.yaml# + +additionalProperties: false + +examples: + - | + #include + #include + #include + touchscreen@2040000 { + compatible = "fsl,imx6ul-tsc"; + reg = <0x02040000 0x4000>, <0x0219c000 0x4000>; + interrupts = , + ; + clocks = <&clks IMX6UL_CLK_IPG>, + <&clks IMX6UL_CLK_ADC2>; + clock-names = "tsc", "adc"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc>; + xnur-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + measure-delay-time = <0xfff>; + pre-charge-time = <0xffff>; + touchscreen-average-samples = <32>; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt deleted file mode 100644 index 164915004424..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Freescale i.MX6UL Touch Controller - -Required properties: -- compatible: must be "fsl,imx6ul-tsc". -- reg: this touch controller address and the ADC2 address. -- interrupts: the interrupt of this touch controller and ADC2. -- clocks: the root clock of touch controller and ADC2. -- clock-names; must be "tsc" and "adc". -- xnur-gpio: the X- gpio this controller connect to. - This xnur-gpio returns to low once the finger leave the touch screen (The - last touch event the touch controller capture). - -Optional properties: -- measure-delay-time: the value of measure delay time. - Before X-axis or Y-axis measurement, the screen need some time before - even potential distribution ready. - This value depends on the touch screen. -- pre-charge-time: the touch screen need some time to precharge. - This value depends on the touch screen. -- touchscreen-average-samples: Number of data samples which are averaged for - each read. Valid values are 1, 4, 8, 16 and 32. - -Example: - tsc: tsc@2040000 { - compatible = "fsl,imx6ul-tsc"; - reg = <0x02040000 0x4000>, <0x0219c000 0x4000>; - interrupts = , - ; - clocks = <&clks IMX6UL_CLK_IPG>, - <&clks IMX6UL_CLK_ADC2>; - clock-names = "tsc", "adc"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_tsc>; - xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; - measure-delay-time = <0xfff>; - pre-charge-time = <0xffff>; - touchscreen-average-samples = <32>; - }; From 465c7756d1fffa2bae9f2c77498b1fcdd169d317 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 26 Feb 2024 22:26:25 +0100 Subject: [PATCH 664/814] dt-bindings: soc: imx: fsl,imx-anatop: add binding Add missing binding for i.MX anatop syscon. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240226212740.2019837-4-sre@kernel.org Signed-off-by: Rob Herring --- .../bindings/soc/imx/fsl,imx-anatop.yaml | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml new file mode 100644 index 000000000000..5a59e3470510 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/imx/fsl,imx-anatop.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ANATOP register + +maintainers: + - Shawn Guo + - Sascha Hauer + +properties: + compatible: + oneOf: + - items: + - enum: + - fsl,imx6sl-anatop + - fsl,imx6sll-anatop + - fsl,imx6sx-anatop + - fsl,imx6ul-anatop + - fsl,imx7d-anatop + - const: fsl,imx6q-anatop + - const: syscon + - const: simple-mfd + - items: + - const: fsl,imx6q-anatop + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + interrupts: + items: + - description: Temperature sensor event + - description: Brown-out event on either of the support regulators + - description: Brown-out event on either the core, gpu or soc regulators + + tempmon: + type: object + unevaluatedProperties: false + $ref: /schemas/thermal/imx-thermal.yaml + +patternProperties: + "regulator-((3p0)|(vddcore)|(vddsoc))$": + type: object + unevaluatedProperties: false + $ref: /schemas/regulator/anatop-regulator.yaml + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + + anatop: anatop@20c8000 { + compatible = "fsl,imx6ul-anatop", "fsl,imx6q-anatop", + "syscon", "simple-mfd"; + reg = <0x020c8000 0x1000>; + interrupts = , + , + ; + + reg_3p0: regulator-3p0 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vdd3p0"; + regulator-min-microvolt = <2625000>; + regulator-max-microvolt = <3400000>; + anatop-reg-offset = <0x120>; + anatop-vol-bit-shift = <8>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <0>; + anatop-min-voltage = <2625000>; + anatop-max-voltage = <3400000>; + anatop-enable-bit = <0>; + }; + + reg_arm: regulator-vddcore { + compatible = "fsl,anatop-regulator"; + regulator-name = "cpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <0>; + anatop-vol-bit-width = <5>; + anatop-delay-reg-offset = <0x170>; + anatop-delay-bit-shift = <24>; + anatop-delay-bit-width = <2>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; + }; + + reg_soc: regulator-vddsoc { + compatible = "fsl,anatop-regulator"; + regulator-name = "vddsoc"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <18>; + anatop-vol-bit-width = <5>; + anatop-delay-reg-offset = <0x170>; + anatop-delay-bit-shift = <28>; + anatop-delay-bit-width = <2>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; + }; + + tempmon: tempmon { + compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon"; + interrupt-parent = <&gpc>; + interrupts = ; + fsl,tempmon = <&anatop>; + nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; + nvmem-cell-names = "calib", "temp_grade"; + clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>; + #thermal-sensor-cells = <0>; + }; + }; From bd9cf5b11fd20e1c5774ef2d95023daf1b90f0c3 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 26 Feb 2024 22:26:26 +0100 Subject: [PATCH 665/814] dt-bindings: soc: imx: fsl,imx-iomuxc-gpr: add imx6 Add compatibles used by different i.MX6 variants to the i.MX IOMUX Controller GPR binding. Acked-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240226212740.2019837-5-sre@kernel.org Signed-off-by: Rob Herring --- .../bindings/soc/imx/fsl,imx-iomuxc-gpr.yaml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx-iomuxc-gpr.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx-iomuxc-gpr.yaml index 1da1b758b4ae..8451cb4dd87c 100644 --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx-iomuxc-gpr.yaml +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx-iomuxc-gpr.yaml @@ -17,7 +17,23 @@ properties: compatible: oneOf: - items: - - const: fsl,imx8mq-iomuxc-gpr + - enum: + - fsl,imx6q-iomuxc-gpr + - fsl,imx8mq-iomuxc-gpr + - const: syscon + - const: simple-mfd + - items: + - enum: + - fsl,imx6sl-iomuxc-gpr + - fsl,imx6sll-iomuxc-gpr + - fsl,imx6ul-iomuxc-gpr + - const: fsl,imx6q-iomuxc-gpr + - const: syscon + - items: + - enum: + - fsl,imx6sx-iomuxc-gpr + - fsl,imx7d-iomuxc-gpr + - const: fsl,imx6q-iomuxc-gpr - const: syscon - const: simple-mfd - items: From 4bfb270378c995773960fb0a8c908fc009607a1b Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 26 Feb 2024 22:26:27 +0100 Subject: [PATCH 666/814] dt-bindings: fsl-imx-sdma: fix HDMI audio index HDMI Audio has been added to the DT binding documentation with an incorrect index. DT and the driver use index 26. This happened, because the binding is missing MULTI_SAI type, which is using index 25. Reported-by: Michael Yackavage Fixes: 7bdbd87d4008 ("dt-bindings: fsl-imx-sdma: Convert imx sdma to DT schema") Acked-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240226212740.2019837-6-sre@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml b/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml index b95dd8db5a30..37135fa024f9 100644 --- a/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml @@ -92,7 +92,8 @@ properties: description: needs firmware more than ver 2 - Shared ASRC: 23 - SAI: 24 - - HDMI Audio: 25 + - Multi SAI: 25 + - HDMI Audio: 26 The third cell: transfer priority ID enum: From b0f3f9ab419c243389da6c0dd6a9db0eea560146 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 Feb 2024 13:29:34 +0100 Subject: [PATCH 667/814] dt-bindings: input: allwinner,sun4i-a10-lrad: drop redundant type from label dtschema defines label as string, so $ref in other bindings is redundant. Signed-off-by: Krzysztof Kozlowski Acked-by: Jernej Skrabec Acked-by: Rob Herring Link: https://lore.kernel.org/r/20240226122934.89257-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- .../bindings/input/allwinner,sun4i-a10-lradc-keys.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml index 5efceb313879..c384bf0bb25d 100644 --- a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml +++ b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml @@ -49,7 +49,6 @@ patternProperties: $ref: input.yaml# properties: label: - $ref: /schemas/types.yaml#/definitions/string description: Descriptive name of the key linux,code: true From e9da6f08edb0bd4c621165496778d77a222e1174 Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Mon, 26 Feb 2024 17:57:16 -0800 Subject: [PATCH 668/814] KVM: selftests: Explicitly close guest_memfd files in some gmem tests Explicitly close() guest_memfd files in various guest_memfd and private_mem_conversions tests, there's no reason to keep the files open until the test exits. Fixes: 8a89efd43423 ("KVM: selftests: Add basic selftest for guest_memfd()") Fixes: 43f623f350ce ("KVM: selftests: Add x86-only selftest for private memory conversions") Signed-off-by: Dongli Zhang Link: https://lore.kernel.org/r/20240227015716.27284-1-dongli.zhang@oracle.com [sean: massage changelog] Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/guest_memfd_test.c | 3 +++ .../selftests/kvm/x86_64/private_mem_conversions_test.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index c78a98c1a915..92eae206baa6 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -167,6 +167,9 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) TEST_ASSERT(ret != -1, "memfd fstat should succeed"); TEST_ASSERT(st1.st_size == 4096, "first memfd st_size should still match requested size"); TEST_ASSERT(st1.st_ino != st2.st_ino, "different memfd should have different inode numbers"); + + close(fd2); + close(fd1); } int main(int argc, char *argv[]) diff --git a/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c index 65ad38b6be1f..e0f642d2a3c4 100644 --- a/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c +++ b/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c @@ -434,6 +434,8 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t r = fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size); TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r)); + + close(memfd); } static void usage(const char *cmd) From fd94213e1417d28b933d4a3d41ad02eac1b29ec2 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Thu, 29 Feb 2024 09:11:52 +0000 Subject: [PATCH 669/814] hisi_acc_vfio_pci: Remove the deferred_reset logic The deferred_reset logic was added to vfio migration drivers to prevent a circular locking dependency with respect to mm_lock and state mutex. This is mainly because of the copy_to/from_user() functions(which takes mm_lock) invoked under state mutex. But for HiSilicon driver, the only place where we now hold the state mutex for copy_to_user is during the PRE_COPY IOCTL. So for pre_copy, release the lock as soon as we have updated the data and perform copy_to_user without state mutex. By this, we can get rid of the deferred_reset logic. Link: https://lore.kernel.org/kvm/20240220132459.GM13330@nvidia.com/ Signed-off-by: Shameer Kolothum Reviewed-by: Brett Creeley Reviewed-by: Kevin Tian Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20240229091152.56664-1-shameerali.kolothum.thodi@huawei.com Signed-off-by: Alex Williamson --- .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 48 +++++-------------- .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 6 +-- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c index 4d27465c8f1a..9a3e97108ace 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c @@ -630,25 +630,11 @@ static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vde } } -/* - * This function is called in all state_mutex unlock cases to - * handle a 'deferred_reset' if exists. - */ -static void -hisi_acc_vf_state_mutex_unlock(struct hisi_acc_vf_core_device *hisi_acc_vdev) +static void hisi_acc_vf_reset(struct hisi_acc_vf_core_device *hisi_acc_vdev) { -again: - spin_lock(&hisi_acc_vdev->reset_lock); - if (hisi_acc_vdev->deferred_reset) { - hisi_acc_vdev->deferred_reset = false; - spin_unlock(&hisi_acc_vdev->reset_lock); - hisi_acc_vdev->vf_qm_state = QM_NOT_READY; - hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING; - hisi_acc_vf_disable_fds(hisi_acc_vdev); - goto again; - } - mutex_unlock(&hisi_acc_vdev->state_mutex); - spin_unlock(&hisi_acc_vdev->reset_lock); + hisi_acc_vdev->vf_qm_state = QM_NOT_READY; + hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING; + hisi_acc_vf_disable_fds(hisi_acc_vdev); } static void hisi_acc_vf_start_device(struct hisi_acc_vf_core_device *hisi_acc_vdev) @@ -804,8 +790,10 @@ static long hisi_acc_vf_precopy_ioctl(struct file *filp, info.dirty_bytes = 0; info.initial_bytes = migf->total_length - *pos; + mutex_unlock(&migf->lock); + mutex_unlock(&hisi_acc_vdev->state_mutex); - ret = copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; out: mutex_unlock(&migf->lock); mutex_unlock(&hisi_acc_vdev->state_mutex); @@ -1071,7 +1059,7 @@ hisi_acc_vfio_pci_set_device_state(struct vfio_device *vdev, break; } } - hisi_acc_vf_state_mutex_unlock(hisi_acc_vdev); + mutex_unlock(&hisi_acc_vdev->state_mutex); return res; } @@ -1092,7 +1080,7 @@ hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev, mutex_lock(&hisi_acc_vdev->state_mutex); *curr_state = hisi_acc_vdev->mig_state; - hisi_acc_vf_state_mutex_unlock(hisi_acc_vdev); + mutex_unlock(&hisi_acc_vdev->state_mutex); return 0; } @@ -1104,21 +1092,9 @@ static void hisi_acc_vf_pci_aer_reset_done(struct pci_dev *pdev) VFIO_MIGRATION_STOP_COPY) return; - /* - * As the higher VFIO layers are holding locks across reset and using - * those same locks with the mm_lock we need to prevent ABBA deadlock - * with the state_mutex and mm_lock. - * In case the state_mutex was taken already we defer the cleanup work - * to the unlock flow of the other running context. - */ - spin_lock(&hisi_acc_vdev->reset_lock); - hisi_acc_vdev->deferred_reset = true; - if (!mutex_trylock(&hisi_acc_vdev->state_mutex)) { - spin_unlock(&hisi_acc_vdev->reset_lock); - return; - } - spin_unlock(&hisi_acc_vdev->reset_lock); - hisi_acc_vf_state_mutex_unlock(hisi_acc_vdev); + mutex_lock(&hisi_acc_vdev->state_mutex); + hisi_acc_vf_reset(hisi_acc_vdev); + mutex_unlock(&hisi_acc_vdev->state_mutex); } static int hisi_acc_vf_qm_init(struct hisi_acc_vf_core_device *hisi_acc_vdev) diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h index dcabfeec6ca1..5bab46602fad 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h @@ -98,8 +98,8 @@ struct hisi_acc_vf_migration_file { struct hisi_acc_vf_core_device { struct vfio_pci_core_device core_device; - u8 match_done:1; - u8 deferred_reset:1; + u8 match_done; + /* For migration state */ struct mutex state_mutex; enum vfio_device_mig_state mig_state; @@ -109,8 +109,6 @@ struct hisi_acc_vf_core_device { struct hisi_qm vf_qm; u32 vf_qm_state; int vf_id; - /* For reset handler */ - spinlock_t reset_lock; struct hisi_acc_vf_migration_file *resuming_migf; struct hisi_acc_vf_migration_file *saving_migf; }; From 1f92d6a7c65f390617463532b408030a5a168097 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Fri, 1 Mar 2024 14:51:47 -0300 Subject: [PATCH 670/814] vfio/mdpy: make mdpy_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the mdpy_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240301-class_cleanup-vfio-v1-1-9236d69083f5@marliere.net Signed-off-by: Alex Williamson --- samples/vfio-mdev/mdpy.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index 72ea5832c927..27795501de6e 100644 --- a/samples/vfio-mdev/mdpy.c +++ b/samples/vfio-mdev/mdpy.c @@ -84,7 +84,9 @@ static struct mdev_type *mdpy_mdev_types[] = { }; static dev_t mdpy_devt; -static struct class *mdpy_class; +static const struct class mdpy_class = { + .name = MDPY_CLASS_NAME, +}; static struct cdev mdpy_cdev; static struct device mdpy_dev; static struct mdev_parent mdpy_parent; @@ -709,13 +711,10 @@ static int __init mdpy_dev_init(void) if (ret) goto err_cdev; - mdpy_class = class_create(MDPY_CLASS_NAME); - if (IS_ERR(mdpy_class)) { - pr_err("Error: failed to register mdpy_dev class\n"); - ret = PTR_ERR(mdpy_class); + ret = class_register(&mdpy_class); + if (ret) goto err_driver; - } - mdpy_dev.class = mdpy_class; + mdpy_dev.class = &mdpy_class; mdpy_dev.release = mdpy_device_release; dev_set_name(&mdpy_dev, "%s", MDPY_NAME); @@ -735,7 +734,7 @@ err_device: device_del(&mdpy_dev); err_put: put_device(&mdpy_dev); - class_destroy(mdpy_class); + class_unregister(&mdpy_class); err_driver: mdev_unregister_driver(&mdpy_driver); err_cdev: @@ -753,8 +752,7 @@ static void __exit mdpy_dev_exit(void) mdev_unregister_driver(&mdpy_driver); cdev_del(&mdpy_cdev); unregister_chrdev_region(mdpy_devt, MINORMASK + 1); - class_destroy(mdpy_class); - mdpy_class = NULL; + class_unregister(&mdpy_class); } module_param_named(count, mdpy_driver.max_instances, int, 0444); From 626f534d774caaccd6861fbccee45a1a6a8781b3 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Fri, 1 Mar 2024 14:51:48 -0300 Subject: [PATCH 671/814] vfio/mbochs: make mbochs_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the mbochs_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240301-class_cleanup-vfio-v1-2-9236d69083f5@marliere.net Signed-off-by: Alex Williamson --- samples/vfio-mdev/mbochs.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index 93405264ff23..9062598ea03d 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -133,7 +133,9 @@ static struct mdev_type *mbochs_mdev_types[] = { }; static dev_t mbochs_devt; -static struct class *mbochs_class; +static const struct class mbochs_class = { + .name = MBOCHS_CLASS_NAME, +}; static struct cdev mbochs_cdev; static struct device mbochs_dev; static struct mdev_parent mbochs_parent; @@ -1422,13 +1424,10 @@ static int __init mbochs_dev_init(void) if (ret) goto err_cdev; - mbochs_class = class_create(MBOCHS_CLASS_NAME); - if (IS_ERR(mbochs_class)) { - pr_err("Error: failed to register mbochs_dev class\n"); - ret = PTR_ERR(mbochs_class); + ret = class_register(&mbochs_class); + if (ret) goto err_driver; - } - mbochs_dev.class = mbochs_class; + mbochs_dev.class = &mbochs_class; mbochs_dev.release = mbochs_device_release; dev_set_name(&mbochs_dev, "%s", MBOCHS_NAME); @@ -1448,7 +1447,7 @@ err_device: device_del(&mbochs_dev); err_put: put_device(&mbochs_dev); - class_destroy(mbochs_class); + class_unregister(&mbochs_class); err_driver: mdev_unregister_driver(&mbochs_driver); err_cdev: @@ -1466,8 +1465,7 @@ static void __exit mbochs_dev_exit(void) mdev_unregister_driver(&mbochs_driver); cdev_del(&mbochs_cdev); unregister_chrdev_region(mbochs_devt, MINORMASK + 1); - class_destroy(mbochs_class); - mbochs_class = NULL; + class_unregister(&mbochs_class); } MODULE_IMPORT_NS(DMA_BUF); From aebd3bd586c67a29ddbe7be7db06b45754477b52 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 6 Mar 2024 09:12:13 +0800 Subject: [PATCH 672/814] LoongArch: KVM: Set reserved bits as zero in CPUCFG Supported CPUCFG information comes from function _kvm_get_cpucfg_mask(). A bit should be zero if it is reserved by HW or if it is not supported by KVM. Also LoongArch software page table walk feature defined in CPUCFG2_LSPW is supported by KVM, it should be enabled by default. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/vcpu.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 36106922b5d7..3a8779065f73 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -304,11 +304,18 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v) return -EINVAL; switch (id) { - case 2: + case LOONGARCH_CPUCFG0: + *v = GENMASK(31, 0); + return 0; + case LOONGARCH_CPUCFG1: + /* CPUCFG1_MSGINT is not supported by KVM */ + *v = GENMASK(25, 0); + return 0; + case LOONGARCH_CPUCFG2: /* CPUCFG2 features unconditionally supported by KVM */ *v = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | CPUCFG2_FPVERS | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | - CPUCFG2_LAM; + CPUCFG2_LSPW | CPUCFG2_LAM; /* * For the ISA extensions listed below, if one is supported * by the host, then it is also supported by KVM. @@ -318,14 +325,26 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v) if (cpu_has_lasx) *v |= CPUCFG2_LASX; + return 0; + case LOONGARCH_CPUCFG3: + *v = GENMASK(16, 0); + return 0; + case LOONGARCH_CPUCFG4: + case LOONGARCH_CPUCFG5: + *v = GENMASK(31, 0); + return 0; + case LOONGARCH_CPUCFG16: + *v = GENMASK(16, 0); + return 0; + case LOONGARCH_CPUCFG17 ... LOONGARCH_CPUCFG20: + *v = GENMASK(30, 0); return 0; default: /* - * No restrictions on other valid CPUCFG IDs' values, but - * CPUCFG data is limited to 32 bits as the LoongArch ISA - * manual says (Volume 1, Section 2.2.10.5 "CPUCFG"). + * CPUCFG bits should be zero if reserved by HW or not + * supported by KVM. */ - *v = U32_MAX; + *v = 0; return 0; } } @@ -344,7 +363,7 @@ static int kvm_check_cpucfg(int id, u64 val) return -EINVAL; switch (id) { - case 2: + case LOONGARCH_CPUCFG2: if (!(val & CPUCFG2_LLFTP)) /* Guests must have a constant timer */ return -EINVAL; From 8bc15d02d5fdff31bfeca02e58e22e26880dde39 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 6 Mar 2024 09:12:13 +0800 Subject: [PATCH 673/814] LoongArch: KVM: Start SW timer only when vcpu is blocking SW timer is enabled when vcpu thread is scheduled out, and it is to wake up vcpu from blocked queue. If vcpu thread is scheduled out but is not blocked, such as it is preempted by other threads, it is not necessary to enable SW timer. Since vcpu thread is still on running queue if it is preempted and SW timer is only to wake up vcpu on blocking queue, so SW timer is not useful in this situation. This patch enables SW timer only when vcpu is scheduled out and is blocking. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/timer.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c index 111328f60872..b0dafe0611ab 100644 --- a/arch/loongarch/kvm/timer.c +++ b/arch/loongarch/kvm/timer.c @@ -93,7 +93,8 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu) /* * Freeze the soft-timer and sync the guest stable timer with it. */ - hrtimer_cancel(&vcpu->arch.swtimer); + if (kvm_vcpu_is_blocking(vcpu)) + hrtimer_cancel(&vcpu->arch.swtimer); /* * From LoongArch Reference Manual Volume 1 Chapter 7.6.2 @@ -168,26 +169,20 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu) * Here judge one-shot timer fired by checking whether TVAL is larger * than TCFG */ - if (ticks < cfg) { + if (ticks < cfg) delta = tick_to_ns(vcpu, ticks); - expire = ktime_add_ns(ktime_get(), delta); - vcpu->arch.expire = expire; + else + delta = 0; + + expire = ktime_add_ns(ktime_get(), delta); + vcpu->arch.expire = expire; + if (kvm_vcpu_is_blocking(vcpu)) { /* * HRTIMER_MODE_PINNED is suggested since vcpu may run in * the same physical cpu in next time */ hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED); - } else if (vcpu->stat.generic.blocking) { - /* - * Inject timer interrupt so that halt polling can dectect and exit. - * VCPU is scheduled out already and sleeps in rcuwait queue and - * will not poll pending events again. kvm_queue_irq() is not enough, - * hrtimer swtimer should be used here. - */ - expire = ktime_add_ns(ktime_get(), 10); - vcpu->arch.expire = expire; - hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED); } } From f66228053e429bd926505c447d3af2d3d610ed92 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 6 Mar 2024 09:12:13 +0800 Subject: [PATCH 674/814] LoongArch: KVM: Do not restart SW timer when it is expired LoongArch VCPUs have their own separate HW timers. SW timer is to wake up blocked vcpu thread, rather than HW timer emulation. When blocking vcpu scheduled out, SW timer is used to wakeup blocked vcpu thread and injects timer interrupt. It does not care about whether guest timer is in period mode or oneshot mode, and SW timer needs not to be restarted since vcpu has been woken. This patch does not restart SW timer when it is expired. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/timer.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c index b0dafe0611ab..bcc6b6d063d9 100644 --- a/arch/loongarch/kvm/timer.c +++ b/arch/loongarch/kvm/timer.c @@ -23,24 +23,6 @@ static inline u64 tick_to_ns(struct kvm_vcpu *vcpu, u64 tick) return div_u64(tick * MNSEC_PER_SEC, vcpu->arch.timer_mhz); } -/* - * Push timer forward on timeout. - * Handle an hrtimer event by push the hrtimer forward a period. - */ -static enum hrtimer_restart kvm_count_timeout(struct kvm_vcpu *vcpu) -{ - unsigned long cfg, period; - - /* Add periodic tick to current expire time */ - cfg = kvm_read_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG); - if (cfg & CSR_TCFG_PERIOD) { - period = tick_to_ns(vcpu, cfg & CSR_TCFG_VAL); - hrtimer_add_expires_ns(&vcpu->arch.swtimer, period); - return HRTIMER_RESTART; - } else - return HRTIMER_NORESTART; -} - /* Low level hrtimer wake routine */ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer) { @@ -50,7 +32,7 @@ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer) kvm_queue_irq(vcpu, INT_TI); rcuwait_wake_up(&vcpu->wait); - return kvm_count_timeout(vcpu); + return HRTIMER_NORESTART; } /* From b99f783106ea5b2f8c9d74f4d3b1e2f77af9ec6e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 6 Mar 2024 09:12:13 +0800 Subject: [PATCH 675/814] LoongArch: KVM: Remove unnecessary CSR register saving during enter guest Some CSR registers like CRMD/PRMD are saved during enter VM mode now. However they are not restored for actual use, so saving for these CSR registers can be removed. Reviewed-by: Tianrui Zhao Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/switch.S | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S index ba976509bfe8..3634431db18a 100644 --- a/arch/loongarch/kvm/switch.S +++ b/arch/loongarch/kvm/switch.S @@ -213,12 +213,6 @@ SYM_FUNC_START(kvm_enter_guest) /* Save host GPRs */ kvm_save_host_gpr a2 - /* Save host CRMD, PRMD to stack */ - csrrd a3, LOONGARCH_CSR_CRMD - st.d a3, a2, PT_CRMD - csrrd a3, LOONGARCH_CSR_PRMD - st.d a3, a2, PT_PRMD - addi.d a2, a1, KVM_VCPU_ARCH st.d sp, a2, KVM_ARCH_HSP st.d tp, a2, KVM_ARCH_HTP From 6caecacc92b9170fa3dd2e5a3b17eaf13cf30065 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 7 Mar 2024 00:08:30 +1100 Subject: [PATCH 676/814] powerpc/fsl: Fix mfpmr() asm constraint error mfpmr() needs to be marked always inline, otherwise the compiler will complain that the rn argument can't be passed to the asm block as an integer: arch/powerpc/include/asm/reg_fsl_emb.h:18:9: warning: 'asm' operand 1 probably does not match constraints 18 | asm (".machine push; " | ^~~ arch/powerpc/include/asm/reg_fsl_emb.h:18:9: error: impossible constraint in 'asm' Mark mtpmr() always inline also to avoid any future problems with it. Fixes: f01dbd73ccf1 ("powerpc/fsl: Modernise mt/mfpmr") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202403051835.iqLGz996-lkp@intel.com/ Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg_fsl_emb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h index b0563c30b062..9893d2001b68 100644 --- a/arch/powerpc/include/asm/reg_fsl_emb.h +++ b/arch/powerpc/include/asm/reg_fsl_emb.h @@ -11,7 +11,7 @@ #ifndef __ASSEMBLY__ /* Performance Monitor Registers */ -static inline unsigned int mfpmr(unsigned int rn) +static __always_inline unsigned int mfpmr(unsigned int rn) { unsigned int rval; @@ -24,7 +24,7 @@ static inline unsigned int mfpmr(unsigned int rn) return rval; } -static inline void mtpmr(unsigned int rn, unsigned int val) +static __always_inline void mtpmr(unsigned int rn, unsigned int val) { asm (".machine push; " ".machine e300; " From 35f20786c481d5ced9283ff42de5c69b65e5ed13 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 27 Jan 2024 11:07:43 -0700 Subject: [PATCH 677/814] powerpc: xor_vmx: Add '-mhard-float' to CFLAGS arch/powerpc/lib/xor_vmx.o is built with '-msoft-float' (from the main powerpc Makefile) and '-maltivec' (from its CFLAGS), which causes an error when building with clang after a recent change in main: error: option '-msoft-float' cannot be specified with '-maltivec' make[6]: *** [scripts/Makefile.build:243: arch/powerpc/lib/xor_vmx.o] Error 1 Explicitly add '-mhard-float' before '-maltivec' in xor_vmx.o's CFLAGS to override the previous inclusion of '-msoft-float' (as the last option wins), which matches how other areas of the kernel use '-maltivec', such as AMDGPU. Cc: stable@vger.kernel.org Closes: https://github.com/ClangBuiltLinux/linux/issues/1986 Link: https://github.com/llvm/llvm-project/commit/4792f912b232141ecba4cbae538873be3c28556c Signed-off-by: Nathan Chancellor Signed-off-by: Michael Ellerman Link: https://msgid.link/20240127-ppc-xor_vmx-drop-msoft-float-v1-1-f24140e81376@kernel.org --- arch/powerpc/lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 6eac63e79a89..0ab65eeb93ee 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -76,7 +76,7 @@ obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o obj-$(CONFIG_ALTIVEC) += xor_vmx.o xor_vmx_glue.o -CFLAGS_xor_vmx.o += -maltivec $(call cc-option,-mabi=altivec) +CFLAGS_xor_vmx.o += -mhard-float -maltivec $(call cc-option,-mabi=altivec) # Enable CFLAGS_xor_vmx.o += -isystem $(shell $(CC) -print-file-name=include) From 83bc680e87292f78c6e823100e417d58a66dcb06 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 17:13:48 -0300 Subject: [PATCH 678/814] macintosh/adb: make adb_dev_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the adb_dev_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Signed-off-by: Michael Ellerman Link: https://msgid.link/20240305-macintosh-v1-1-9c3f4f882045@marliere.net --- drivers/macintosh/adb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 057b0221f695..b0407c5fadb2 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -74,7 +74,9 @@ static struct adb_driver *adb_driver_list[] = { NULL }; -static struct class *adb_dev_class; +static const struct class adb_dev_class = { + .name = "adb", +}; static struct adb_driver *adb_controller; BLOCKING_NOTIFIER_HEAD(adb_client_list); @@ -888,10 +890,10 @@ adbdev_init(void) return; } - adb_dev_class = class_create("adb"); - if (IS_ERR(adb_dev_class)) + if (class_register(&adb_dev_class)) return; - device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + + device_create(&adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); platform_device_register(&adb_pfdev); platform_driver_probe(&adb_pfdrv, adb_dummy_probe); From 20933531be0577cdd782216858c26150dbc7936f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 5 Mar 2024 23:34:08 +1100 Subject: [PATCH 679/814] powerpc/embedded6xx: Fix no previous prototype for avr_uart_send() etc. Move the prototypes into mpc10x.h which is included by all the relevant C files, fixes: arch/powerpc/platforms/embedded6xx/ls_uart.c:59:6: error: no previous prototype for 'avr_uart_configure' arch/powerpc/platforms/embedded6xx/ls_uart.c:82:6: error: no previous prototype for 'avr_uart_send' Signed-off-by: Michael Ellerman Link: https://msgid.link/20240305123410.3306253-1-mpe@ellerman.id.au --- arch/powerpc/platforms/embedded6xx/linkstation.c | 3 --- arch/powerpc/platforms/embedded6xx/mpc10x.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 9c10aac40c7b..e265f026eee2 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -99,9 +99,6 @@ static void __init linkstation_init_IRQ(void) mpic_init(mpic); } -extern void avr_uart_configure(void); -extern void avr_uart_send(const char); - static void __noreturn linkstation_restart(char *cmd) { local_irq_disable(); diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h index 5ad12023e562..ebc258fa4858 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc10x.h +++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h @@ -156,4 +156,7 @@ int mpc10x_disable_store_gathering(struct pci_controller *hose); /* For MPC107 boards that use the built-in openpic */ void mpc10x_set_openpic(void); +void avr_uart_configure(void); +void avr_uart_send(const char c); + #endif /* __PPC_KERNEL_MPC10X_H */ From e8b1ce0e287fd1493334f3435d763aecd517afd9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 5 Mar 2024 23:34:09 +1100 Subject: [PATCH 680/814] powerpc/amigaone: Make several functions static These functions can all be static. Make them so. That also fixes no previous prototype warnings: arch/powerpc/platforms/amigaone/setup.c:28:6: error: no previous prototype for 'amigaone_show_cpuinfo' arch/powerpc/platforms/amigaone/setup.c:68:13: error: no previous prototype for 'amigaone_setup_arch' arch/powerpc/platforms/amigaone/setup.c:86:13: error: no previous prototype for 'amigaone_init_IRQ' arch/powerpc/platforms/amigaone/setup.c:126:17: error: no previous prototype for 'amigaone_restart' Signed-off-by: Michael Ellerman Link: https://msgid.link/20240305123410.3306253-2-mpe@ellerman.id.au --- arch/powerpc/platforms/amigaone/setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c index 6c6e714a7521..2c8dc0886912 100644 --- a/arch/powerpc/platforms/amigaone/setup.c +++ b/arch/powerpc/platforms/amigaone/setup.c @@ -25,7 +25,7 @@ extern void __flush_disable_L1(void); -void amigaone_show_cpuinfo(struct seq_file *m) +static void amigaone_show_cpuinfo(struct seq_file *m) { seq_printf(m, "vendor\t\t: Eyetech Ltd.\n"); } @@ -65,7 +65,7 @@ static int __init amigaone_add_bridge(struct device_node *dev) return 0; } -void __init amigaone_setup_arch(void) +static void __init amigaone_setup_arch(void) { if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0); @@ -83,7 +83,7 @@ static void __init amigaone_discover_phbs(void) BUG_ON(phb != 0); } -void __init amigaone_init_IRQ(void) +static void __init amigaone_init_IRQ(void) { struct device_node *pic, *np = NULL; const unsigned long *prop = NULL; @@ -123,7 +123,7 @@ static int __init request_isa_regions(void) } machine_device_initcall(amigaone, request_isa_regions); -void __noreturn amigaone_restart(char *cmd) +static void __noreturn amigaone_restart(char *cmd) { local_irq_disable(); From 5b9e00a6004cf837c43fdb8d5290df619de78024 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 5 Mar 2024 23:34:10 +1100 Subject: [PATCH 681/814] powerpc/4xx: Fix warp_gpio_leds build failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 44x/warp_defconfig build fails with: arch/powerpc/platforms/44x/warp.c:109:15: error: variable ‘warp_gpio_leds’ has initializer but incomplete type 109 | static struct platform_device warp_gpio_leds = { | ^~~~~~~~~~~~~~~ Fix it by including platform_device.h. Fixes: ef175b29a242 ("of: Stop circularly including of_device.h and of_platform.h") Signed-off-by: Michael Ellerman Link: https://msgid.link/20240305123410.3306253-3-mpe@ellerman.id.au --- arch/powerpc/platforms/44x/warp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index bf0188dcb918..a5001d32f978 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include From 38f680c25ece49c1f8ff55ee78dca0ee4e1793a6 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:39 +0800 Subject: [PATCH 682/814] KVM: riscv: selftests: Add exception handling support Add the infrastructure for guest exception handling in riscv selftests. Customized handlers can be enabled by vm_install_exception_handler(vector) or vm_install_interrupt_handler(). The code is inspired from that of x86/arm64. 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 | 50 +++++++++ .../selftests/kvm/lib/riscv/handlers.S | 101 ++++++++++++++++++ .../selftests/kvm/lib/riscv/processor.c | 69 ++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 tools/testing/selftests/kvm/lib/riscv/handlers.S diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 63592045720f..3e94e915c9f0 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -53,6 +53,7 @@ LIBKVM_s390x += lib/s390x/diag318_test_handler.c LIBKVM_s390x += lib/s390x/processor.c LIBKVM_s390x += lib/s390x/ucall.c +LIBKVM_riscv += lib/riscv/handlers.S LIBKVM_riscv += lib/riscv/processor.c LIBKVM_riscv += lib/riscv/ucall.c diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index b6b95e747688..fe8eda69ce00 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -48,6 +48,56 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype, KVM_REG_RISCV_SBI_SINGLE, \ idx, KVM_REG_SIZE_ULONG) +struct ex_regs { + unsigned long ra; + unsigned long sp; + unsigned long gp; + unsigned long tp; + unsigned long t0; + unsigned long t1; + unsigned long t2; + unsigned long s0; + unsigned long s1; + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + unsigned long s2; + unsigned long s3; + unsigned long s4; + unsigned long s5; + unsigned long s6; + unsigned long s7; + unsigned long s8; + unsigned long s9; + unsigned long s10; + unsigned long s11; + unsigned long t3; + unsigned long t4; + unsigned long t5; + unsigned long t6; + unsigned long epc; + unsigned long status; + unsigned long cause; +}; + +#define NR_VECTORS 2 +#define NR_EXCEPTIONS 32 +#define EC_MASK (NR_EXCEPTIONS - 1) + +typedef void(*exception_handler_fn)(struct ex_regs *); + +void vm_init_vector_tables(struct kvm_vm *vm); +void vcpu_init_vector_tables(struct kvm_vcpu *vcpu); + +void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler); + +void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler); + /* L3 index Bit[47:39] */ #define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL #define PGTBL_L3_INDEX_SHIFT 39 diff --git a/tools/testing/selftests/kvm/lib/riscv/handlers.S b/tools/testing/selftests/kvm/lib/riscv/handlers.S new file mode 100644 index 000000000000..aa0abd3f35bb --- /dev/null +++ b/tools/testing/selftests/kvm/lib/riscv/handlers.S @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + */ + +#ifndef __ASSEMBLY__ +#define __ASSEMBLY__ +#endif + +#include + +.macro save_context + addi sp, sp, (-8*34) + sd x1, 0(sp) + sd x2, 8(sp) + sd x3, 16(sp) + sd x4, 24(sp) + sd x5, 32(sp) + sd x6, 40(sp) + sd x7, 48(sp) + sd x8, 56(sp) + sd x9, 64(sp) + sd x10, 72(sp) + sd x11, 80(sp) + sd x12, 88(sp) + sd x13, 96(sp) + sd x14, 104(sp) + sd x15, 112(sp) + sd x16, 120(sp) + sd x17, 128(sp) + sd x18, 136(sp) + sd x19, 144(sp) + sd x20, 152(sp) + sd x21, 160(sp) + sd x22, 168(sp) + sd x23, 176(sp) + sd x24, 184(sp) + sd x25, 192(sp) + sd x26, 200(sp) + sd x27, 208(sp) + sd x28, 216(sp) + sd x29, 224(sp) + sd x30, 232(sp) + sd x31, 240(sp) + csrr s0, CSR_SEPC + csrr s1, CSR_SSTATUS + csrr s2, CSR_SCAUSE + sd s0, 248(sp) + sd s1, 256(sp) + sd s2, 264(sp) +.endm + +.macro restore_context + ld s2, 264(sp) + ld s1, 256(sp) + ld s0, 248(sp) + csrw CSR_SCAUSE, s2 + csrw CSR_SSTATUS, s1 + csrw CSR_SEPC, s0 + ld x31, 240(sp) + ld x30, 232(sp) + ld x29, 224(sp) + ld x28, 216(sp) + ld x27, 208(sp) + ld x26, 200(sp) + ld x25, 192(sp) + ld x24, 184(sp) + ld x23, 176(sp) + ld x22, 168(sp) + ld x21, 160(sp) + ld x20, 152(sp) + ld x19, 144(sp) + ld x18, 136(sp) + ld x17, 128(sp) + ld x16, 120(sp) + ld x15, 112(sp) + ld x14, 104(sp) + ld x13, 96(sp) + ld x12, 88(sp) + ld x11, 80(sp) + ld x10, 72(sp) + ld x9, 64(sp) + ld x8, 56(sp) + ld x7, 48(sp) + ld x6, 40(sp) + ld x5, 32(sp) + ld x4, 24(sp) + ld x3, 16(sp) + ld x2, 8(sp) + ld x1, 0(sp) + addi sp, sp, (8*34) +.endm + +.balign 4 +.global exception_vectors +exception_vectors: + save_context + move a0, sp + call route_exception + restore_context + sret diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 2bb33a8ac03c..87ce44992c87 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -13,6 +13,8 @@ #define DEFAULT_RISCV_GUEST_STACK_VADDR_MIN 0xac0000 +static vm_vaddr_t exception_handlers; + static uint64_t page_align(struct kvm_vm *vm, uint64_t v) { return (v + vm->page_size) & ~(vm->page_size - 1); @@ -364,8 +366,75 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) va_end(ap); } +void kvm_exit_unexpected_exception(int vector, int ec) +{ + ucall(UCALL_UNHANDLED, 2, vector, ec); +} + void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { + struct ucall uc; + + if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) { + TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)", + uc.args[0], uc.args[1]); + } +} + +struct handlers { + exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS]; +}; + +void route_exception(struct ex_regs *regs) +{ + struct handlers *handlers = (struct handlers *)exception_handlers; + int vector = 0, ec; + + ec = regs->cause & ~CAUSE_IRQ_FLAG; + if (ec >= NR_EXCEPTIONS) + goto unexpected_exception; + + /* Use the same handler for all the interrupts */ + if (regs->cause & CAUSE_IRQ_FLAG) { + vector = 1; + ec = 0; + } + + if (handlers && handlers->exception_handlers[vector][ec]) + return handlers->exception_handlers[vector][ec](regs); + +unexpected_exception: + return kvm_exit_unexpected_exception(vector, ec); +} + +void vcpu_init_vector_tables(struct kvm_vcpu *vcpu) +{ + extern char exception_vectors; + + vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)&exception_vectors); +} + +void vm_init_vector_tables(struct kvm_vm *vm) +{ + vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers), + vm->page_size, MEM_REGION_DATA); + + *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers; +} + +void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler) +{ + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); + + assert(vector < NR_EXCEPTIONS); + handlers->exception_handlers[0][vector] = handler; +} + +void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler) +{ + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); + + handlers->exception_handlers[1][0] = handler; } struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, From 1e979288c9b50a1eef1c5fa2fa93936012a0ed6f Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:40 +0800 Subject: [PATCH 683/814] KVM: riscv: selftests: Add guest helper to get vcpu id Add guest_get_vcpuid() helper to simplify accessing to per-cpu private data. The sscratch CSR was used to store the vcpu id. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/include/aarch64/processor.h | 4 ---- tools/testing/selftests/kvm/include/kvm_util_base.h | 2 ++ tools/testing/selftests/kvm/lib/riscv/processor.c | 8 ++++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index cf20e44e86f2..9e518b562827 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -226,8 +226,4 @@ void smccc_smc(uint32_t function_id, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, struct arm_smccc_res *res); - - -uint32_t guest_get_vcpuid(void); - #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 9e5afc472c14..39c2499df341 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -1081,4 +1081,6 @@ void kvm_selftest_arch_init(void); void kvm_arch_vm_post_create(struct kvm_vm *vm); +uint32_t guest_get_vcpuid(void); + #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 87ce44992c87..4be94d0f0b94 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -316,6 +316,9 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.sp), stack_vaddr + stack_size); vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); + /* Setup sscratch for guest_get_vcpuid() */ + vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(sscratch), vcpu_id); + /* Setup default exception vector of guest */ vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)guest_unexp_trap); @@ -437,6 +440,11 @@ void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handle handlers->exception_handlers[1][0] = handler; } +uint32_t guest_get_vcpuid(void) +{ + return csr_read(CSR_SSCRATCH); +} + struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, From 812806bd1e70f79cc69061f9fd9bb1d367990d37 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:41 +0800 Subject: [PATCH 684/814] KVM: riscv: selftests: Change vcpu_has_ext to a common function Move vcpu_has_ext to the processor.c and rename it to __vcpu_has_ext so that other test cases can use it for vCPU extension check. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/include/riscv/processor.h | 2 ++ tools/testing/selftests/kvm/lib/riscv/processor.c | 10 ++++++++++ tools/testing/selftests/kvm/riscv/get-reg-list.c | 11 +---------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index fe8eda69ce00..1b0a9e9d2d30 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -48,6 +48,8 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype, KVM_REG_RISCV_SBI_SINGLE, \ idx, KVM_REG_SIZE_ULONG) +bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext); + struct ex_regs { unsigned long ra; unsigned long sp; diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 4be94d0f0b94..ec66d331a127 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -15,6 +15,16 @@ static vm_vaddr_t exception_handlers; +bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext) +{ + unsigned long value = 0; + int ret; + + ret = __vcpu_get_reg(vcpu, ext, &value); + + return !ret && !!value; +} + static uint64_t page_align(struct kvm_vm *vm, uint64_t v) { return (v + vm->page_size) & ~(vm->page_size - 1); diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 6435e7a65642..8cece02ca23a 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -123,15 +123,6 @@ bool check_reject_set(int err) return err == EINVAL; } -static bool vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext_id) -{ - int ret; - unsigned long value; - - ret = __vcpu_get_reg(vcpu, ext_id, &value); - return (ret) ? false : !!value; -} - void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) { unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 }; @@ -176,7 +167,7 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) __vcpu_set_reg(vcpu, feature, 1); /* Double check whether the desired extension was enabled */ - __TEST_REQUIRE(vcpu_has_ext(vcpu, feature), + __TEST_REQUIRE(__vcpu_has_ext(vcpu, feature), "%s not available, skipping tests", s->name); } } From d0b94bcbb04262b9ffe6e172223e8cbb663a2c9d Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Mon, 22 Jan 2024 17:58:42 +0800 Subject: [PATCH 685/814] KVM: riscv: selftests: Add sstc timer test Add a KVM selftests to validate the Sstc timer functionality. The test was ported from arm64 arch timer test. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/aarch64/arch_timer.c | 12 +- tools/testing/selftests/kvm/arch_timer.c | 10 +- .../selftests/kvm/include/riscv/arch_timer.h | 71 +++++++++++ .../selftests/kvm/include/riscv/processor.h | 10 ++ .../selftests/kvm/include/timer_test.h | 5 +- .../testing/selftests/kvm/riscv/arch_timer.c | 111 ++++++++++++++++++ 7 files changed, 210 insertions(+), 10 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/riscv/arch_timer.h create mode 100644 tools/testing/selftests/kvm/riscv/arch_timer.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 3e94e915c9f0..426f85798aea 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -185,6 +185,7 @@ TEST_GEN_PROGS_s390x += rseq_test TEST_GEN_PROGS_s390x += set_memory_region_test TEST_GEN_PROGS_s390x += kvm_binary_stats_test +TEST_GEN_PROGS_riscv += arch_timer TEST_GEN_PROGS_riscv += demand_paging_test TEST_GEN_PROGS_riscv += dirty_log_test TEST_GEN_PROGS_riscv += get-reg-list diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index b9ce8c6455db..6dfd7fa1fced 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -194,10 +194,14 @@ struct kvm_vm *test_vm_create(void) vm_init_descriptor_tables(vm); vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handler); - if (!test_args.offset.reserved) { - if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET)) - vm_ioctl(vm, KVM_ARM_SET_COUNTER_OFFSET, &test_args.offset); - else + if (!test_args.reserved) { + if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET)) { + struct kvm_arm_counter_offset offset = { + .counter_offset = test_args.counter_offset, + .reserved = 0, + }; + vm_ioctl(vm, KVM_ARM_SET_COUNTER_OFFSET, &offset); + } else TEST_FAIL("no support for global offset"); } diff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c index f7e4cee8cb34..ae1f1a6d8312 100644 --- a/tools/testing/selftests/kvm/arch_timer.c +++ b/tools/testing/selftests/kvm/arch_timer.c @@ -36,7 +36,7 @@ struct test_args test_args = { .timer_period_ms = TIMER_TEST_PERIOD_MS_DEF, .migration_freq_ms = TIMER_TEST_MIGRATION_FREQ_MS, .timer_err_margin_us = TIMER_TEST_ERR_MARGIN_US, - .offset = { .reserved = 1 }, + .reserved = 1, }; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; @@ -75,6 +75,8 @@ static void *test_vcpu_run(void *arg) TEST_FAIL("Unexpected guest exit"); } + pr_info("PASS(vCPU-%d).\n", vcpu_idx); + return NULL; } @@ -190,7 +192,7 @@ static void test_print_help(char *name) TIMER_TEST_PERIOD_MS_DEF); pr_info("\t-m: Frequency (in ms) of vCPUs to migrate to different pCPU. 0 to turn off (default: %u)\n", TIMER_TEST_MIGRATION_FREQ_MS); - pr_info("\t-o: Counter offset (in counter cycles, default: 0)\n"); + pr_info("\t-o: Counter offset (in counter cycles, default: 0) [aarch64-only]\n"); pr_info("\t-e: Interrupt arrival error margin (in us) of the guest timer (default: %u)\n", TIMER_TEST_ERR_MARGIN_US); pr_info("\t-h: print this help screen\n"); @@ -223,8 +225,8 @@ static bool parse_args(int argc, char *argv[]) test_args.timer_err_margin_us = atoi_non_negative("Error Margin", optarg); break; case 'o': - test_args.offset.counter_offset = strtol(optarg, NULL, 0); - test_args.offset.reserved = 0; + test_args.counter_offset = strtol(optarg, NULL, 0); + test_args.reserved = 0; break; case 'h': default: diff --git a/tools/testing/selftests/kvm/include/riscv/arch_timer.h b/tools/testing/selftests/kvm/include/riscv/arch_timer.h new file mode 100644 index 000000000000..225d81dad064 --- /dev/null +++ b/tools/testing/selftests/kvm/include/riscv/arch_timer.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RISC-V Arch Timer(sstc) specific interface + * + * Copyright (c) 2024 Intel Corporation + */ + +#ifndef SELFTEST_KVM_ARCH_TIMER_H +#define SELFTEST_KVM_ARCH_TIMER_H + +#include +#include + +static unsigned long timer_freq; + +#define msec_to_cycles(msec) \ + ((timer_freq) * (uint64_t)(msec) / 1000) + +#define usec_to_cycles(usec) \ + ((timer_freq) * (uint64_t)(usec) / 1000000) + +#define cycles_to_usec(cycles) \ + ((uint64_t)(cycles) * 1000000 / (timer_freq)) + +static inline uint64_t timer_get_cycles(void) +{ + return csr_read(CSR_TIME); +} + +static inline void timer_set_cmp(uint64_t cval) +{ + csr_write(CSR_STIMECMP, cval); +} + +static inline uint64_t timer_get_cmp(void) +{ + return csr_read(CSR_STIMECMP); +} + +static inline void timer_irq_enable(void) +{ + csr_set(CSR_SIE, IE_TIE); +} + +static inline void timer_irq_disable(void) +{ + csr_clear(CSR_SIE, IE_TIE); +} + +static inline void timer_set_next_cmp_ms(uint32_t msec) +{ + uint64_t now_ct = timer_get_cycles(); + uint64_t next_ct = now_ct + msec_to_cycles(msec); + + timer_set_cmp(next_ct); +} + +static inline void __delay(uint64_t cycles) +{ + uint64_t start = timer_get_cycles(); + + while ((timer_get_cycles() - start) < cycles) + cpu_relax(); +} + +static inline void udelay(unsigned long usec) +{ + __delay(usec_to_cycles(usec)); +} + +#endif /* SELFTEST_KVM_ARCH_TIMER_H */ diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index 1b0a9e9d2d30..ce473fe251dd 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -193,4 +193,14 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, bool guest_sbi_probe_extension(int extid, long *out_val); +static inline void local_irq_enable(void) +{ + csr_set(CSR_SSTATUS, SR_SIE); +} + +static inline void local_irq_disable(void) +{ + csr_clear(CSR_SSTATUS, SR_SIE); +} + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/timer_test.h b/tools/testing/selftests/kvm/include/timer_test.h index 256e2d2137cf..9b6edaafe6d4 100644 --- a/tools/testing/selftests/kvm/include/timer_test.h +++ b/tools/testing/selftests/kvm/include/timer_test.h @@ -23,8 +23,9 @@ struct test_args { uint32_t timer_period_ms; uint32_t migration_freq_ms; uint32_t timer_err_margin_us; - /* TODO: Change arm specific type to a common one */ - struct kvm_arm_counter_offset offset; + /* Members of struct kvm_arm_counter_offset */ + uint64_t counter_offset; + uint64_t reserved; }; /* Shared variables between host and guest */ diff --git a/tools/testing/selftests/kvm/riscv/arch_timer.c b/tools/testing/selftests/kvm/riscv/arch_timer.c new file mode 100644 index 000000000000..e22848f747c0 --- /dev/null +++ b/tools/testing/selftests/kvm/riscv/arch_timer.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * arch_timer.c - Tests the riscv64 sstc timer IRQ functionality + * + * The test validates the sstc timer IRQs using vstimecmp registers. + * It's ported from the aarch64 arch_timer test. + * + * Copyright (c) 2024, Intel Corporation. + */ + +#define _GNU_SOURCE + +#include "arch_timer.h" +#include "kvm_util.h" +#include "processor.h" +#include "timer_test.h" + +static int timer_irq = IRQ_S_TIMER; + +static void guest_irq_handler(struct ex_regs *regs) +{ + uint64_t xcnt, xcnt_diff_us, cmp; + unsigned int intid = regs->cause & ~CAUSE_IRQ_FLAG; + uint32_t cpu = guest_get_vcpuid(); + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + timer_irq_disable(); + + xcnt = timer_get_cycles(); + cmp = timer_get_cmp(); + xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt); + + /* Make sure we are dealing with the correct timer IRQ */ + GUEST_ASSERT_EQ(intid, timer_irq); + + __GUEST_ASSERT(xcnt >= cmp, + "xcnt = 0x%"PRIx64", cmp = 0x%"PRIx64", xcnt_diff_us = 0x%" PRIx64, + xcnt, cmp, xcnt_diff_us); + + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); +} + +static void guest_run(struct test_vcpu_shared_data *shared_data) +{ + uint32_t irq_iter, config_iter; + + shared_data->nr_iter = 0; + shared_data->guest_stage = 0; + + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { + /* Setup the next interrupt */ + timer_set_next_cmp_ms(test_args.timer_period_ms); + shared_data->xcnt = timer_get_cycles(); + timer_irq_enable(); + + /* Setup a timeout for the interrupt to arrive */ + udelay(msecs_to_usecs(test_args.timer_period_ms) + + test_args.timer_err_margin_us); + + irq_iter = READ_ONCE(shared_data->nr_iter); + __GUEST_ASSERT(config_iter + 1 == irq_iter, + "config_iter + 1 = 0x%x, irq_iter = 0x%x.\n" + " Guest timer interrupt was not trigged within the specified\n" + " interval, try to increase the error margin by [-e] option.\n", + config_iter + 1, irq_iter); + } +} + +static void guest_code(void) +{ + uint32_t cpu = guest_get_vcpuid(); + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + timer_irq_disable(); + local_irq_enable(); + + guest_run(shared_data); + + GUEST_DONE(); +} + +struct kvm_vm *test_vm_create(void) +{ + struct kvm_vm *vm; + int nr_vcpus = test_args.nr_vcpus; + + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); + __TEST_REQUIRE(__vcpu_has_ext(vcpus[0], RISCV_ISA_EXT_REG(KVM_RISCV_ISA_EXT_SSTC)), + "SSTC not available, skipping test\n"); + + vm_init_vector_tables(vm); + vm_install_interrupt_handler(vm, guest_irq_handler); + + for (int i = 0; i < nr_vcpus; i++) + vcpu_init_vector_tables(vcpus[i]); + + /* Initialize guest timer frequency. */ + vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency), &timer_freq); + sync_global_to_guest(vm, timer_freq); + pr_debug("timer_freq: %lu\n", timer_freq); + + /* Make all the test's cmdline args visible to the guest */ + sync_global_to_guest(vm, test_args); + + return vm; +} + +void test_vm_cleanup(struct kvm_vm *vm) +{ + kvm_vm_free(vm); +} From d808f0b1be4888a87524164bc7dad2242734de38 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 13 Feb 2024 19:04:00 +0530 Subject: [PATCH 686/814] RISC-V: KVM: Forward SEED CSR access to user space The SEED CSR access from VS/VU mode (guest) will always trap to HS-mode (KVM) when Zkr extension is available to the Guest/VM. Forward this CSR access to KVM user space so that it can be emulated based on the method chosen by VMM. Fixes: f370b4e668f0 ("RISC-V: KVM: Allow scalar crypto extensions for Guest/VM") Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_insn.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index 7a6abed41bc1..ee7215f4071f 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -7,6 +7,8 @@ #include #include +#include + #define INSN_OPCODE_MASK 0x007c #define INSN_OPCODE_SHIFT 2 #define INSN_OPCODE_SYSTEM 28 @@ -213,9 +215,20 @@ struct csr_func { unsigned long wr_mask); }; +static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask) +{ + if (!riscv_isa_extension_available(vcpu->arch.isa, ZKR)) + return KVM_INSN_ILLEGAL_TRAP; + + return KVM_INSN_EXIT_TO_USER_SPACE; +} + static const struct csr_func csr_funcs[] = { KVM_RISCV_VCPU_AIA_CSR_FUNCS KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS + { .base = CSR_SEED, .count = 1, .func = seed_csr_rmw }, }; /** From f943ebe2ec26272d71f9c7643ec667c616419bb1 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 13 Feb 2024 10:32:26 +0530 Subject: [PATCH 687/814] RISC-V: KVM: Allow Ztso extension for Guest/VM Extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Ztso extension for Guest/VM. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu_onereg.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 7499e88a947c..f8aa9f2ace95 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -166,6 +166,7 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZVFH, KVM_RISCV_ISA_EXT_ZVFHMIN, KVM_RISCV_ISA_EXT_ZFA, + KVM_RISCV_ISA_EXT_ZTSO, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 5f7355e96008..38f5cf286087 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -66,6 +66,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZKSED), KVM_ISA_EXT_ARR(ZKSH), KVM_ISA_EXT_ARR(ZKT), + KVM_ISA_EXT_ARR(ZTSO), KVM_ISA_EXT_ARR(ZVBB), KVM_ISA_EXT_ARR(ZVBC), KVM_ISA_EXT_ARR(ZVFH), @@ -141,6 +142,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZKSED: case KVM_RISCV_ISA_EXT_ZKSH: case KVM_RISCV_ISA_EXT_ZKT: + case KVM_RISCV_ISA_EXT_ZTSO: case KVM_RISCV_ISA_EXT_ZVBB: case KVM_RISCV_ISA_EXT_ZVBC: case KVM_RISCV_ISA_EXT_ZVFH: From d9bb4eca32f99c5fcde705d1bb4cb6b445dbd6e8 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 13 Feb 2024 10:36:16 +0530 Subject: [PATCH 688/814] KVM: riscv: selftests: Add Ztso extension to get-reg-list test The KVM RISC-V allows Ztso extension for Guest/VM so add this extension to get-reg-list test. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/riscv/get-reg-list.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 8cece02ca23a..a464aa6c0b09 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -73,6 +73,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKSED: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKSH: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKT: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZTSO: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVBB: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVBC: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVFH: @@ -436,6 +437,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZKSED), KVM_ISA_EXT_ARR(ZKSH), KVM_ISA_EXT_ARR(ZKT), + KVM_ISA_EXT_ARR(ZTSO), KVM_ISA_EXT_ARR(ZVBB), KVM_ISA_EXT_ARR(ZVBC), KVM_ISA_EXT_ARR(ZVFH), @@ -957,6 +959,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zkr, ZKR); KVM_ISA_EXT_SIMPLE_CONFIG(zksed, ZKSED); KVM_ISA_EXT_SIMPLE_CONFIG(zksh, ZKSH); KVM_ISA_EXT_SIMPLE_CONFIG(zkt, ZKT); +KVM_ISA_EXT_SIMPLE_CONFIG(ztso, ZTSO); KVM_ISA_EXT_SIMPLE_CONFIG(zvbb, ZVBB); KVM_ISA_EXT_SIMPLE_CONFIG(zvbc, ZVBC); KVM_ISA_EXT_SIMPLE_CONFIG(zvfh, ZVFH); @@ -1010,6 +1013,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zksed, &config_zksh, &config_zkt, + &config_ztso, &config_zvbb, &config_zvbc, &config_zvfh, From 77fc0bfa43f83c1080b35a4915c767cf2c4979ff Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 13 Feb 2024 13:35:45 +0530 Subject: [PATCH 689/814] RISC-V: KVM: Allow Zacas extension for Guest/VM Extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Zacas extension for Guest/VM. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu_onereg.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index f8aa9f2ace95..37fb0f70b3e5 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -167,6 +167,7 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZVFHMIN, KVM_RISCV_ISA_EXT_ZFA, KVM_RISCV_ISA_EXT_ZTSO, + KVM_RISCV_ISA_EXT_ZACAS, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 38f5cf286087..f4a6124d25c9 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -40,6 +40,7 @@ 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(ZACAS), KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBC), @@ -118,6 +119,7 @@ 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_ZACAS: case KVM_RISCV_ISA_EXT_ZBA: case KVM_RISCV_ISA_EXT_ZBB: case KVM_RISCV_ISA_EXT_ZBC: From d8c0831348e78fdaf67aa95070bae2ef8e819b05 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 13 Feb 2024 13:39:17 +0530 Subject: [PATCH 690/814] KVM: riscv: selftests: Add Zacas extension to get-reg-list test The KVM RISC-V allows Zacas extension for Guest/VM so add this extension to get-reg-list test. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/riscv/get-reg-list.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index a464aa6c0b09..b882b7b9b785 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -47,6 +47,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVINVAL: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVPBMT: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZACAS: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBA: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBB: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBC: @@ -411,6 +412,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(SVINVAL), KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), + KVM_ISA_EXT_ARR(ZACAS), KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBC), @@ -933,6 +935,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(sstc, SSTC); KVM_ISA_EXT_SIMPLE_CONFIG(svinval, SVINVAL); KVM_ISA_EXT_SIMPLE_CONFIG(svnapot, SVNAPOT); KVM_ISA_EXT_SIMPLE_CONFIG(svpbmt, SVPBMT); +KVM_ISA_EXT_SIMPLE_CONFIG(zacas, ZACAS); KVM_ISA_EXT_SIMPLE_CONFIG(zba, ZBA); KVM_ISA_EXT_SIMPLE_CONFIG(zbb, ZBB); KVM_ISA_EXT_SIMPLE_CONFIG(zbc, ZBC); @@ -987,6 +990,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_svinval, &config_svnapot, &config_svpbmt, + &config_zacas, &config_zba, &config_zbb, &config_zbc, From 3e62273ac63aeeb80bd3b24fa0102a4de9972d83 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Feb 2024 13:29:30 -0600 Subject: [PATCH 691/814] soc: fsl: qbman: Remove RESERVEDMEM_OF_DECLARE usage There is no reason to use RESERVEDMEM_OF_DECLARE() as the initialization hook just saves off the base address and size. Use of RESERVEDMEM_OF_DECLARE() is reserved for non-driver code and initialization which must be done early. For qbman, retrieving the address and size can be done in probe just as easily. Link: https://lore.kernel.org/r/20240201192931.1324130-1-robh@kernel.org Signed-off-by: Rob Herring --- drivers/soc/fsl/qbman/bman_ccsr.c | 27 ++--------- drivers/soc/fsl/qbman/dpaa_sys.c | 12 +++-- drivers/soc/fsl/qbman/dpaa_sys.h | 4 +- drivers/soc/fsl/qbman/qman_ccsr.c | 77 ++++++++++--------------------- 4 files changed, 40 insertions(+), 80 deletions(-) diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c index cb24a08be084..b0f26f6f731e 100644 --- a/drivers/soc/fsl/qbman/bman_ccsr.c +++ b/drivers/soc/fsl/qbman/bman_ccsr.c @@ -144,17 +144,6 @@ static int bm_set_memory(u64 ba, u32 size) static dma_addr_t fbpr_a; static size_t fbpr_sz; -static int bman_fbpr(struct reserved_mem *rmem) -{ - fbpr_a = rmem->base; - fbpr_sz = rmem->size; - - WARN_ON(!(fbpr_a && fbpr_sz)); - - return 0; -} -RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr); - static irqreturn_t bman_isr(int irq, void *ptr) { u32 isr_val, ier_val, ecsr_val, isr_mask, i; @@ -242,17 +231,11 @@ static int fsl_bman_probe(struct platform_device *pdev) return -ENODEV; } - /* - * If FBPR memory wasn't defined using the qbman compatible string - * try using the of_reserved_mem_device method - */ - if (!fbpr_a) { - ret = qbman_init_private_mem(dev, 0, &fbpr_a, &fbpr_sz); - if (ret) { - dev_err(dev, "qbman_init_private_mem() failed 0x%x\n", - ret); - return -ENODEV; - } + ret = qbman_init_private_mem(dev, 0, "fsl,bman-fbpr", &fbpr_a, &fbpr_sz); + if (ret) { + dev_err(dev, "qbman_init_private_mem() failed 0x%x\n", + ret); + return -ENODEV; } dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz); diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c index 33751450047e..e1d7b79cc450 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.c +++ b/drivers/soc/fsl/qbman/dpaa_sys.c @@ -34,8 +34,8 @@ /* * Initialize a devices private memory region */ -int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, - size_t *size) +int qbman_init_private_mem(struct device *dev, int idx, const char *compat, + dma_addr_t *addr, size_t *size) { struct device_node *mem_node; struct reserved_mem *rmem; @@ -44,8 +44,12 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); if (!mem_node) { - dev_err(dev, "No memory-region found for index %d\n", idx); - return -ENODEV; + mem_node = of_find_compatible_node(NULL, NULL, compat); + if (!mem_node) { + dev_err(dev, "No memory-region found for index %d or compatible '%s'\n", + idx, compat); + return -ENODEV; + } } rmem = of_reserved_mem_lookup(mem_node); diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h index ae8afa552b1e..16485bde9636 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.h +++ b/drivers/soc/fsl/qbman/dpaa_sys.h @@ -101,8 +101,8 @@ static inline u8 dpaa_cyc_diff(u8 ringsize, u8 first, u8 last) #define DPAA_GENALLOC_OFF 0x80000000 /* Initialize the devices private memory region */ -int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, - size_t *size); +int qbman_init_private_mem(struct device *dev, int idx, const char *compat, + dma_addr_t *addr, size_t *size); /* memremap() attributes for different platforms */ #ifdef CONFIG_PPC diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index 157659fd033a..392e54f14dbe 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -468,28 +468,6 @@ static int zero_priv_mem(phys_addr_t addr, size_t sz) return 0; } - -static int qman_fqd(struct reserved_mem *rmem) -{ - fqd_a = rmem->base; - fqd_sz = rmem->size; - - WARN_ON(!(fqd_a && fqd_sz)); - return 0; -} -RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd); - -static int qman_pfdr(struct reserved_mem *rmem) -{ - pfdr_a = rmem->base; - pfdr_sz = rmem->size; - - WARN_ON(!(pfdr_a && pfdr_sz)); - - return 0; -} -RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr); - #endif unsigned int qm_get_fqid_maxcnt(void) @@ -796,39 +774,34 @@ static int fsl_qman_probe(struct platform_device *pdev) qm_channel_caam = QMAN_CHANNEL_CAAM_REV3; } - if (fqd_a) { -#ifdef CONFIG_PPC - /* - * For PPC backward DT compatibility - * FQD memory MUST be zero'd by software - */ - zero_priv_mem(fqd_a, fqd_sz); -#else - WARN(1, "Unexpected architecture using non shared-dma-mem reservations"); -#endif - } else { - /* - * Order of memory regions is assumed as FQD followed by PFDR - * in order to ensure allocations from the correct regions the - * driver initializes then allocates each piece in order - */ - ret = qbman_init_private_mem(dev, 0, &fqd_a, &fqd_sz); - if (ret) { - dev_err(dev, "qbman_init_private_mem() for FQD failed 0x%x\n", - ret); - return -ENODEV; - } + /* + * Order of memory regions is assumed as FQD followed by PFDR + * in order to ensure allocations from the correct regions the + * driver initializes then allocates each piece in order + */ + ret = qbman_init_private_mem(dev, 0, "fsl,qman-fqd", &fqd_a, &fqd_sz); + if (ret) { + dev_err(dev, "qbman_init_private_mem() for FQD failed 0x%x\n", + ret); + return -ENODEV; } +#ifdef CONFIG_PPC + /* + * For PPC backward DT compatibility + * FQD memory MUST be zero'd by software + */ + zero_priv_mem(fqd_a, fqd_sz); +#else + WARN(1, "Unexpected architecture using non shared-dma-mem reservations"); +#endif dev_dbg(dev, "Allocated FQD 0x%llx 0x%zx\n", fqd_a, fqd_sz); - if (!pfdr_a) { - /* Setup PFDR memory */ - ret = qbman_init_private_mem(dev, 1, &pfdr_a, &pfdr_sz); - if (ret) { - dev_err(dev, "qbman_init_private_mem() for PFDR failed 0x%x\n", - ret); - return -ENODEV; - } + /* Setup PFDR memory */ + ret = qbman_init_private_mem(dev, 1, "fsl,qman-pfdr", &pfdr_a, &pfdr_sz); + if (ret) { + dev_err(dev, "qbman_init_private_mem() for PFDR failed 0x%x\n", + ret); + return -ENODEV; } dev_dbg(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz); From 4d4f986d296f3435dac4ee4ab79a6614bc8d1442 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 29 Feb 2024 15:09:11 -0500 Subject: [PATCH 692/814] dt-bindings: interrupt-controller: fsl,intmux: Include power-domains support Enable the power-domains property for the fsl,intmux node. This addition accommodates i.MX8QXP, i.MX8QM, and i.MX8DXL, which utilize the power-domains property. Incorporating this eliminates DTB_CHECK errors in relevant device tree source files. Signed-off-by: Frank Li Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240229200911.712572-1-Frank.Li@nxp.com Signed-off-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/fsl,intmux.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,intmux.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,intmux.yaml index 985bfa4f6fda..78baa0a571cf 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,intmux.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,intmux.yaml @@ -37,6 +37,9 @@ properties: clock-names: const: ipg + power-domains: + maxItems: 1 + required: - compatible - reg From 329105ce53437ff64b29f6c429dfe5dc2aa7b676 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 6 Mar 2024 23:58:51 +1100 Subject: [PATCH 693/814] powerpc/64s: Fix get_hugepd_cache_index() build failure With CONFIG_BUG=n, the 64-bit Book3S build fails with: arch/powerpc/include/asm/book3s/64/pgtable-64k.h: In function 'get_hugepd_cache_index': arch/powerpc/include/asm/book3s/64/pgtable-64k.h:51:1: error: no return statement in function returning non-void Currently the body of the function is just BUG(), so when CONFIG_BUG=n it is an empty function, leading to the error. get_hugepd_cache_index() should never be called, the only call is behind an is_hugepd() check, which is always false for this configuration. Instead mark it as always inline, and change the BUG() to BUILD_BUG(). That should allow the compiler to see that the function is never called, and therefore that it never returns, fixing the build error. Signed-off-by: Michael Ellerman Link: https://msgid.link/20240306125853.3714578-1-mpe@ellerman.id.au --- arch/powerpc/include/asm/book3s/64/pgtable-64k.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable-64k.h b/arch/powerpc/include/asm/book3s/64/pgtable-64k.h index 2fce3498b000..ced7ee8b42fc 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable-64k.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable-64k.h @@ -45,9 +45,9 @@ static inline int hugepd_ok(hugepd_t hpd) /* * This should never get called */ -static inline int get_hugepd_cache_index(int index) +static __always_inline int get_hugepd_cache_index(int index) { - BUG(); + BUILD_BUG(); } #endif /* CONFIG_HUGETLB_PAGE */ From c2e5d70cf05b48bfbd5b6625bbd0ec3052cecd5d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 6 Mar 2024 23:58:52 +1100 Subject: [PATCH 694/814] powerpc/83xx: Fix build failure with FPU=n Building eg. 83xx/mpc832x_rdb_defconfig with FPU=n, fails with: arch/powerpc/platforms/83xx/suspend.c: In function 'mpc83xx_suspend_enter': arch/powerpc/platforms/83xx/suspend.c:209:17: error: implicit declaration of function 'enable_kernel_fp' 209 | enable_kernel_fp(); Fix it by providing an enable_kernel_fp() stub for FPU=n builds, which allows using IS_ENABLED(CONFIG_PPC_FPU) around the call to enable_kernel_fp(). Signed-off-by: Michael Ellerman Link: https://msgid.link/20240306125853.3714578-2-mpe@ellerman.id.au --- arch/powerpc/include/asm/switch_to.h | 4 ++++ arch/powerpc/platforms/83xx/suspend.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h index aee25e3ebf96..fc933807ddc8 100644 --- a/arch/powerpc/include/asm/switch_to.h +++ b/arch/powerpc/include/asm/switch_to.h @@ -48,6 +48,10 @@ static inline void disable_kernel_fp(void) #else static inline void save_fpu(struct task_struct *t) { } static inline void flush_fp_to_thread(struct task_struct *t) { } +static inline void enable_kernel_fp(void) +{ + BUILD_BUG(); +} #endif #ifdef CONFIG_ALTIVEC diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index c9664e46b03d..99bd4355f28e 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -206,7 +206,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state) out_be32(&pmc_regs->config1, in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF); - enable_kernel_fp(); + if (IS_ENABLED(CONFIG_PPC_FPU)) + enable_kernel_fp(); mpc83xx_enter_deep_sleep(immrbase); From 9db2235326c4b868b6e065dfa3a69011ee570848 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Wed, 1 Feb 2023 22:36:19 +0800 Subject: [PATCH 695/814] powerpc/macio: Make remove callback of macio driver void returned Commit fc7a6209d571 ("bus: Make remove callback return void") forces bus_type::remove be void-returned, it doesn't make much sense for any bus based driver implementing remove callbalk to return non-void to its caller. This change is for macio bus based drivers. Signed-off-by: Dawei Li Acked-by: Damien Le Moal Acked-by: Jakub Kicinski Signed-off-by: Michael Ellerman Link: https://msgid.link/TYCP286MB232391520CB471E7C8D6EA84CAD19@TYCP286MB2323.JPNP286.PROD.OUTLOOK.COM --- arch/powerpc/include/asm/macio.h | 2 +- drivers/ata/pata_macio.c | 4 +--- drivers/macintosh/rack-meter.c | 4 +--- drivers/net/ethernet/apple/bmac.c | 4 +--- drivers/net/ethernet/apple/mace.c | 4 +--- drivers/scsi/mac53c94.c | 5 +---- drivers/scsi/mesh.c | 5 +---- drivers/tty/serial/pmac_zilog.c | 7 ++----- sound/aoa/soundbus/i2sbus/core.c | 4 +--- 9 files changed, 10 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index ab9608e63e40..9203ff6acbf6 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h @@ -126,7 +126,7 @@ static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev) struct macio_driver { int (*probe)(struct macio_dev* dev, const struct of_device_id *match); - int (*remove)(struct macio_dev* dev); + void (*remove)(struct macio_dev *dev); int (*suspend)(struct macio_dev* dev, pm_message_t state); int (*resume)(struct macio_dev* dev); diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c index 17f6ccee53c7..4ac854f6b057 100644 --- a/drivers/ata/pata_macio.c +++ b/drivers/ata/pata_macio.c @@ -1188,7 +1188,7 @@ static int pata_macio_attach(struct macio_dev *mdev, return rc; } -static int pata_macio_detach(struct macio_dev *mdev) +static void pata_macio_detach(struct macio_dev *mdev) { struct ata_host *host = macio_get_drvdata(mdev); struct pata_macio_priv *priv = host->private_data; @@ -1203,8 +1203,6 @@ static int pata_macio_detach(struct macio_dev *mdev) ata_host_detach(host); unlock_media_bay(priv->mdev->media_bay); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 40240bce77b0..896a43bd819f 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -523,7 +523,7 @@ static int rackmeter_probe(struct macio_dev* mdev, return rc; } -static int rackmeter_remove(struct macio_dev* mdev) +static void rackmeter_remove(struct macio_dev *mdev) { struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev); @@ -558,8 +558,6 @@ static int rackmeter_remove(struct macio_dev* mdev) /* Get rid of me */ kfree(rm); - - return 0; } static int rackmeter_shutdown(struct macio_dev* mdev) diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c index 9e653e2925f7..292b1f9cd9e7 100644 --- a/drivers/net/ethernet/apple/bmac.c +++ b/drivers/net/ethernet/apple/bmac.c @@ -1591,7 +1591,7 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length) } #endif -static int bmac_remove(struct macio_dev *mdev) +static void bmac_remove(struct macio_dev *mdev) { struct net_device *dev = macio_get_drvdata(mdev); struct bmac_data *bp = netdev_priv(dev); @@ -1609,8 +1609,6 @@ static int bmac_remove(struct macio_dev *mdev) macio_release_resources(mdev); free_netdev(dev); - - return 0; } static const struct of_device_id bmac_match[] = diff --git a/drivers/net/ethernet/apple/mace.c b/drivers/net/ethernet/apple/mace.c index fd1b008b7208..e6350971c707 100644 --- a/drivers/net/ethernet/apple/mace.c +++ b/drivers/net/ethernet/apple/mace.c @@ -272,7 +272,7 @@ static int mace_probe(struct macio_dev *mdev, const struct of_device_id *match) return rc; } -static int mace_remove(struct macio_dev *mdev) +static void mace_remove(struct macio_dev *mdev) { struct net_device *dev = macio_get_drvdata(mdev); struct mace_data *mp; @@ -296,8 +296,6 @@ static int mace_remove(struct macio_dev *mdev) free_netdev(dev); macio_release_resources(mdev); - - return 0; } static void dbdma_reset(volatile struct dbdma_regs __iomem *dma) diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 6a019132109c..377dcab32cd8 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -508,7 +508,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat return rc; } -static int mac53c94_remove(struct macio_dev *mdev) +static void mac53c94_remove(struct macio_dev *mdev) { struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev); struct Scsi_Host *host = fp->host; @@ -526,11 +526,8 @@ static int mac53c94_remove(struct macio_dev *mdev) scsi_host_put(host); macio_release_resources(mdev); - - return 0; } - static struct of_device_id mac53c94_match[] = { { diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index e276583c590c..d63177b30c84 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1986,7 +1986,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) return -ENODEV; } -static int mesh_remove(struct macio_dev *mdev) +static void mesh_remove(struct macio_dev *mdev) { struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); struct Scsi_Host *mesh_host = ms->host; @@ -2013,11 +2013,8 @@ static int mesh_remove(struct macio_dev *mdev) macio_release_resources(mdev); scsi_host_put(mesh_host); - - return 0; } - static struct of_device_id mesh_match[] = { { diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index c8bf08c19c64..732d821db4f8 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1507,12 +1507,12 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) * That one should not be called, macio isn't really a hotswap device, * we don't expect one of those serial ports to go away... */ -static int pmz_detach(struct macio_dev *mdev) +static void pmz_detach(struct macio_dev *mdev) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); if (!uap) - return -ENODEV; + return; uart_remove_one_port(&pmz_uart_reg, &uap->port); @@ -1523,11 +1523,8 @@ static int pmz_detach(struct macio_dev *mdev) dev_set_drvdata(&mdev->ofdev.dev, NULL); uap->dev = NULL; uap->port.dev = NULL; - - return 0; } - static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 3f49a9e28bfc..b8ff5cccd0c8 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -365,15 +365,13 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) return 0; } -static int i2sbus_remove(struct macio_dev* dev) +static void i2sbus_remove(struct macio_dev *dev) { struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); struct i2sbus_dev *i2sdev, *tmp; list_for_each_entry_safe(i2sdev, tmp, &control->list, item) soundbus_remove_one(&i2sdev->sound); - - return 0; } #ifdef CONFIG_PM From 5804be0618486f8979208e323188e44f8013a6a3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 19:54:39 +0200 Subject: [PATCH 696/814] MIPS: ralink: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The driver doesn't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index fc503679a93d..8b485cbe854e 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include From e5d9592c8652ee95e2251778eb34522f7826360f Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 10:37:50 -0300 Subject: [PATCH 697/814] mips: mt: make mt_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the mt_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mips_mt.h | 2 +- arch/mips/kernel/mips-mt.c | 14 ++++---------- arch/mips/kernel/rtlx-mt.c | 8 ++++---- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/arch/mips/include/asm/mips_mt.h b/arch/mips/include/asm/mips_mt.h index b444523ecd50..28917f1582b3 100644 --- a/arch/mips/include/asm/mips_mt.h +++ b/arch/mips/include/asm/mips_mt.h @@ -26,6 +26,6 @@ static inline void mips_mt_set_cpuoptions(void) { } #endif struct class; -extern struct class *mt_class; +extern const struct class mt_class; #endif /* __ASM_MIPS_MT_H */ diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index c07d64438b5b..c938ba208fc0 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -229,19 +229,13 @@ void mips_mt_set_cpuoptions(void) } } -struct class *mt_class; +const struct class mt_class = { + .name = "mt", +}; static int __init mips_mt_init(void) { - struct class *mtc; - - mtc = class_create("mt"); - if (IS_ERR(mtc)) - return PTR_ERR(mtc); - - mt_class = mtc; - - return 0; + return class_register(&mt_class); } subsys_initcall(mips_mt_init); diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c index 38c6925a1bea..ff7535de42ca 100644 --- a/arch/mips/kernel/rtlx-mt.c +++ b/arch/mips/kernel/rtlx-mt.c @@ -95,11 +95,11 @@ int __init rtlx_module_init(void) atomic_set(&channel_wqs[i].in_open, 0); mutex_init(&channel_wqs[i].mutex); - dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, + dev = device_create(&mt_class, NULL, MKDEV(major, i), NULL, "%s%d", RTLX_MODULE_NAME, i); if (IS_ERR(dev)) { while (i--) - device_destroy(mt_class, MKDEV(major, i)); + device_destroy(&mt_class, MKDEV(major, i)); err = PTR_ERR(dev); goto out_chrdev; @@ -127,7 +127,7 @@ int __init rtlx_module_init(void) out_class: for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); + device_destroy(&mt_class, MKDEV(major, i)); out_chrdev: unregister_chrdev(major, RTLX_MODULE_NAME); @@ -139,7 +139,7 @@ void __exit rtlx_module_exit(void) int i; for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); + device_destroy(&mt_class, MKDEV(major, i)); unregister_chrdev(major, RTLX_MODULE_NAME); From 8b2de7402f3bd897e09cfd83564c94bfd5a3cf86 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 10:37:51 -0300 Subject: [PATCH 698/814] mips: sibyte: make tb_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the tb_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Signed-off-by: Thomas Bogendoerfer --- arch/mips/sibyte/common/sb_tbprof.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index 408db45efdc8..af5333986900 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c @@ -535,13 +535,14 @@ static const struct file_operations sbprof_tb_fops = { .llseek = default_llseek, }; -static struct class *tb_class; +static const struct class tb_class = { + .name = "sb_tracebuffer", +}; static struct device *tb_dev; static int __init sbprof_tb_init(void) { struct device *dev; - struct class *tbc; int err; if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) { @@ -550,15 +551,11 @@ static int __init sbprof_tb_init(void) return -EIO; } - tbc = class_create("sb_tracebuffer"); - if (IS_ERR(tbc)) { - err = PTR_ERR(tbc); + err = class_register(&tb_class); + if (err) goto out_chrdev; - } - tb_class = tbc; - - dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), NULL, "tb"); + dev = device_create(&tb_class, NULL, MKDEV(SBPROF_TB_MAJOR, 0), NULL, "tb"); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_class; @@ -573,7 +570,7 @@ static int __init sbprof_tb_init(void) return 0; out_class: - class_destroy(tb_class); + class_unregister(&tb_class); out_chrdev: unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME); @@ -582,9 +579,9 @@ out_chrdev: static void __exit sbprof_tb_cleanup(void) { - device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0)); + device_destroy(&tb_class, MKDEV(SBPROF_TB_MAJOR, 0)); unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME); - class_destroy(tb_class); + class_unregister(&tb_class); } module_init(sbprof_tb_init); From 992cf65674778e22436807796b2df927de21bb75 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Wed, 6 Mar 2024 23:40:21 -0600 Subject: [PATCH 699/814] Input: iqs7222 - add support for IQS7222D v1.1 and v1.2 The vendor has introduced two new revisions with slightly different memory maps; update the driver to support them. Fixes: dd24e202ac72 ("Input: iqs7222 - add support for Azoteq IQS7222D") Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/ZelTRYX3fenMQuhF@nixie71 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/iqs7222.c | 112 +++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index 36aeeae77611..9ca5a743f19f 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -620,6 +620,118 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { }, }, }, + { + .prod_num = IQS7222_PROD_NUM_D, + .fw_major = 1, + .fw_minor = 2, + .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, + }, + }, + }, + { + .prod_num = IQS7222_PROD_NUM_D, + .fw_major = 1, + .fw_minor = 1, + .touch_link = 1774, + .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, + }, + }, + }, { .prod_num = IQS7222_PROD_NUM_D, .fw_major = 0, From 5d3d723470996d3b9050a89427d9fc72cd0241e9 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Sep 2022 14:29:01 +0200 Subject: [PATCH 700/814] dt-bindings: timer: mediatek: Convert to json-schema Convert the MediaTek SoC timer txt binding to json-schema. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220929122901.614315-3-angelogioacchino.delregno@collabora.com [robh: Add mt8365 compatible, drop duplicate mediatek,mt6795-systimer, drop quotes] Signed-off-by: Rob Herring --- .../bindings/timer/mediatek,mtk-timer.txt | 48 ----------- .../bindings/timer/mediatek,timer.yaml | 84 +++++++++++++++++++ 2 files changed, 84 insertions(+), 48 deletions(-) delete mode 100644 Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt create mode 100644 Documentation/devicetree/bindings/timer/mediatek,timer.yaml diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt deleted file mode 100644 index b3e797e8aa31..000000000000 --- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt +++ /dev/null @@ -1,48 +0,0 @@ -MediaTek Timers ---------------- - -MediaTek SoCs have different timers on different platforms, -- CPUX (ARM/ARM64 System Timer) -- GPT (General Purpose Timer) -- SYST (System Timer) - -The proper timer will be selected automatically by driver. - -Required properties: -- compatible should contain: - For those SoCs that use GPT - * "mediatek,mt2701-timer" for MT2701 compatible timers (GPT) - * "mediatek,mt6580-timer" for MT6580 compatible timers (GPT) - * "mediatek,mt6582-timer" for MT6582 compatible timers (GPT) - * "mediatek,mt6589-timer" for MT6589 compatible timers (GPT) - * "mediatek,mt7623-timer" for MT7623 compatible timers (GPT) - * "mediatek,mt8127-timer" for MT8127 compatible timers (GPT) - * "mediatek,mt8135-timer" for MT8135 compatible timers (GPT) - * "mediatek,mt8173-timer" for MT8173 compatible timers (GPT) - * "mediatek,mt8516-timer" for MT8516 compatible timers (GPT) - * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT) - - For those SoCs that use SYST - * "mediatek,mt8183-timer" for MT8183 compatible timers (SYST) - * "mediatek,mt8186-timer" for MT8186 compatible timers (SYST) - * "mediatek,mt8188-timer" for MT8188 compatible timers (SYST) - * "mediatek,mt8192-timer" for MT8192 compatible timers (SYST) - * "mediatek,mt8195-timer" for MT8195 compatible timers (SYST) - * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST) - * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST) - - For those SoCs that use CPUX - * "mediatek,mt6795-systimer" for MT6795 compatible timers (CPUX) - * "mediatek,mt8365-systimer" for MT8365 compatible timers (CPUX) - -- reg: Should contain location and length for timer register. -- clocks: Should contain system clock. - -Examples: - - timer@10008000 { - compatible = "mediatek,mt6577-timer"; - reg = <0x10008000 0x80>; - interrupts = ; - clocks = <&system_clk>; - }; diff --git a/Documentation/devicetree/bindings/timer/mediatek,timer.yaml b/Documentation/devicetree/bindings/timer/mediatek,timer.yaml new file mode 100644 index 000000000000..f68fc7050c56 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/mediatek,timer.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/mediatek,timer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek SoC timers + +maintainers: + - Matthias Brugger + +description: + MediaTek SoCs have different timers on different platforms, + CPUX (ARM/ARM64 System Timer), GPT (General Purpose Timer) + and SYST (System Timer). + +properties: + compatible: + oneOf: + - items: + - enum: + - mediatek,mt6577-timer + - mediatek,mt6765-timer + - mediatek,mt6795-systimer + # GPT Timers + - items: + - enum: + - mediatek,mt2701-timer + - mediatek,mt6580-timer + - mediatek,mt6582-timer + - mediatek,mt6589-timer + - mediatek,mt7623-timer + - mediatek,mt8127-timer + - mediatek,mt8135-timer + - mediatek,mt8173-timer + - mediatek,mt8516-timer + - const: mediatek,mt6577-timer + # SYST Timers + - items: + - enum: + - mediatek,mt7629-timer + - mediatek,mt8183-timer + - mediatek,mt8186-timer + - mediatek,mt8188-timer + - mediatek,mt8192-timer + - mediatek,mt8195-timer + - mediatek,mt8365-systimer + - const: mediatek,mt6765-timer + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: Timer clock + - description: RTC or bus clock + + clock-names: + minItems: 1 + maxItems: 2 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + timer@10008000 { + compatible = "mediatek,mt6577-timer"; + reg = <0x10008000 0x80>; + interrupts = ; + clocks = <&system_clk>; + }; From 26dd48780bd2232a8f50f878929a9e448b7fd531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 8 Mar 2024 09:51:12 +0100 Subject: [PATCH 701/814] parisc: led: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Helge Deller --- drivers/parisc/led.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 1f75d2416001..b49cb010a4d8 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -308,15 +308,13 @@ static int hppa_led_generic_probe(struct platform_device *pdev, return 0; } -static int platform_led_remove(struct platform_device *pdev) +static void platform_led_remove(struct platform_device *pdev) { struct hppa_drvdata *p = platform_get_drvdata(pdev); int i; for (i = 0; i < NUM_LEDS_PER_BOARD; i++) led_classdev_unregister(&p->leds[i].led_cdev); - - return 0; } static struct led_type mainboard_led_types[NUM_LEDS_PER_BOARD] = { @@ -371,7 +369,7 @@ MODULE_ALIAS("platform:platform-leds"); static struct platform_driver hppa_mainboard_led_driver = { .probe = platform_led_probe, - .remove = platform_led_remove, + .remove_new = platform_led_remove, .driver = { .name = "platform-leds", }, From bc9ce934c469d594d77c44b41a90570fc8881e4d Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Mon, 26 Feb 2024 13:52:25 +0200 Subject: [PATCH 702/814] MAINTAINERS: Remove T Ambarus from few mchp entries I have been no longer at Microchip for more than a year and I'm no longer interested in maintaining these drivers. Let other mchp people step up, thus remove myself. Thanks for the nice collaboration everyone! Signed-off-by: Tudor Ambarus Acked-by: Vinod Koul Signed-off-by: Herbert Xu --- MAINTAINERS | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5a4051996f1e..dc1564ce2f01 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14234,7 +14234,6 @@ F: drivers/misc/xilinx_tmr_manager.c MICROCHIP AT91 DMA DRIVERS M: Ludovic Desroches -M: Tudor Ambarus L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: dmaengine@vger.kernel.org S: Supported @@ -14283,9 +14282,8 @@ F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml F: drivers/media/platform/microchip/microchip-csi2dc.c MICROCHIP ECC DRIVER -M: Tudor Ambarus L: linux-crypto@vger.kernel.org -S: Maintained +S: Orphan F: drivers/crypto/atmel-ecc.* MICROCHIP EIC DRIVER @@ -14390,9 +14388,8 @@ S: Maintained F: drivers/mmc/host/atmel-mci.c MICROCHIP NAND DRIVER -M: Tudor Ambarus L: linux-mtd@lists.infradead.org -S: Supported +S: Orphan F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: drivers/mtd/nand/raw/atmel/* From 12e37aef7ba20a5a0d6e076968a41293b019e90d Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 26 Feb 2024 19:57:00 +0100 Subject: [PATCH 703/814] hwrng: hisi - use dev_err_probe Replace dev_err + return with dev_err_probe. Signed-off-by: Martin Kaiser Reviewed-by: Jonathan Cameron Signed-off-by: Herbert Xu --- drivers/char/hw_random/hisi-rng.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c index b6f27566e0ba..4e501d5c121f 100644 --- a/drivers/char/hw_random/hisi-rng.c +++ b/drivers/char/hw_random/hisi-rng.c @@ -89,10 +89,8 @@ static int hisi_rng_probe(struct platform_device *pdev) rng->rng.read = hisi_rng_read; ret = devm_hwrng_register(&pdev->dev, &rng->rng); - if (ret) { - dev_err(&pdev->dev, "failed to register hwrng\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to register hwrng\n"); return 0; } From db8ac883855ee3ccf52eb47ac665dbc1efac3af9 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 29 Feb 2024 23:14:48 +1300 Subject: [PATCH 704/814] crypto: hisilicon/zip - fix the missing CRYPTO_ALG_ASYNC in cra_flags Add the missing CRYPTO_ALG_ASYNC flag since hisilizon zip driver works asynchronously. Cc: Zhou Wang Signed-off-by: Barry Song Acked-by: Yang Shen Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_crypto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c index c650c741a18d..94e2d66b04b6 100644 --- a/drivers/crypto/hisilicon/zip/zip_crypto.c +++ b/drivers/crypto/hisilicon/zip/zip_crypto.c @@ -591,6 +591,7 @@ static struct acomp_alg hisi_zip_acomp_deflate = { .base = { .cra_name = "deflate", .cra_driver_name = "hisi-deflate-acomp", + .cra_flags = CRYPTO_ALG_ASYNC, .cra_module = THIS_MODULE, .cra_priority = HZIP_ALG_PRIORITY, .cra_ctxsize = sizeof(struct hisi_zip_ctx), From 30dd94dba350043a32cfe9cb478ed621aae3c5c9 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 29 Feb 2024 23:14:49 +1300 Subject: [PATCH 705/814] crypto: iaa - fix the missing CRYPTO_ALG_ASYNC in cra_flags Add the missing CRYPTO_ALG_ASYNC flag since intel iaa driver works asynchronously. Signed-off-by: Barry Song Acked-by: Tom Zanussi Signed-off-by: Herbert Xu --- drivers/crypto/intel/iaa/iaa_crypto_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index b54f93c64033..1cd304de5388 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -1823,6 +1823,7 @@ static struct acomp_alg iaa_acomp_fixed_deflate = { .base = { .cra_name = "deflate", .cra_driver_name = "deflate-iaa", + .cra_flags = CRYPTO_ALG_ASYNC, .cra_ctxsize = sizeof(struct iaa_compression_ctx), .cra_module = THIS_MODULE, .cra_priority = IAA_ALG_PRIORITY, From 43a7885ec0dfca2bdc60f2de736e55cf5e7b915d Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Thu, 29 Feb 2024 18:36:03 +0100 Subject: [PATCH 706/814] crypto: tcrypt - add ffdhe2048(dh) test Commit 7dce59819750 ("crypto: dh - implement ffdheXYZ(dh) templates") implemented the said templates. Add ffdhe2048(dh) test as it is the fastest one. This is a requirement for the FIPS certification. Signed-off-by: Vladis Dronov Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index ea4d1cea9c06..8aea416f6480 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1851,6 +1851,9 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret = min(ret, tcrypt_test("cbc(aria)")); ret = min(ret, tcrypt_test("ctr(aria)")); break; + case 193: + ret = min(ret, tcrypt_test("ffdhe2048(dh)")); + break; case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, speed_template_16_24_32); From 77292bb8ca69c808741aadbd29207605296e24af Mon Sep 17 00:00:00 2001 From: Barry Song Date: Sat, 2 Mar 2024 08:27:45 +1300 Subject: [PATCH 707/814] crypto: scomp - remove memcpy if sg_nents is 1 and pages are lowmem while sg_nents is 1, which is always true for the current kernel as the only user - zswap is this case, we might have a chance to remove memcpy, thus improve the performance. Though sg_nents is 1, its buffer might cross two pages. If those pages are highmem, we have no cheap way to map them to contiguous virtual address because kmap doesn't support more than one page (kmap single higmem page could be still expensive for tlb) and vmap is expensive. So we also test and enure page is not highmem in order to safely use page_to_virt before removing the memcpy. The good news is that in the most majority of cases, we are lowmem, and we are always lowmem in those modern and popular hardware. Cc: Johannes Weiner Cc: Nhat Pham Cc: Yosry Ahmed Signed-off-by: Barry Song Tested-by: Chengming Zhou Signed-off-by: Herbert Xu --- crypto/scompress.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/crypto/scompress.c b/crypto/scompress.c index 9cda4ef84a9b..93daf3eb9842 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -117,6 +117,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) struct crypto_scomp *scomp = *tfm_ctx; void **ctx = acomp_request_ctx(req); struct scomp_scratch *scratch; + void *src, *dst; unsigned int dlen; int ret; @@ -134,13 +135,25 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) scratch = raw_cpu_ptr(&scomp_scratch); spin_lock(&scratch->lock); - scatterwalk_map_and_copy(scratch->src, req->src, 0, req->slen, 0); - if (dir) - ret = crypto_scomp_compress(scomp, scratch->src, req->slen, - scratch->dst, &req->dlen, *ctx); + if (sg_nents(req->src) == 1 && !PageHighMem(sg_page(req->src))) { + src = page_to_virt(sg_page(req->src)) + req->src->offset; + } else { + scatterwalk_map_and_copy(scratch->src, req->src, 0, + req->slen, 0); + src = scratch->src; + } + + if (req->dst && sg_nents(req->dst) == 1 && !PageHighMem(sg_page(req->dst))) + dst = page_to_virt(sg_page(req->dst)) + req->dst->offset; else - ret = crypto_scomp_decompress(scomp, scratch->src, req->slen, - scratch->dst, &req->dlen, *ctx); + dst = scratch->dst; + + if (dir) + ret = crypto_scomp_compress(scomp, src, req->slen, + dst, &req->dlen, *ctx); + else + ret = crypto_scomp_decompress(scomp, src, req->slen, + dst, &req->dlen, *ctx); if (!ret) { if (!req->dst) { req->dst = sgl_alloc(req->dlen, GFP_ATOMIC, NULL); @@ -152,8 +165,17 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) ret = -ENOSPC; goto out; } - scatterwalk_map_and_copy(scratch->dst, req->dst, 0, req->dlen, - 1); + if (dst == scratch->dst) { + scatterwalk_map_and_copy(scratch->dst, req->dst, 0, + req->dlen, 1); + } else { + int nr_pages = DIV_ROUND_UP(req->dst->offset + req->dlen, PAGE_SIZE); + int i; + struct page *dst_page = sg_page(req->dst); + + for (i = 0; i < nr_pages; i++) + flush_dcache_page(dst_page + i); + } } out: spin_unlock(&scratch->lock); From dc1460fe1b2dc883195d21759676d55b183fd495 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 16 Feb 2024 17:05:50 -0800 Subject: [PATCH 708/814] of: Always unflatten in unflatten_and_copy_device_tree() We want to populate an empty DT whenever CONFIG_OF is enabled so that overlays can be applied and the DT unit tests can be run. Make unflatten_and_copy_device_tree() stop printing a warning if the 'initial_boot_params' pointer is NULL. Instead, simply copy the dtb if there is one and then unflatten it. If there isn't a DT to copy, then the call to unflatten_device_tree() is largely a no-op, so nothing really changes here. Cc: Rob Herring Cc: Frank Rowand Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-2-sboyd@kernel.org Signed-off-by: Rob Herring --- drivers/of/fdt.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index bf502ba8da95..dfeba8b8ce94 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1318,6 +1318,21 @@ bool __init early_init_dt_scan(void *params) return true; } +static void *__init copy_device_tree(void *fdt) +{ + int size; + void *dt; + + size = fdt_totalsize(fdt); + dt = early_init_dt_alloc_memory_arch(size, + roundup_pow_of_two(FDT_V17_SIZE)); + + if (dt) + memcpy(dt, fdt, size); + + return dt; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -1350,22 +1365,9 @@ void __init unflatten_device_tree(void) */ void __init unflatten_and_copy_device_tree(void) { - int size; - void *dt; + if (initial_boot_params) + initial_boot_params = copy_device_tree(initial_boot_params); - if (!initial_boot_params) { - pr_warn("No valid device tree found, continuing without\n"); - return; - } - - size = fdt_totalsize(initial_boot_params); - dt = early_init_dt_alloc_memory_arch(size, - roundup_pow_of_two(FDT_V17_SIZE)); - - if (dt) { - memcpy(dt, initial_boot_params, size); - initial_boot_params = dt; - } unflatten_device_tree(); } From 7b937cc243e5b1df8780a0aa743ce800df6c68d1 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 16 Feb 2024 17:05:51 -0800 Subject: [PATCH 709/814] of: Create of_root if no dtb provided by firmware When enabling CONFIG_OF on a platform where 'of_root' is not populated by firmware, we end up without a root node. In order to apply overlays and create subnodes of the root node, we need one. Create this root node by unflattening an empty builtin dtb. If firmware provides a flattened device tree (FDT) then the FDT is unflattened via setup_arch(). Otherwise, the call to unflatten(_and_copy)?_device_tree() will create an empty root node. We make of_have_populated_dt() return true only if the DTB was loaded by firmware so that existing callers don't change behavior after this patch. The call in the of platform code is removed because it prevents overlays from creating platform devices when the empty root node is used. [sboyd@kernel.org: Update of_have_populated_dt() to treat this empty dtb as not populated. Drop setup_of() initcall] Signed-off-by: Frank Rowand Link: https://lore.kernel.org/r/20230317053415.2254616-2-frowand.list@gmail.com Cc: Rob Herring Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-3-sboyd@kernel.org Signed-off-by: Rob Herring --- drivers/of/Kconfig | 5 ++--- drivers/of/Makefile | 2 +- drivers/of/empty_root.dts | 6 ++++++ drivers/of/fdt.c | 32 +++++++++++++++++++++++++++++++- drivers/of/platform.c | 3 --- include/linux/of.h | 25 +++++++++++++++---------- 6 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 drivers/of/empty_root.dts diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index da9826accb1b..d738fbad9c36 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -14,9 +14,8 @@ if OF config OF_UNITTEST bool "Device Tree runtime unit tests" - depends on !SPARC + depends on OF_EARLY_FLATTREE select IRQ_DOMAIN - select OF_EARLY_FLATTREE select OF_RESOLVE help This option builds in test cases for the device tree infrastructure @@ -54,7 +53,7 @@ config OF_FLATTREE select CRC32 config OF_EARLY_FLATTREE - bool + def_bool OF && !(SPARC || ALPHA || HEXAGON || M68K || PARISC || S390) select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM select OF_FLATTREE diff --git a/drivers/of/Makefile b/drivers/of/Makefile index eff624854575..df305348d1cb 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -2,7 +2,7 @@ obj-y = base.o cpu.o device.o module.o platform.o property.o obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o -obj-$(CONFIG_OF_FLATTREE) += fdt.o +obj-$(CONFIG_OF_FLATTREE) += fdt.o empty_root.dtb.o obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o obj-$(CONFIG_OF_PROMTREE) += pdt.o obj-$(CONFIG_OF_ADDRESS) += address.o diff --git a/drivers/of/empty_root.dts b/drivers/of/empty_root.dts new file mode 100644 index 000000000000..cf9e97a60f48 --- /dev/null +++ b/drivers/of/empty_root.dts @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +/ { + +}; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index dfeba8b8ce94..e5a385285149 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "OF: fdt: " fmt +#include #include #include #include @@ -32,6 +33,13 @@ #include "of_private.h" +/* + * __dtb_empty_root_begin[] and __dtb_empty_root_end[] magically created by + * cmd_dt_S_dtb in scripts/Makefile.lib + */ +extern uint8_t __dtb_empty_root_begin[]; +extern uint8_t __dtb_empty_root_end[]; + /* * of_fdt_limit_memory - limit the number of regions in the /memory node * @limit: maximum entries @@ -1343,7 +1351,29 @@ static void *__init copy_device_tree(void *fdt) */ void __init unflatten_device_tree(void) { - __unflatten_device_tree(initial_boot_params, NULL, &of_root, + void *fdt = initial_boot_params; + + /* Don't use the bootloader provided DTB if ACPI is enabled */ + if (!acpi_disabled) + fdt = NULL; + + /* + * Populate an empty root node when ACPI is enabled or bootloader + * doesn't provide one. + */ + if (!fdt) { + fdt = (void *) __dtb_empty_root_begin; + /* fdt_totalsize() will be used for copy size */ + if (fdt_totalsize(fdt) > + __dtb_empty_root_end - __dtb_empty_root_begin) { + pr_err("invalid size in dtb_empty_root\n"); + return; + } + of_fdt_crc32 = crc32_be(~0, fdt, fdt_totalsize(fdt)); + fdt = copy_device_tree(fdt); + } + + __unflatten_device_tree(fdt, NULL, &of_root, early_init_dt_alloc_memory_arch, false); /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ba964df6b6db..389d4ea6bfc1 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -512,9 +512,6 @@ static int __init of_platform_default_populate_init(void) device_links_supplier_sync_state_pause(); - if (!of_have_populated_dt()) - return -ENODEV; - if (IS_ENABLED(CONFIG_PPC)) { struct device_node *boot_display = NULL; struct platform_device *dev; diff --git a/include/linux/of.h b/include/linux/of.h index a3e8e429ad7f..d5e7acdc8c8e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -180,11 +180,6 @@ static inline bool is_of_node(const struct fwnode_handle *fwnode) &__of_fwnode_handle_node->fwnode : NULL; \ }) -static inline bool of_have_populated_dt(void) -{ - return of_root != NULL; -} - static inline bool of_node_is_root(const struct device_node *node) { return node && (node->parent == NULL); @@ -546,11 +541,6 @@ static inline struct device_node *of_find_node_with_property( #define of_fwnode_handle(node) NULL -static inline bool of_have_populated_dt(void) -{ - return false; -} - static inline struct device_node *of_get_compatible_child(const struct device_node *parent, const char *compatible) { @@ -1634,6 +1624,21 @@ static inline bool of_device_is_system_power_controller(const struct device_node return of_property_read_bool(np, "system-power-controller"); } +/** + * of_have_populated_dt() - Has DT been populated by bootloader + * + * Return: True if a DTB has been populated by the bootloader and it isn't the + * empty builtin one. False otherwise. + */ +static inline bool of_have_populated_dt(void) +{ +#ifdef CONFIG_OF + return of_property_present(of_root, "compatible"); +#else + return false; +#endif +} + /* * Overlay support */ From 221a819aa3ca5bbbc91ce425b3e8d9463b121d09 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 16 Feb 2024 17:05:52 -0800 Subject: [PATCH 710/814] um: Unconditionally call unflatten_device_tree() Call this function unconditionally so that we can populate an empty DTB on platforms that don't boot with a command line provided DTB. There's no harm in calling unflatten_device_tree() unconditionally. If there isn't a valid initial_boot_params dtb then unflatten_device_tree() returns early. Cc: Rob Herring Cc: Frank Rowand Cc: Richard Weinberger Cc: Anton Ivanov Cc: Johannes Berg Cc: linux-um@lists.infradead.org Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-4-sboyd@kernel.org Signed-off-by: Rob Herring --- arch/um/kernel/dtb.c | 14 +++++++------- drivers/of/unittest.c | 4 ---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/um/kernel/dtb.c b/arch/um/kernel/dtb.c index 484141b06938..4954188a6a09 100644 --- a/arch/um/kernel/dtb.c +++ b/arch/um/kernel/dtb.c @@ -16,16 +16,16 @@ void uml_dtb_init(void) void *area; area = uml_load_file(dtb, &size); - if (!area) - return; + if (area) { + if (!early_init_dt_scan(area)) { + pr_err("invalid DTB %s\n", dtb); + memblock_free(area, size); + return; + } - if (!early_init_dt_scan(area)) { - pr_err("invalid DTB %s\n", dtb); - memblock_free(area, size); - return; + early_init_fdt_scan_reserved_mem(); } - early_init_fdt_scan_reserved_mem(); unflatten_device_tree(); } diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index cfd60e35a899..891752a20a5f 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -4087,10 +4087,6 @@ static int __init of_unittest(void) add_taint(TAINT_TEST, LOCKDEP_STILL_OK); /* adding data for unittest */ - - if (IS_ENABLED(CONFIG_UML)) - unittest_unflatten_overlay_base(); - res = unittest_data_add(); if (res) return res; From 40f18dbbb42c56019b889b5b1fdce3da89e354da Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 16 Feb 2024 17:05:53 -0800 Subject: [PATCH 711/814] x86/of: Unconditionally call unflatten_and_copy_device_tree() Call this function unconditionally so that we can populate an empty DTB on platforms that don't boot with a firmware provided or builtin DTB. There's no harm in calling unflatten_device_tree() unconditionally here. If there isn't a non-NULL 'initial_boot_params' pointer then unflatten_device_tree() returns early. Cc: Rob Herring Cc: Frank Rowand Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Cc: Dave Hansen Cc: x86@kernel.org Cc: H. Peter Anvin Tested-by: Saurabh Sengar Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-5-sboyd@kernel.org Signed-off-by: Rob Herring --- arch/x86/kernel/devicetree.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index afd09924094e..650752d112a6 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -283,22 +283,24 @@ void __init x86_flattree_get_config(void) u32 size, map_len; void *dt; - if (!initial_dtb) - return; + if (initial_dtb) { + map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128); - map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128); + dt = early_memremap(initial_dtb, map_len); + size = fdt_totalsize(dt); + if (map_len < size) { + early_memunmap(dt, map_len); + dt = early_memremap(initial_dtb, size); + map_len = size; + } - dt = early_memremap(initial_dtb, map_len); - size = fdt_totalsize(dt); - if (map_len < size) { - early_memunmap(dt, map_len); - dt = early_memremap(initial_dtb, size); - map_len = size; + early_init_dt_verify(dt); } - early_init_dt_verify(dt); unflatten_and_copy_device_tree(); - early_memunmap(dt, map_len); + + if (initial_dtb) + early_memunmap(dt, map_len); } #endif From d1eabd218edee6a6f0458a8705ebc02b860a624f Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 16 Feb 2024 17:05:55 -0800 Subject: [PATCH 712/814] of: unittest: treat missing of_root as error instead of fixing up unflatten_device_tree() now ensures that the 'of_root' node is populated with the root of a default empty devicetree. Remove the unittest code that created 'of_root' if it was missing. Verify that 'of_root' is valid before attempting to attach the testcase-data subtree. Remove the unittest code that unflattens the unittest overlay base if architecture is UML because that is always done now. Signed-off-by: Frank Rowand Link: https://lore.kernel.org/r/20230317053415.2254616-3-frowand.list@gmail.com Cc: Rob Herring Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-7-sboyd@kernel.org Signed-off-by: Rob Herring --- drivers/of/unittest.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 891752a20a5f..4c67de37bf26 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1744,20 +1744,16 @@ static int __init unittest_data_add(void) return -EINVAL; } + /* attach the sub-tree to live tree */ if (!of_root) { - of_root = unittest_data_node; - for_each_of_allnodes(np) - __of_attach_node_sysfs(np); - of_aliases = of_find_node_by_path("/aliases"); - of_chosen = of_find_node_by_path("/chosen"); - of_overlay_mutex_unlock(); - return 0; + pr_warn("%s: no live tree to attach sub-tree\n", __func__); + kfree(unittest_data); + return -ENODEV; } EXPECT_BEGIN(KERN_INFO, "Duplicate name in testcase-data, renamed to \"duplicate-name#1\""); - /* attach the sub-tree to live tree */ np = unittest_data_node->child; while (np) { struct device_node *next = np->sibling; From 893ecc6d2d61381bc56991178cb3de697a948b78 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 16 Feb 2024 17:05:56 -0800 Subject: [PATCH 713/814] of: Add KUnit test to confirm DTB is loaded Add a KUnit test that confirms a DTB has been loaded, i.e. there is a root node, and that the of_have_populated_dt() API works properly. We skip the test when CONFIG_OF_EARLY_FLATREE=n because in that case we know architecture code hasn't called unflatten_(and_copy_)?device_tree() which would populate some sort of root node. Cc: Rob Herring Cc: Frank Rowand Reviewed-by: David Gow Cc: Brendan Higgins Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20240217010557.2381548-8-sboyd@kernel.org Signed-off-by: Rob Herring --- drivers/of/.kunitconfig | 3 +++ drivers/of/Kconfig | 9 +++++++ drivers/of/Makefile | 2 ++ drivers/of/of_test.c | 57 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 drivers/of/.kunitconfig create mode 100644 drivers/of/of_test.c diff --git a/drivers/of/.kunitconfig b/drivers/of/.kunitconfig new file mode 100644 index 000000000000..5a8fee11978c --- /dev/null +++ b/drivers/of/.kunitconfig @@ -0,0 +1,3 @@ +CONFIG_KUNIT=y +CONFIG_OF=y +CONFIG_OF_KUNIT_TEST=y diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index d738fbad9c36..dd726c7056bf 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -36,6 +36,15 @@ config OF_UNITTEST If unsure, say N here. This option is not safe to enable. +config OF_KUNIT_TEST + tristate "Devicetree KUnit Test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + This option builds KUnit unit tests for device tree infrastructure. + + If unsure, say N here, but this option is safe to enable. + config OF_ALL_DTBS bool "Build all Device Tree Blobs" depends on COMPILE_TEST diff --git a/drivers/of/Makefile b/drivers/of/Makefile index df305348d1cb..251d33532148 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -19,4 +19,6 @@ obj-y += kexec.o endif endif +obj-$(CONFIG_OF_KUNIT_TEST) += of_test.o + obj-$(CONFIG_OF_UNITTEST) += unittest-data/ diff --git a/drivers/of/of_test.c b/drivers/of/of_test.c new file mode 100644 index 000000000000..a9301d293f01 --- /dev/null +++ b/drivers/of/of_test.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for OF APIs + */ +#include +#include + +#include + +/* + * Test that the root node "/" can be found by path. + */ +static void of_dtb_root_node_found_by_path(struct kunit *test) +{ + struct device_node *np; + + np = of_find_node_by_path("/"); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np); + of_node_put(np); +} + +/* + * Test that the 'of_root' global variable is always populated when DT code is + * enabled. Remove this test once of_root is removed from global access. + */ +static void of_dtb_root_node_populates_of_root(struct kunit *test) +{ + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, of_root); +} + +static struct kunit_case of_dtb_test_cases[] = { + KUNIT_CASE(of_dtb_root_node_found_by_path), + KUNIT_CASE(of_dtb_root_node_populates_of_root), + {} +}; + +static int of_dtb_test_init(struct kunit *test) +{ + if (!IS_ENABLED(CONFIG_OF_EARLY_FLATTREE)) + kunit_skip(test, "requires CONFIG_OF_EARLY_FLATTREE"); + + return 0; +} + +/* + * Test suite to confirm a DTB is loaded. + */ +static struct kunit_suite of_dtb_suite = { + .name = "of_dtb", + .test_cases = of_dtb_test_cases, + .init = of_dtb_test_init, +}; + +kunit_test_suites( + &of_dtb_suite, +); +MODULE_LICENSE("GPL"); From 802a8874a3889a4a0d218d4f73e5855c96d5b8a8 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:22 +0100 Subject: [PATCH 714/814] sparc32: Use generic cmpdi2/ucmpdi2 variants Use the generic variants - the implementation is the same. As a nice side-effect fix the following warnings: cmpdi2.c: warning: no previous prototype for '__cmpdi2' [-Wmissing-prototypes] ucmpdi2.c: warning: no previous prototype for '__ucmpdi2' [-Wmissing-prototypes] Signed-off-by: Sam Ravnborg Fixes: 0fcb70851fbf ("Makefile.extrawarn: turn on missing-prototypes globally") Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Reviewed-by: Maciej W. Rozycki Tested-by: Maciej W. Rozycki # build-tested Cc: "David S. Miller" Cc: Andreas Larsson Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-1-1f186603c5c4@ravnborg.org --- arch/sparc/Kconfig | 2 ++ arch/sparc/lib/Makefile | 4 ++-- arch/sparc/lib/cmpdi2.c | 28 ---------------------------- arch/sparc/lib/ucmpdi2.c | 20 -------------------- 4 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 arch/sparc/lib/cmpdi2.c delete mode 100644 arch/sparc/lib/ucmpdi2.c diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index b087d4fe00af..734f23daecca 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -57,6 +57,8 @@ config SPARC32 select CLZ_TAB select DMA_DIRECT_REMAP select GENERIC_ATOMIC64 + select GENERIC_LIB_CMPDI2 + select GENERIC_LIB_UCMPDI2 select HAVE_UID16 select LOCK_MM_AND_FIND_VMA select OLD_SIGACTION diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 59669ebddd4e..ee5091dd67ed 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -14,7 +14,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-$(CONFIG_SPARC64) += atomic_64.o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o -lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o +lib-$(CONFIG_SPARC32) += muldi3.o bitext.o lib-$(CONFIG_SPARC64) += multi3.o lib-$(CONFIG_SPARC64) += fls.o lib-$(CONFIG_SPARC64) += fls64.o @@ -51,5 +51,5 @@ lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o obj-$(CONFIG_SPARC64) += iomap.o -obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o +obj-$(CONFIG_SPARC32) += atomic32.o obj-$(CONFIG_SPARC64) += PeeCeeI.o diff --git a/arch/sparc/lib/cmpdi2.c b/arch/sparc/lib/cmpdi2.c deleted file mode 100644 index 333367fe7353..000000000000 --- a/arch/sparc/lib/cmpdi2.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -word_type __cmpdi2(long long a, long long b) -{ - const DWunion au = { - .ll = a - }; - const DWunion bu = { - .ll = b - }; - - if (au.s.high < bu.s.high) - return 0; - else if (au.s.high > bu.s.high) - return 2; - - if ((unsigned int) au.s.low < (unsigned int) bu.s.low) - return 0; - else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) - return 2; - - return 1; -} - -EXPORT_SYMBOL(__cmpdi2); diff --git a/arch/sparc/lib/ucmpdi2.c b/arch/sparc/lib/ucmpdi2.c deleted file mode 100644 index 82c1cccb1264..000000000000 --- a/arch/sparc/lib/ucmpdi2.c +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include "libgcc.h" - -word_type __ucmpdi2(unsigned long long a, unsigned long long b) -{ - const DWunion au = {.ll = a}; - const DWunion bu = {.ll = b}; - - if ((unsigned int) au.s.high < (unsigned int) bu.s.high) - return 0; - else if ((unsigned int) au.s.high > (unsigned int) bu.s.high) - return 2; - if ((unsigned int) au.s.low < (unsigned int) bu.s.low) - return 0; - else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) - return 2; - return 1; -} -EXPORT_SYMBOL(__ucmpdi2); From 7bfba2ca462356331c735e68cff1cb7515150bad Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:23 +0100 Subject: [PATCH 715/814] sparc32: Fix build with trapbase Fix the following build errors: irq_32.c:258:7: error: array subscript [16, 79] is outside array bounds of 'struct tt_entry[1] irq_32.c:271:14: error: assignment to 'struct tt_entry *' from incompatible pointer type 'struct tt_entry (*)[] trapbase is a pointer to an array of tt_entry, but the code declared it as a pointer so the compiler see a single entry and not an array. Fix this by modifyinf the declaration to be an array, and modify all users to take the address of the first member. Signed-off-by: Sam Ravnborg Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Cc: Andreas Larsson Cc: "David S. Miller" Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-2-1f186603c5c4@ravnborg.org --- arch/sparc/kernel/irq_32.c | 6 +++--- arch/sparc/kernel/kernel.h | 8 ++++---- arch/sparc/kernel/kgdb_32.c | 4 ++-- arch/sparc/kernel/leon_smp.c | 6 +++--- arch/sparc/kernel/setup_32.c | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index e8452be5123b..8605dd710f3c 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -268,11 +268,11 @@ int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) if (sparc_cpu_model != sparc_leon) { struct tt_entry *trap_table; - trap_table = &trapbase_cpu1; + trap_table = &trapbase_cpu1[0]; INSTANTIATE(trap_table) - trap_table = &trapbase_cpu2; + trap_table = &trapbase_cpu2[0]; INSTANTIATE(trap_table) - trap_table = &trapbase_cpu3; + trap_table = &trapbase_cpu3[0]; INSTANTIATE(trap_table) } #endif diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 15da3c0597a5..a8fb7c0bf053 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -138,10 +138,10 @@ extern unsigned int t_nmi[]; extern unsigned int linux_trap_ipi15_sun4d[]; extern unsigned int linux_trap_ipi15_sun4m[]; -extern struct tt_entry trapbase; -extern struct tt_entry trapbase_cpu1; -extern struct tt_entry trapbase_cpu2; -extern struct tt_entry trapbase_cpu3; +extern struct tt_entry trapbase[]; +extern struct tt_entry trapbase_cpu1[]; +extern struct tt_entry trapbase_cpu2[]; +extern struct tt_entry trapbase_cpu3[]; extern char cputypval[]; diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c index 58ad3f7de1fb..3b2c673ec627 100644 --- a/arch/sparc/kernel/kgdb_32.c +++ b/arch/sparc/kernel/kgdb_32.c @@ -37,7 +37,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) gdb_regs[GDB_Y] = regs->y; gdb_regs[GDB_PSR] = regs->psr; gdb_regs[GDB_WIM] = 0; - gdb_regs[GDB_TBR] = (unsigned long) &trapbase; + gdb_regs[GDB_TBR] = (unsigned long) &trapbase[0]; gdb_regs[GDB_PC] = regs->pc; gdb_regs[GDB_NPC] = regs->npc; gdb_regs[GDB_FSR] = 0; @@ -72,7 +72,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) gdb_regs[GDB_PSR] = t->kpsr; gdb_regs[GDB_WIM] = t->kwim; - gdb_regs[GDB_TBR] = (unsigned long) &trapbase; + gdb_regs[GDB_TBR] = (unsigned long) &trapbase[0]; gdb_regs[GDB_PC] = t->kpc; gdb_regs[GDB_NPC] = t->kpc + 4; gdb_regs[GDB_FSR] = 0; diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 991e9ad3d3e8..1ee393abc463 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -245,13 +245,13 @@ void __init leon_smp_done(void) /* Free unneeded trap tables */ if (!cpu_present(1)) { - free_reserved_page(virt_to_page(&trapbase_cpu1)); + free_reserved_page(virt_to_page(&trapbase_cpu1[0])); } if (!cpu_present(2)) { - free_reserved_page(virt_to_page(&trapbase_cpu2)); + free_reserved_page(virt_to_page(&trapbase_cpu2[0])); } if (!cpu_present(3)) { - free_reserved_page(virt_to_page(&trapbase_cpu3)); + free_reserved_page(virt_to_page(&trapbase_cpu3[0])); } /* Ok, they are spinning and ready to go. */ smp_processors_ready = 1; diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index e3b72a7b46d3..704375c061e7 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -67,7 +67,7 @@ static void prom_sync_me(void) __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t" "nop\n\t" "nop\n\t" - "nop\n\t" : : "r" (&trapbase)); + "nop\n\t" : : "r" (&trapbase[0])); prom_printf("PROM SYNC COMMAND...\n"); show_mem(); @@ -285,7 +285,7 @@ void __init setup_arch(char **cmdline_p) int i; unsigned long highest_paddr; - sparc_ttable = &trapbase; + sparc_ttable = &trapbase[0]; /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); From 6892982316846d4c40d12b0641d59519d868a784 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:24 +0100 Subject: [PATCH 716/814] mtd: maps: sun_uflash: Declare uflash_devinit static This fixes the following warning: sun_uflash.c:50:5: error: no previous prototype for 'uflash_devinit' Signed-off-by: Sam Ravnborg Fixes: 0fcb70851fbf ("Makefile.extrawarn: turn on missing-prototypes globally") Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Cc: Andreas Larsson Cc: "David S. Miller" Reviewed-by: Andreas Larsson Acked-by: Miquel Raynal Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-3-1f186603c5c4@ravnborg.org --- drivers/mtd/maps/sun_uflash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index f58cfb15d6e8..b69dade3f7ad 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -47,7 +47,7 @@ struct map_info uflash_map_templ = { .bankwidth = UFLASH_BUSWIDTH, }; -int uflash_devinit(struct platform_device *op, struct device_node *dp) +static int uflash_devinit(struct platform_device *op, struct device_node *dp) { struct uflash_dev *up; From 99bd9a4f87926e12ce60796d7db1d6b226aca5e3 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:26 +0100 Subject: [PATCH 717/814] sparc32: Do not select GENERIC_ISA_DMA sparc32 do not support generic isa dma, so do not select the symbol. This fixes the following warnings: dma.c:70:5: error: no previous prototype for 'request_dma' [-Werror=missing-prototypes] dma.c:88:6: error: no previous prototype for 'free_dma' [-Werror=missing-prototypes] Signed-off-by: Sam Ravnborg Fixes: 0fcb70851fbf ("Makefile.extrawarn: turn on missing-prototypes globally") Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Cc: Andreas Larsson Cc: "David S. Miller" Cc: Randy Dunlap Cc: Maciej W. Rozycki Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-5-1f186603c5c4@ravnborg.org --- arch/sparc/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 734f23daecca..d08a5662ea60 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -138,10 +138,6 @@ config HIGHMEM default y if SPARC32 select KMAP_LOCAL -config GENERIC_ISA_DMA - bool - default y if SPARC32 - config PGTABLE_LEVELS default 4 if 64BIT default 3 From 91d3ff922c346d6d8cb8de5ff8d504fe0ca9e17e Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:27 +0100 Subject: [PATCH 718/814] sparc32: Fix parport build with sparc32 include/asm/parport.h is sparc64 specific. Rename it to parport_64.h and use the generic version for sparc32. This fixed all{mod,yes}config build errors like: parport_pc.c:(.text):undefined-reference-to-ebus_dma_enable parport_pc.c:(.text):undefined-reference-to-ebus_dma_irq_enable parport_pc.c:(.text):undefined-reference-to-ebus_dma_register The errors occur as the sparc32 build references sparc64 symbols. Signed-off-by: Sam Ravnborg Cc: "David S. Miller" Cc: Andreas Larsson Cc: Randy Dunlap Cc: Maciej W. Rozycki Closes: https://lore.kernel.org/r/20230406160548.25721-1-rdunlap@infradead.org/ Fixes: 66bcd06099bb ("parport_pc: Also enable driver for PCI systems") Cc: stable@vger.kernel.org # v5.18+ Tested-by: Randy Dunlap # build-tested Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-6-1f186603c5c4@ravnborg.org --- arch/sparc/include/asm/parport.h | 259 +--------------------------- arch/sparc/include/asm/parport_64.h | 256 +++++++++++++++++++++++++++ 2 files changed, 263 insertions(+), 252 deletions(-) create mode 100644 arch/sparc/include/asm/parport_64.h diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h index 0a7ffcfd59cd..e2eed8f97665 100644 --- a/arch/sparc/include/asm/parport.h +++ b/arch/sparc/include/asm/parport.h @@ -1,256 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* parport.h: sparc64 specific parport initialization and dma. - * - * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) - */ +#ifndef ___ASM_SPARC_PARPORT_H +#define ___ASM_SPARC_PARPORT_H -#ifndef _ASM_SPARC64_PARPORT_H -#define _ASM_SPARC64_PARPORT_H 1 - -#include -#include - -#include -#include -#include - -#define PARPORT_PC_MAX_PORTS PARPORT_MAX - -/* - * While sparc64 doesn't have an ISA DMA API, we provide something that looks - * close enough to make parport_pc happy - */ -#define HAS_DMA - -#ifdef CONFIG_PARPORT_PC_FIFO -static DEFINE_SPINLOCK(dma_spin_lock); - -#define claim_dma_lock() \ -({ unsigned long flags; \ - spin_lock_irqsave(&dma_spin_lock, flags); \ - flags; \ -}) - -#define release_dma_lock(__flags) \ - spin_unlock_irqrestore(&dma_spin_lock, __flags); +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif #endif -static struct sparc_ebus_info { - struct ebus_dma_info info; - unsigned int addr; - unsigned int count; - int lock; - - struct parport *port; -} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; - -static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); - -static inline int request_dma(unsigned int dmanr, const char *device_id) -{ - if (dmanr >= PARPORT_PC_MAX_PORTS) - return -EINVAL; - if (xchg(&sparc_ebus_dmas[dmanr].lock, 1) != 0) - return -EBUSY; - return 0; -} - -static inline void free_dma(unsigned int dmanr) -{ - if (dmanr >= PARPORT_PC_MAX_PORTS) { - printk(KERN_WARNING "Trying to free DMA%d\n", dmanr); - return; - } - if (xchg(&sparc_ebus_dmas[dmanr].lock, 0) == 0) { - printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr); - return; - } -} - -static inline void enable_dma(unsigned int dmanr) -{ - ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1); - - if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info, - sparc_ebus_dmas[dmanr].addr, - sparc_ebus_dmas[dmanr].count)) - BUG(); -} - -static inline void disable_dma(unsigned int dmanr) -{ - ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0); -} - -static inline void clear_dma_ff(unsigned int dmanr) -{ - /* nothing */ -} - -static inline void set_dma_mode(unsigned int dmanr, char mode) -{ - ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE)); -} - -static inline void set_dma_addr(unsigned int dmanr, unsigned int addr) -{ - sparc_ebus_dmas[dmanr].addr = addr; -} - -static inline void set_dma_count(unsigned int dmanr, unsigned int count) -{ - sparc_ebus_dmas[dmanr].count = count; -} - -static inline unsigned int get_dma_residue(unsigned int dmanr) -{ - return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); -} - -static int ecpp_probe(struct platform_device *op) -{ - unsigned long base = op->resource[0].start; - unsigned long config = op->resource[1].start; - unsigned long d_base = op->resource[2].start; - unsigned long d_len; - struct device_node *parent; - struct parport *p; - int slot, err; - - parent = op->dev.of_node->parent; - if (of_node_name_eq(parent, "dma")) { - p = parport_pc_probe_port(base, base + 0x400, - op->archdata.irqs[0], PARPORT_DMA_NOFIFO, - op->dev.parent->parent, 0); - if (!p) - return -ENOMEM; - dev_set_drvdata(&op->dev, p); - return 0; - } - - for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { - if (!test_and_set_bit(slot, dma_slot_map)) - break; - } - err = -ENODEV; - if (slot >= PARPORT_PC_MAX_PORTS) - goto out_err; - - spin_lock_init(&sparc_ebus_dmas[slot].info.lock); - - d_len = (op->resource[2].end - d_base) + 1UL; - sparc_ebus_dmas[slot].info.regs = - of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); - - if (!sparc_ebus_dmas[slot].info.regs) - goto out_clear_map; - - sparc_ebus_dmas[slot].info.flags = 0; - sparc_ebus_dmas[slot].info.callback = NULL; - sparc_ebus_dmas[slot].info.client_cookie = NULL; - sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; - strcpy(sparc_ebus_dmas[slot].info.name, "parport"); - if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) - goto out_unmap_regs; - - ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); - - /* Configure IRQ to Push Pull, Level Low */ - /* Enable ECP, set bit 2 of the CTR first */ - outb(0x04, base + 0x02); - ns87303_modify(config, PCR, - PCR_EPP_ENABLE | - PCR_IRQ_ODRAIN, - PCR_ECP_ENABLE | - PCR_ECP_CLK_ENA | - PCR_IRQ_POLAR); - - /* CTR bit 5 controls direction of port */ - ns87303_modify(config, PTR, - 0, PTR_LPT_REG_DIR); - - p = parport_pc_probe_port(base, base + 0x400, - op->archdata.irqs[0], - slot, - op->dev.parent, - 0); - err = -ENOMEM; - if (!p) - goto out_disable_irq; - - dev_set_drvdata(&op->dev, p); - - return 0; - -out_disable_irq: - ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); - ebus_dma_unregister(&sparc_ebus_dmas[slot].info); - -out_unmap_regs: - of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); - -out_clear_map: - clear_bit(slot, dma_slot_map); - -out_err: - return err; -} - -static int ecpp_remove(struct platform_device *op) -{ - struct parport *p = dev_get_drvdata(&op->dev); - int slot = p->dma; - - parport_pc_unregister_port(p); - - if (slot != PARPORT_DMA_NOFIFO) { - unsigned long d_base = op->resource[2].start; - unsigned long d_len; - - d_len = (op->resource[2].end - d_base) + 1UL; - - ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); - ebus_dma_unregister(&sparc_ebus_dmas[slot].info); - of_iounmap(&op->resource[2], - sparc_ebus_dmas[slot].info.regs, - d_len); - clear_bit(slot, dma_slot_map); - } - - return 0; -} - -static const struct of_device_id ecpp_match[] = { - { - .name = "ecpp", - }, - { - .name = "parallel", - .compatible = "ecpp", - }, - { - .name = "parallel", - .compatible = "ns87317-ecpp", - }, - { - .name = "parallel", - .compatible = "pnpALI,1533,3", - }, - {}, -}; - -static struct platform_driver ecpp_driver = { - .driver = { - .name = "ecpp", - .of_match_table = ecpp_match, - }, - .probe = ecpp_probe, - .remove = ecpp_remove, -}; - -static int parport_pc_find_nonpci_ports(int autoirq, int autodma) -{ - return platform_driver_register(&ecpp_driver); -} - -#endif /* !(_ASM_SPARC64_PARPORT_H */ diff --git a/arch/sparc/include/asm/parport_64.h b/arch/sparc/include/asm/parport_64.h new file mode 100644 index 000000000000..0a7ffcfd59cd --- /dev/null +++ b/arch/sparc/include/asm/parport_64.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* parport.h: sparc64 specific parport initialization and dma. + * + * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) + */ + +#ifndef _ASM_SPARC64_PARPORT_H +#define _ASM_SPARC64_PARPORT_H 1 + +#include +#include + +#include +#include +#include + +#define PARPORT_PC_MAX_PORTS PARPORT_MAX + +/* + * While sparc64 doesn't have an ISA DMA API, we provide something that looks + * close enough to make parport_pc happy + */ +#define HAS_DMA + +#ifdef CONFIG_PARPORT_PC_FIFO +static DEFINE_SPINLOCK(dma_spin_lock); + +#define claim_dma_lock() \ +({ unsigned long flags; \ + spin_lock_irqsave(&dma_spin_lock, flags); \ + flags; \ +}) + +#define release_dma_lock(__flags) \ + spin_unlock_irqrestore(&dma_spin_lock, __flags); +#endif + +static struct sparc_ebus_info { + struct ebus_dma_info info; + unsigned int addr; + unsigned int count; + int lock; + + struct parport *port; +} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; + +static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); + +static inline int request_dma(unsigned int dmanr, const char *device_id) +{ + if (dmanr >= PARPORT_PC_MAX_PORTS) + return -EINVAL; + if (xchg(&sparc_ebus_dmas[dmanr].lock, 1) != 0) + return -EBUSY; + return 0; +} + +static inline void free_dma(unsigned int dmanr) +{ + if (dmanr >= PARPORT_PC_MAX_PORTS) { + printk(KERN_WARNING "Trying to free DMA%d\n", dmanr); + return; + } + if (xchg(&sparc_ebus_dmas[dmanr].lock, 0) == 0) { + printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr); + return; + } +} + +static inline void enable_dma(unsigned int dmanr) +{ + ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1); + + if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info, + sparc_ebus_dmas[dmanr].addr, + sparc_ebus_dmas[dmanr].count)) + BUG(); +} + +static inline void disable_dma(unsigned int dmanr) +{ + ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0); +} + +static inline void clear_dma_ff(unsigned int dmanr) +{ + /* nothing */ +} + +static inline void set_dma_mode(unsigned int dmanr, char mode) +{ + ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE)); +} + +static inline void set_dma_addr(unsigned int dmanr, unsigned int addr) +{ + sparc_ebus_dmas[dmanr].addr = addr; +} + +static inline void set_dma_count(unsigned int dmanr, unsigned int count) +{ + sparc_ebus_dmas[dmanr].count = count; +} + +static inline unsigned int get_dma_residue(unsigned int dmanr) +{ + return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); +} + +static int ecpp_probe(struct platform_device *op) +{ + unsigned long base = op->resource[0].start; + unsigned long config = op->resource[1].start; + unsigned long d_base = op->resource[2].start; + unsigned long d_len; + struct device_node *parent; + struct parport *p; + int slot, err; + + parent = op->dev.of_node->parent; + if (of_node_name_eq(parent, "dma")) { + p = parport_pc_probe_port(base, base + 0x400, + op->archdata.irqs[0], PARPORT_DMA_NOFIFO, + op->dev.parent->parent, 0); + if (!p) + return -ENOMEM; + dev_set_drvdata(&op->dev, p); + return 0; + } + + for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { + if (!test_and_set_bit(slot, dma_slot_map)) + break; + } + err = -ENODEV; + if (slot >= PARPORT_PC_MAX_PORTS) + goto out_err; + + spin_lock_init(&sparc_ebus_dmas[slot].info.lock); + + d_len = (op->resource[2].end - d_base) + 1UL; + sparc_ebus_dmas[slot].info.regs = + of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); + + if (!sparc_ebus_dmas[slot].info.regs) + goto out_clear_map; + + sparc_ebus_dmas[slot].info.flags = 0; + sparc_ebus_dmas[slot].info.callback = NULL; + sparc_ebus_dmas[slot].info.client_cookie = NULL; + sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; + strcpy(sparc_ebus_dmas[slot].info.name, "parport"); + if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) + goto out_unmap_regs; + + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); + + /* Configure IRQ to Push Pull, Level Low */ + /* Enable ECP, set bit 2 of the CTR first */ + outb(0x04, base + 0x02); + ns87303_modify(config, PCR, + PCR_EPP_ENABLE | + PCR_IRQ_ODRAIN, + PCR_ECP_ENABLE | + PCR_ECP_CLK_ENA | + PCR_IRQ_POLAR); + + /* CTR bit 5 controls direction of port */ + ns87303_modify(config, PTR, + 0, PTR_LPT_REG_DIR); + + p = parport_pc_probe_port(base, base + 0x400, + op->archdata.irqs[0], + slot, + op->dev.parent, + 0); + err = -ENOMEM; + if (!p) + goto out_disable_irq; + + dev_set_drvdata(&op->dev, p); + + return 0; + +out_disable_irq: + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); + ebus_dma_unregister(&sparc_ebus_dmas[slot].info); + +out_unmap_regs: + of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); + +out_clear_map: + clear_bit(slot, dma_slot_map); + +out_err: + return err; +} + +static int ecpp_remove(struct platform_device *op) +{ + struct parport *p = dev_get_drvdata(&op->dev); + int slot = p->dma; + + parport_pc_unregister_port(p); + + if (slot != PARPORT_DMA_NOFIFO) { + unsigned long d_base = op->resource[2].start; + unsigned long d_len; + + d_len = (op->resource[2].end - d_base) + 1UL; + + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); + ebus_dma_unregister(&sparc_ebus_dmas[slot].info); + of_iounmap(&op->resource[2], + sparc_ebus_dmas[slot].info.regs, + d_len); + clear_bit(slot, dma_slot_map); + } + + return 0; +} + +static const struct of_device_id ecpp_match[] = { + { + .name = "ecpp", + }, + { + .name = "parallel", + .compatible = "ecpp", + }, + { + .name = "parallel", + .compatible = "ns87317-ecpp", + }, + { + .name = "parallel", + .compatible = "pnpALI,1533,3", + }, + {}, +}; + +static struct platform_driver ecpp_driver = { + .driver = { + .name = "ecpp", + .of_match_table = ecpp_match, + }, + .probe = ecpp_probe, + .remove = ecpp_remove, +}; + +static int parport_pc_find_nonpci_ports(int autoirq, int autodma) +{ + return platform_driver_register(&ecpp_driver); +} + +#endif /* !(_ASM_SPARC64_PARPORT_H */ From 24338a6ae13cb743ced77da1b3a12c83f08a0c96 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 24 Feb 2024 18:42:28 +0100 Subject: [PATCH 719/814] sparc32: Fix section mismatch in leon_pci_grpci Passing a datastructre marked _initconst to platform_driver_register() is wrong. Drop the __initconst notation. This fixes the following warnings: WARNING: modpost: vmlinux: section mismatch in reference: grpci1_of_driver+0x30 (section: .data) -> grpci1_of_match (section: .init.rodata) WARNING: modpost: vmlinux: section mismatch in reference: grpci2_of_driver+0x30 (section: .data) -> grpci2_of_match (section: .init.rodata) Signed-off-by: Sam Ravnborg Cc: "David S. Miller" Cc: Andreas Larsson Fixes: 4154bb821f0b ("sparc: leon: grpci1: constify of_device_id") Fixes: 03949b1cb9f1 ("sparc: leon: grpci2: constify of_device_id") Tested-by: Randy Dunlap # build-tested Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/20240224-sam-fix-sparc32-all-builds-v2-7-1f186603c5c4@ravnborg.org --- arch/sparc/kernel/leon_pci_grpci1.c | 2 +- arch/sparc/kernel/leon_pci_grpci2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c index 8700a0e3b0df..b2b639bee068 100644 --- a/arch/sparc/kernel/leon_pci_grpci1.c +++ b/arch/sparc/kernel/leon_pci_grpci1.c @@ -697,7 +697,7 @@ err1: return err; } -static const struct of_device_id grpci1_of_match[] __initconst = { +static const struct of_device_id grpci1_of_match[] = { { .name = "GAISLER_PCIFBRG", }, diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index 282b49d496ea..9f662340b5b2 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -889,7 +889,7 @@ err1: return err; } -static const struct of_device_id grpci2_of_match[] __initconst = { +static const struct of_device_id grpci2_of_match[] = { { .name = "GAISLER_GRPCI2", }, From 61fc8d40676c0742882f86071ced8f2b81c488bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:08 +0100 Subject: [PATCH 720/814] sbus: Add prototype for bbc_envctrl_init and bbc_envctrl_cleanup to header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following build warning: drivers/sbus/char/bbc_envctrl.c:566:5: error: no previous prototype for ‘bbc_envctrl_init’ [-Werror=missing-prototypes] 566 | int bbc_envctrl_init(struct bbc_i2c_bus *bp) | ^~~~~~~~~~~~~~~~ drivers/sbus/char/bbc_envctrl.c:594:6: error: no previous prototype for ‘bbc_envctrl_cleanup’ [-Werror=missing-prototypes] 594 | void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) | ^~~~~~~~~~~~~~~~~~~ which in the presence of -Werror=missing-prototypes yields a compiler error. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/57bc3b43b405431a486162fb8c2558072e976747.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/bbc_i2c.c | 3 --- drivers/sbus/char/bbc_i2c.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 1c76e27d527a..970e04d8937d 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -358,9 +358,6 @@ fail: return NULL; } -extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); -extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); - static int bbc_i2c_probe(struct platform_device *op) { struct bbc_i2c_bus *bp; diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h index 7ffe908c62dc..6c748836754b 100644 --- a/drivers/sbus/char/bbc_i2c.h +++ b/drivers/sbus/char/bbc_i2c.h @@ -82,4 +82,7 @@ extern int bbc_i2c_readb(struct bbc_i2c_client *, unsigned char *byte, int off); extern int bbc_i2c_write_buf(struct bbc_i2c_client *, char *buf, int len, int off); extern int bbc_i2c_read_buf(struct bbc_i2c_client *, char *buf, int len, int off); +extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); +extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); + #endif /* _BBC_I2C_H */ From d0e71777f7eb15aed8cd26dcc4a325236c5bca97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:09 +0100 Subject: [PATCH 721/814] sbus: bbc_i2c: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/a5ba9d930451d1eeabc4208cc6c75184a92a248d.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/bbc_i2c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 970e04d8937d..3192dcb83b86 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -382,7 +382,7 @@ static int bbc_i2c_probe(struct platform_device *op) return err; } -static int bbc_i2c_remove(struct platform_device *op) +static void bbc_i2c_remove(struct platform_device *op) { struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); @@ -396,8 +396,6 @@ static int bbc_i2c_remove(struct platform_device *op) of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); kfree(bp); - - return 0; } static const struct of_device_id bbc_i2c_match[] = { @@ -415,7 +413,7 @@ static struct platform_driver bbc_i2c_driver = { .of_match_table = bbc_i2c_match, }, .probe = bbc_i2c_probe, - .remove = bbc_i2c_remove, + .remove_new = bbc_i2c_remove, }; module_platform_driver(bbc_i2c_driver); From 3f35533053a4e9983e507ba773d5f908c97b049f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:10 +0100 Subject: [PATCH 722/814] sbus: display7seg: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/dc10c77a6ababab6ffdb344982e8a04cc337bdc7.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/display7seg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 18e6f84e754f..521cf8affe65 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -229,7 +229,7 @@ out_iounmap: goto out; } -static int d7s_remove(struct platform_device *op) +static void d7s_remove(struct platform_device *op) { struct d7s *p = dev_get_drvdata(&op->dev); u8 regs = readb(p->regs); @@ -245,8 +245,6 @@ static int d7s_remove(struct platform_device *op) misc_deregister(&d7s_miscdev); of_iounmap(&op->resource[0], p->regs, sizeof(u8)); - - return 0; } static const struct of_device_id d7s_match[] = { @@ -263,7 +261,7 @@ static struct platform_driver d7s_driver = { .of_match_table = d7s_match, }, .probe = d7s_probe, - .remove = d7s_remove, + .remove_new = d7s_remove, }; module_platform_driver(d7s_driver); From 09c531e06048fa300f64616a6703f0ab9592dc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:11 +0100 Subject: [PATCH 723/814] sbus: envctrl: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/0b61ed6fb4ebe2880951b1e849551dbc63402802.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/envctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 3dd7274cb0a3..491cc6c0b3f9 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1097,7 +1097,7 @@ out_iounmap: return err; } -static int envctrl_remove(struct platform_device *op) +static void envctrl_remove(struct platform_device *op) { int index; @@ -1108,8 +1108,6 @@ static int envctrl_remove(struct platform_device *op) for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) kfree(i2c_childlist[index].tables); - - return 0; } static const struct of_device_id envctrl_match[] = { @@ -1127,7 +1125,7 @@ static struct platform_driver envctrl_driver = { .of_match_table = envctrl_match, }, .probe = envctrl_probe, - .remove = envctrl_remove, + .remove_new = envctrl_remove, }; module_platform_driver(envctrl_driver); From e81a3214e6b57f0bc587eeaaf53ef4634168794b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:12 +0100 Subject: [PATCH 724/814] sbus: flash: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/a9c6351fc24c40d011697cd7540950f412507965.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/flash.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index ea2d903ba673..05d37d31c3b8 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -187,11 +187,9 @@ static int flash_probe(struct platform_device *op) return misc_register(&flash_dev); } -static int flash_remove(struct platform_device *op) +static void flash_remove(struct platform_device *op) { misc_deregister(&flash_dev); - - return 0; } static const struct of_device_id flash_match[] = { @@ -208,7 +206,7 @@ static struct platform_driver flash_driver = { .of_match_table = flash_match, }, .probe = flash_probe, - .remove = flash_remove, + .remove_new = flash_remove, }; module_platform_driver(flash_driver); From 024a5e6b96e745cb0fe30487cd9a9055d5c40e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 23:30:13 +0100 Subject: [PATCH 725/814] sbus: uctrl: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson Link: https://lore.kernel.org/r/59b07175ca590031ee28c11c5941384ab3603799.1709591118.git.u.kleine-koenig@pengutronix.de --- drivers/sbus/char/uctrl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 0660425e3a5a..cf15a4186d03 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -399,7 +399,7 @@ out_free: goto out; } -static int uctrl_remove(struct platform_device *op) +static void uctrl_remove(struct platform_device *op) { struct uctrl_driver *p = dev_get_drvdata(&op->dev); @@ -409,7 +409,6 @@ static int uctrl_remove(struct platform_device *op) of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); kfree(p); } - return 0; } static const struct of_device_id uctrl_match[] = { @@ -426,7 +425,7 @@ static struct platform_driver uctrl_driver = { .of_match_table = uctrl_match, }, .probe = uctrl_probe, - .remove = uctrl_remove, + .remove_new = uctrl_remove, }; From 84b76d05828a1909e20d0f66553b876b801f98c8 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 7 Mar 2024 19:07:42 +0100 Subject: [PATCH 726/814] lib/fonts: Allow Sparc console 8x16 font for sparc64 early boot text console Allow FONT_SUN8x16 when EARLYFB is enabled for sparc64, even when FRAMEBUFFER_CONSOLE is not to avoid the following warning for this case WARNING: unmet direct dependencies detected for FONT_SUN8x16 Depends on [n]: FONT_SUPPORT [=y] && (FRAMEBUFFER_CONSOLE [=n] && (FONTS [=n] || SPARC [=y]) || BOOTX_TEXT) Selected by [y]: - EARLYFB [=y] && SPARC64 [=y] by allowing it in the same manner as is done for powerpc in commit 0ebc7feae79a ("powerpc: Use shared font data"). Signed-off-by: Andreas Larsson Fixes: 0f1991949d9b ("sparc: Use shared font data") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402241539.epQT43nI-lkp@intel.com/ Cc: "Dr. David Alan Gilbert" Cc: Michael Ellerman Cc: Sam Ravnborg Cc: Randy Dunlap Cc: "David S. Miller" Reviewed-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240307180742.900068-1-andreas@gaisler.com --- lib/fonts/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fonts/Kconfig b/lib/fonts/Kconfig index 7ee468ef21ec..7e945fdcbf11 100644 --- a/lib/fonts/Kconfig +++ b/lib/fonts/Kconfig @@ -98,7 +98,8 @@ config FONT_10x18 config FONT_SUN8x16 bool "Sparc console 8x16 font" - depends on (FRAMEBUFFER_CONSOLE && (FONTS || SPARC)) || BOOTX_TEXT + depends on (FRAMEBUFFER_CONSOLE && (FONTS || SPARC)) || \ + BOOTX_TEXT || EARLYFB help This is the high resolution console font for Sun machines. Say Y. From 1099a04ccc9b4d2b9d5dcd33d9bb9c333e147e8d Mon Sep 17 00:00:00 2001 From: Dharma Balasubiramani Date: Fri, 9 Feb 2024 12:17:55 +0530 Subject: [PATCH 727/814] dt-bindings: input: atmel,captouch: convert bindings to YAML Convert the Atmel capacitive touchscreen bindings to YAML format. Signed-off-by: Dharma Balasubiramani Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240209064755.47516-1-dharma.b@microchip.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/atmel,captouch.txt | 36 ----------- .../bindings/input/atmel,captouch.yaml | 59 +++++++++++++++++++ 2 files changed, 59 insertions(+), 36 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/atmel,captouch.txt create mode 100644 Documentation/devicetree/bindings/input/atmel,captouch.yaml diff --git a/Documentation/devicetree/bindings/input/atmel,captouch.txt b/Documentation/devicetree/bindings/input/atmel,captouch.txt deleted file mode 100644 index fe9ee5c53bcc..000000000000 --- a/Documentation/devicetree/bindings/input/atmel,captouch.txt +++ /dev/null @@ -1,36 +0,0 @@ -Device tree bindings for Atmel capacitive touch device, typically -an Atmel touch sensor connected to AtmegaXX MCU running firmware -based on Qtouch library. - -The node for this device must be a child of a I2C controller node, as the -device communicates via I2C. - -Required properties: - - compatible: Must be "atmel,captouch". - reg: The I2C slave address of the device. - interrupts: Property describing the interrupt line the device - is connected to. The device only has one interrupt - source. - linux,keycodes: Specifies an array of numeric keycode values to - be used for reporting button presses. The array can - contain up to 8 entries. - -Optional properties: - - autorepeat: Enables the Linux input system's autorepeat - feature on the input device. - -Example: - - atmel-captouch@51 { - compatible = "atmel,captouch"; - reg = <0x51>; - interrupt-parent = <&tlmm>; - interrupts = <67 IRQ_TYPE_EDGE_FALLING>; - linux,keycodes = , , - , , - , , - , ; - autorepeat; - }; diff --git a/Documentation/devicetree/bindings/input/atmel,captouch.yaml b/Documentation/devicetree/bindings/input/atmel,captouch.yaml new file mode 100644 index 000000000000..f7477091d5a6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/atmel,captouch.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/atmel,captouch.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel capacitive touch device + +maintainers: + - Dharma balasubiramani + +description: + Atmel capacitive touch device, typically an Atmel touch sensor connected to + AtmegaXX MCU running firmware based on Qtouch library. + +allOf: + - $ref: input.yaml# + +properties: + compatible: + const: atmel,captouch + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + linux,keycodes: + minItems: 1 + maxItems: 8 + +required: + - compatible + - reg + - interrupts + - linux,keycodes + +unevaluatedProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touch@51 { + compatible = "atmel,captouch"; + reg = <0x51>; + interrupt-parent = <&tlmm>; + interrupts = <67 IRQ_TYPE_EDGE_FALLING>; + linux,keycodes = , , + , , + , , + , ; + autorepeat; + }; + }; From fd5860ab6341506004219b080aea40213b299d2e Mon Sep 17 00:00:00 2001 From: Dave Wysochanski Date: Wed, 31 Jan 2024 11:10:06 -0500 Subject: [PATCH 728/814] NFS: Fix nfs_netfs_issue_read() xarray locking for writeback interrupt The loop inside nfs_netfs_issue_read() currently does not disable interrupts while iterating through pages in the xarray to submit for NFS read. This is not safe though since after taking xa_lock, another page in the mapping could be processed for writeback inside an interrupt, and deadlock can occur. The fix is simple and clean if we use xa_for_each_range(), which handles the iteration with RCU while reducing code complexity. The problem is easily reproduced with the following test: mount -o vers=3,fsc 127.0.0.1:/export /mnt/nfs dd if=/dev/zero of=/mnt/nfs/file1.bin bs=4096 count=1 echo 3 > /proc/sys/vm/drop_caches dd if=/mnt/nfs/file1.bin of=/dev/null umount /mnt/nfs On the console with a lockdep-enabled kernel a message similar to the following will be seen: ================================ WARNING: inconsistent lock state 6.7.0-lockdbg+ #10 Not tainted -------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. test5/1708 [HC0[0]:SC0[0]:HE1:SE1] takes: ffff888127baa598 (&xa->xa_lock#4){+.?.}-{3:3}, at: nfs_netfs_issue_read+0x1b2/0x4b0 [nfs] {IN-SOFTIRQ-W} state was registered at: lock_acquire+0x144/0x380 _raw_spin_lock_irqsave+0x4e/0xa0 __folio_end_writeback+0x17e/0x5c0 folio_end_writeback+0x93/0x1b0 iomap_finish_ioend+0xeb/0x6a0 blk_update_request+0x204/0x7f0 blk_mq_end_request+0x30/0x1c0 blk_complete_reqs+0x7e/0xa0 __do_softirq+0x113/0x544 __irq_exit_rcu+0xfe/0x120 irq_exit_rcu+0xe/0x20 sysvec_call_function_single+0x6f/0x90 asm_sysvec_call_function_single+0x1a/0x20 pv_native_safe_halt+0xf/0x20 default_idle+0x9/0x20 default_idle_call+0x67/0xa0 do_idle+0x2b5/0x300 cpu_startup_entry+0x34/0x40 start_secondary+0x19d/0x1c0 secondary_startup_64_no_verify+0x18f/0x19b irq event stamp: 176891 hardirqs last enabled at (176891): [] _raw_spin_unlock_irqrestore+0x44/0x60 hardirqs last disabled at (176890): [] _raw_spin_lock_irqsave+0x79/0xa0 softirqs last enabled at (176646): [] __irq_exit_rcu+0xfe/0x120 softirqs last disabled at (176633): [] __irq_exit_rcu+0xfe/0x120 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&xa->xa_lock#4); lock(&xa->xa_lock#4); *** DEADLOCK *** 2 locks held by test5/1708: #0: ffff888127baa498 (&sb->s_type->i_mutex_key#22){++++}-{4:4}, at: nfs_start_io_read+0x28/0x90 [nfs] #1: ffff888127baa650 (mapping.invalidate_lock#3){.+.+}-{4:4}, at: page_cache_ra_unbounded+0xa4/0x280 stack backtrace: CPU: 6 PID: 1708 Comm: test5 Kdump: loaded Not tainted 6.7.0-lockdbg+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-1.fc39 04/01/2014 Call Trace: dump_stack_lvl+0x5b/0x90 mark_lock+0xb3f/0xd20 __lock_acquire+0x77b/0x3360 _raw_spin_lock+0x34/0x80 nfs_netfs_issue_read+0x1b2/0x4b0 [nfs] netfs_begin_read+0x77f/0x980 [netfs] nfs_netfs_readahead+0x45/0x60 [nfs] nfs_readahead+0x323/0x5a0 [nfs] read_pages+0xf3/0x5c0 page_cache_ra_unbounded+0x1c8/0x280 filemap_get_pages+0x38c/0xae0 filemap_read+0x206/0x5e0 nfs_file_read+0xb7/0x140 [nfs] vfs_read+0x2a9/0x460 ksys_read+0xb7/0x140 Fixes: 000dbe0bec05 ("NFS: Convert buffered read paths to use netfs when fscache is enabled") Suggested-by: Jeff Layton Signed-off-by: Dave Wysochanski Reviewed-by: Jeff Layton Reviewed-by: David Howells Signed-off-by: Trond Myklebust --- fs/nfs/fscache.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 2d1bfee225c3..ddc1ee031955 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c @@ -301,11 +301,11 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq) struct inode *inode = sreq->rreq->inode; struct nfs_open_context *ctx = sreq->rreq->netfs_priv; struct page *page; + unsigned long idx; int err; pgoff_t start = (sreq->start + sreq->transferred) >> PAGE_SHIFT; pgoff_t last = ((sreq->start + sreq->len - sreq->transferred - 1) >> PAGE_SHIFT); - XA_STATE(xas, &sreq->rreq->mapping->i_pages, start); nfs_pageio_init_read(&pgio, inode, false, &nfs_async_read_completion_ops); @@ -316,19 +316,14 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq) pgio.pg_netfs = netfs; /* used in completion */ - xas_lock(&xas); - xas_for_each(&xas, page, last) { + xa_for_each_range(&sreq->rreq->mapping->i_pages, idx, page, start, last) { /* nfs_read_add_folio() may schedule() due to pNFS layout and other RPCs */ - xas_pause(&xas); - xas_unlock(&xas); err = nfs_read_add_folio(&pgio, ctx, page_folio(page)); if (err < 0) { netfs->error = err; goto out; } - xas_lock(&xas); } - xas_unlock(&xas); out: nfs_pageio_complete_read(&pgio); nfs_netfs_put(netfs); From 7e5ae43b2d0eb89560bf7da7c9c745d31bf72ffe Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Fri, 2 Feb 2024 15:21:13 -0500 Subject: [PATCH 729/814] NFSv4.1: add tracepoint to trunked nfs4_exchange_id calls Add a tracepoint to track when the client sends EXCHANGE_ID to test a new transport for session trunking. nfs4_detect_session_trunking() tests for trunking and returns EINVAL if trunking can't be done, add EINVAL mapping to show_nfs4_status() in tracepoints. Signed-off-by: Olga Kornievskaia Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 6 ++++-- fs/nfs/nfs4trace.h | 30 ++++++++++++++++++++++++++++++ include/trace/misc/nfs.h | 1 + 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b2ff8c7a2149..206b4607b29a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8970,10 +8970,12 @@ try_again: return; status = task->tk_status; - if (status == 0) + if (status == 0) { status = nfs4_detect_session_trunking(adata->clp, task->tk_msg.rpc_resp, xprt); - + trace_nfs4_trunked_exchange_id(adata->clp, + xprt->address_strings[RPC_DISPLAY_ADDR], status); + } if (status == 0) rpc_clnt_xprt_switch_add_xprt(clnt, xprt); else if (status != -NFS4ERR_DELAY && rpc_clnt_xprt_switch_has_addr(clnt, diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 713d080fd268..7d9cb980865d 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -77,6 +77,36 @@ DEFINE_NFS4_CLIENTID_EVENT(nfs4_bind_conn_to_session); DEFINE_NFS4_CLIENTID_EVENT(nfs4_sequence); DEFINE_NFS4_CLIENTID_EVENT(nfs4_reclaim_complete); +TRACE_EVENT(nfs4_trunked_exchange_id, + TP_PROTO( + const struct nfs_client *clp, + const char *addr, + int error + ), + + TP_ARGS(clp, addr, error), + + TP_STRUCT__entry( + __string(main_addr, clp->cl_hostname) + __string(trunk_addr, addr) + __field(unsigned long, error) + ), + + TP_fast_assign( + __entry->error = error < 0 ? -error : 0; + __assign_str(main_addr, clp->cl_hostname); + __assign_str(trunk_addr, addr); + ), + + TP_printk( + "error=%ld (%s) main_addr=%s trunk_addr=%s", + -__entry->error, + show_nfs4_status(__entry->error), + __get_str(main_addr), + __get_str(trunk_addr) + ) +); + TRACE_EVENT(nfs4_sequence_done, TP_PROTO( const struct nfs4_session *session, diff --git a/include/trace/misc/nfs.h b/include/trace/misc/nfs.h index 0d9d48dca38a..5387eb0a6a08 100644 --- a/include/trace/misc/nfs.h +++ b/include/trace/misc/nfs.h @@ -239,6 +239,7 @@ TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_PNFS); { EHOSTDOWN, "EHOSTDOWN" }, \ { EPIPE, "EPIPE" }, \ { EPFNOSUPPORT, "EPFNOSUPPORT" }, \ + { EINVAL, "EINVAL" }, \ { EPROTONOSUPPORT, "EPROTONOSUPPORT" }, \ { NFS4ERR_ACCESS, "ACCESS" }, \ { NFS4ERR_ATTRNOTSUPP, "ATTRNOTSUPP" }, \ From edc99a2dd3ce07f61c379e641e417c07226be5ec Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 15 Feb 2024 13:42:40 -0500 Subject: [PATCH 730/814] nfs: remove unused NFS_CALL macro Nothing uses this, and thank goodness, as the syntax looks horrid. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/nfs_xdr.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 539b57fbf3ce..d09b9773b20c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1820,13 +1820,6 @@ struct nfs_rpc_ops { void (*disable_swap)(struct inode *inode); }; -/* - * NFS_CALL(getattr, inode, (fattr)); - * into - * NFS_PROTO(inode)->getattr(fattr); - */ -#define NFS_CALL(op, inode, args) NFS_PROTO(inode)->op args - /* * Function vectors etc. for the NFS client */ From 2057a48d0dd00c6a2a94ded7df2bf1d3f2a4a0da Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 15 Feb 2024 14:57:30 -0500 Subject: [PATCH 731/814] sunrpc: add a struct rpc_stats arg to rpc_create_args We want to be able to have our rpc stats handled in a per network namespace manner, so add an option to rpc_create_args to specify a different rpc_stats struct instead of using the one on the rpc_program. Signed-off-by: Josef Bacik Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 1 + net/sunrpc/clnt.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 5e9d1469c6fa..5321585c778f 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -139,6 +139,7 @@ struct rpc_create_args { const char *servername; const char *nodename; const struct rpc_program *program; + struct rpc_stat *stats; u32 prognumber; /* overrides program->number */ u32 version; rpc_authflavor_t authflavor; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index cda0935a68c9..28f3749f6dc6 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -405,7 +405,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, clnt->cl_maxproc = version->nrprocs; clnt->cl_prog = args->prognumber ? : program->number; clnt->cl_vers = version->number; - clnt->cl_stats = program->stats; + clnt->cl_stats = args->stats ? : program->stats; clnt->cl_metrics = rpc_alloc_iostats(clnt); rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects); err = -ENOMEM; @@ -691,6 +691,7 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt) .version = clnt->cl_vers, .authflavor = clnt->cl_auth->au_flavor, .cred = clnt->cl_cred, + .stats = clnt->cl_stats, }; return __rpc_clone_client(&args, clnt); } @@ -713,6 +714,7 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor) .version = clnt->cl_vers, .authflavor = flavor, .cred = clnt->cl_cred, + .stats = clnt->cl_stats, }; return __rpc_clone_client(&args, clnt); } @@ -1068,6 +1070,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, .version = vers, .authflavor = old->cl_auth->au_flavor, .cred = old->cl_cred, + .stats = old->cl_stats, }; struct rpc_clnt *clnt; int err; From d47151b79e3220e72ae323b8b8e9d6da20dc884e Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 15 Feb 2024 14:57:31 -0500 Subject: [PATCH 732/814] nfs: expose /proc/net/sunrpc/nfs in net namespaces We're using nfs mounts inside of containers in production and noticed that the nfs stats are not exposed in /proc. This is a problem for us as we use these stats for monitoring, and have to do this awkward bind mount from the main host into the container in order to get to these states. Add the rpc_proc_register call to the pernet operations entry and exit points so these stats can be exposed inside of network namespaces. Signed-off-by: Josef Bacik Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index ebb8d60e1152..e11e9c34aa56 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -2427,11 +2427,13 @@ EXPORT_SYMBOL_GPL(nfs_net_id); static int nfs_net_init(struct net *net) { nfs_clients_init(net); + rpc_proc_register(net, &nfs_rpcstat); return nfs_fs_proc_net_init(net); } static void nfs_net_exit(struct net *net) { + rpc_proc_unregister(net, "nfs"); nfs_fs_proc_net_exit(net); nfs_clients_exit(net); } @@ -2486,15 +2488,12 @@ static int __init init_nfs_fs(void) if (err) goto out1; - rpc_proc_register(&init_net, &nfs_rpcstat); - err = register_nfs_fs(); if (err) goto out0; return 0; out0: - rpc_proc_unregister(&init_net, "nfs"); nfs_destroy_directcache(); out1: nfs_destroy_writepagecache(); @@ -2524,7 +2523,6 @@ static void __exit exit_nfs_fs(void) nfs_destroy_inodecache(); nfs_destroy_nfspagecache(); unregister_pernet_subsys(&nfs_net_ops); - rpc_proc_unregister(&init_net, "nfs"); unregister_nfs_fs(); nfs_fs_proc_exit(); nfsiod_stop(); From 1548036ef1204df65ca5a16e8b199c858cb80075 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 15 Feb 2024 14:57:32 -0500 Subject: [PATCH 733/814] nfs: make the rpc_stat per net namespace Now that we're exposing the rpc stats on a per-network namespace basis, move this struct into struct nfs_net and use that to make sure only the per-network namespace stats are exposed. Signed-off-by: Josef Bacik Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 5 ++++- fs/nfs/inode.c | 4 +++- fs/nfs/internal.h | 2 -- fs/nfs/netns.h | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index fbdc9ca80f71..a8fad331dff6 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -73,7 +73,6 @@ const struct rpc_program nfs_program = { .number = NFS_PROGRAM, .nrvers = ARRAY_SIZE(nfs_version), .version = nfs_version, - .stats = &nfs_rpcstat, .pipe_dir_name = NFS_PIPE_DIRNAME, }; @@ -502,6 +501,7 @@ int nfs_create_rpc_client(struct nfs_client *clp, const struct nfs_client_initdata *cl_init, rpc_authflavor_t flavor) { + struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); struct rpc_clnt *clnt = NULL; struct rpc_create_args args = { .net = clp->cl_net, @@ -513,6 +513,7 @@ int nfs_create_rpc_client(struct nfs_client *clp, .servername = clp->cl_hostname, .nodename = cl_init->nodename, .program = &nfs_program, + .stats = &nn->rpcstats, .version = clp->rpc_ops->version, .authflavor = flavor, .cred = cl_init->cred, @@ -1182,6 +1183,8 @@ void nfs_clients_init(struct net *net) #endif spin_lock_init(&nn->nfs_client_lock); nn->boot_time = ktime_get_real(); + memset(&nn->rpcstats, 0, sizeof(nn->rpcstats)); + nn->rpcstats.program = &nfs_program; nfs_netns_sysfs_setup(nn, net); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e11e9c34aa56..91b4d811958a 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -2426,8 +2426,10 @@ EXPORT_SYMBOL_GPL(nfs_net_id); static int nfs_net_init(struct net *net) { + struct nfs_net *nn = net_generic(net, nfs_net_id); + nfs_clients_init(net); - rpc_proc_register(net, &nfs_rpcstat); + rpc_proc_register(net, &nn->rpcstats); return nfs_fs_proc_net_init(net); } diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e3722ce6722e..06253695fe53 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -449,8 +449,6 @@ int nfs_try_get_tree(struct fs_context *); int nfs_get_tree_common(struct fs_context *); void nfs_kill_super(struct super_block *); -extern struct rpc_stat nfs_rpcstat; - extern int __init register_nfs_fs(void); extern void __exit unregister_nfs_fs(void); extern bool nfs_sb_active(struct super_block *sb); diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index c8374f74dce1..a68b21603ea9 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -9,6 +9,7 @@ #include #include #include +#include struct bl_dev_msg { int32_t status; @@ -34,6 +35,7 @@ struct nfs_net { struct nfs_netns_client *nfs_client; spinlock_t nfs_client_lock; ktime_t boot_time; + struct rpc_stat rpcstats; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_nfsfs; #endif From 698ad1a538da0b6bf969cfee630b4e3a026afb87 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 18 Feb 2024 22:16:53 +0100 Subject: [PATCH 734/814] NFS: Fix an off by one in root_nfs_cat() The intent is to check if 'dest' is truncated or not. So, >= should be used instead of >, because strlcat() returns the length of 'dest' and 'src' excluding the trailing NULL. Fixes: 56463e50d1fc ("NFS: Use super.c for NFSROOT mount option parsing") Signed-off-by: Christophe JAILLET Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust --- fs/nfs/nfsroot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 7600100ba26f..432612d22437 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -175,10 +175,10 @@ static int __init root_nfs_cat(char *dest, const char *src, size_t len = strlen(dest); if (len && dest[len - 1] != ',') - if (strlcat(dest, ",", destlen) > destlen) + if (strlcat(dest, ",", destlen) >= destlen) return -1; - if (strlcat(dest, src, destlen) > destlen) + if (strlcat(dest, src, destlen) >= destlen) return -1; return 0; } From a35518cae4b325632840bc8c3aa9ad9bac430038 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Tue, 20 Feb 2024 18:25:34 -0500 Subject: [PATCH 735/814] NFSv4.1/pnfs: fix NFS with TLS in pnfs Currently, even though xprtsec=tls is specified and used for operations to MDS, any operations that go to DS travel over unencrypted connection. Or additionally, if more than 1 DS can serve the data, then trunked connections are also done unencrypted. IN GETDEVINCEINFO, we get an entry for the DS which carries a protocol type (which is TCP), then nfs4_set_ds_client() gets called with TCP instead of TCP with TLS. Currently, each trunked connection is created and uses clp->cl_hostname value which if TLS is used would get passed up in the handshake upcall, but instead we need to pass in the appropriate trunked address value. Fixes: c8407f2e560c ("NFS: Add an "xprtsec=" NFS mount option") Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust --- fs/nfs/pnfs_nfs.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index afd23910f3bf..88e061bd711b 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c @@ -919,6 +919,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr); list_for_each_entry(da, &ds->ds_addrs, da_node) { + char servername[48]; + dprintk("%s: DS %s: trying address %s\n", __func__, ds->ds_remotestr, da->da_remotestr); @@ -929,6 +931,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, .dstaddr = (struct sockaddr *)&da->da_addr, .addrlen = da->da_addrlen, .servername = clp->cl_hostname, + .xprtsec = clp->cl_xprtsec, }; struct nfs4_add_xprt_data xprtdata = { .clp = clp, @@ -938,10 +941,45 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, .data = &xprtdata, }; - if (da->da_transport != clp->cl_proto) + if (da->da_transport != clp->cl_proto && + clp->cl_proto != XPRT_TRANSPORT_TCP_TLS) continue; + if (da->da_transport == XPRT_TRANSPORT_TCP && + mds_srv->nfs_client->cl_proto == + XPRT_TRANSPORT_TCP_TLS) { + struct sockaddr *addr = + (struct sockaddr *)&da->da_addr; + struct sockaddr_in *sin = + (struct sockaddr_in *)&da->da_addr; + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&da->da_addr; + + /* for NFS with TLS we need to supply a correct + * servername of the trunked transport, not the + * servername of the main transport stored in + * clp->cl_hostname. And set the protocol to + * indicate to use TLS + */ + servername[0] = '\0'; + switch(addr->sa_family) { + case AF_INET: + snprintf(servername, sizeof(servername), + "%pI4", &sin->sin_addr.s_addr); + break; + case AF_INET6: + snprintf(servername, sizeof(servername), + "%pI6", &sin6->sin6_addr); + break; + default: + /* do not consider this address */ + continue; + } + xprt_args.ident = XPRT_TRANSPORT_TCP_TLS; + xprt_args.servername = servername; + } if (da->da_addr.ss_family != clp->cl_addr.ss_family) continue; + /** * Test this address for session trunking and * add as an alias @@ -953,6 +991,10 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, if (xprtdata.cred) put_cred(xprtdata.cred); } else { + if (da->da_transport == XPRT_TRANSPORT_TCP && + mds_srv->nfs_client->cl_proto == + XPRT_TRANSPORT_TCP_TLS) + da->da_transport = XPRT_TRANSPORT_TCP_TLS; clp = nfs4_set_ds_client(mds_srv, &da->da_addr, da->da_addrlen, From 0b81371d3c6b849bfde9f478bfe70661759cc018 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 28 Feb 2024 10:05:07 +1100 Subject: [PATCH 736/814] NFS: remove sync_mode test from nfs_writepage_locked() nfs_writepage_locked() is only called from nfs_wb_folio() (since Commit 12fc0a963128 ("nfs: Remove writepage")) so ->sync_mode is always WB_SYNC_ALL. This means the test for WB_SYNC_NONE is dead code and can be removed. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bb79d3a886ae..58adbb7709ba 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -667,10 +667,6 @@ static int nfs_writepage_locked(struct folio *folio, struct inode *inode = folio_file_mapping(folio)->host; int err; - if (wbc->sync_mode == WB_SYNC_NONE && - NFS_SERVER(inode)->write_congested) - return AOP_WRITEPAGE_ACTIVATE; - nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); nfs_pageio_init_write(&pgio, inode, 0, false, &nfs_async_write_completion_ops); From 2fdbc20036acda9e5694db74a032d3c605323005 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 28 Feb 2024 11:24:53 +1100 Subject: [PATCH 737/814] NFS: avoid infinite loop in pnfs_update_layout. If pnfsd_update_layout() is called on a file for which recovery has failed it will enter a tight infinite loop. NFS_LAYOUT_INVALID_STID will be set, nfs4_select_rw_stateid() will return -EIO, and nfs4_schedule_stateid_recovery() will do nothing, so nfs4_client_recover_expired_lease() will not wait. So the code will loop indefinitely. Break the loop by testing the validity of the open stateid at the top of the loop. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 0c0fed1ecd0b..a5cc6199127f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1999,6 +1999,14 @@ pnfs_update_layout(struct inode *ino, } lookup_again: + if (!nfs4_valid_open_stateid(ctx->state)) { + trace_pnfs_update_layout(ino, pos, count, + iomode, lo, lseg, + PNFS_UPDATE_LAYOUT_INVALID_OPEN); + lseg = ERR_PTR(-EIO); + goto out; + } + lseg = ERR_PTR(nfs4_client_recover_expired_lease(clp)); if (IS_ERR(lseg)) goto out; From 0460253913e50a2aec911fe83090d60397f17664 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 24 Feb 2024 15:59:28 -0500 Subject: [PATCH 738/814] NFSv4: nfs4_do_open() is incorrectly triggering state recovery We're seeing spurious calls to nfs4_schedule_stateid_recovery() from nfs4_do_open() in situations where there is no trigger coming from the server. In theory the code path being triggered is supposed to notice that state recovery happened while we were processing the open call result from the server, before the open stateid is published. However in the years since that code was added, we've also added the 'session draining' mechanism, which ensures that the state recovery will wait until all the session slots have been returned. In nfs4_do_open() the session slot is only returned on exit of the function, so we don't need the legacy mechanism. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 4 ---- fs/nfs/nfs4_fs.h | 1 - fs/nfs/nfs4proc.c | 7 +------ fs/nfs/nfs4state.c | 12 +++++++----- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index fa1a14def45c..4ba612e78da8 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -181,7 +181,6 @@ static int nfs_delegation_claim_opens(struct inode *inode, struct nfs_open_context *ctx; struct nfs4_state_owner *sp; struct nfs4_state *state; - unsigned int seq; int err; again: @@ -202,12 +201,9 @@ again: sp = state->owner; /* Block nfs4_proc_unlck */ mutex_lock(&sp->so_delegreturn_mutex); - seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); err = nfs4_open_delegation_recall(ctx, state, stateid); if (!err) err = nfs_delegation_claim_locks(state, stateid); - if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) - err = -EAGAIN; mutex_unlock(&sp->so_delegreturn_mutex); put_nfs_open_context(ctx); if (err != 0) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 581698f1b7b2..cf17f4bc9815 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -120,7 +120,6 @@ struct nfs4_state_owner { unsigned long so_flags; struct list_head so_states; struct nfs_seqid_counter so_seqid; - seqcount_spinlock_t so_reclaim_seqcount; struct mutex so_delegreturn_mutex; }; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 206b4607b29a..e9c4f7b9d44e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3069,10 +3069,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx); struct inode *dir = d_inode(opendata->dir); unsigned long dir_verifier; - unsigned int seq; int ret; - seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); dir_verifier = nfs_save_change_attribute(dir); ret = _nfs4_proc_open(opendata, ctx); @@ -3125,11 +3123,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, if (ret != 0) goto out; - if (d_inode(dentry) == state->inode) { + if (d_inode(dentry) == state->inode) nfs_inode_attach_open_context(ctx); - if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) - nfs4_schedule_stateid_recovery(server, state); - } out: if (!opendata->cancelled) { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 9a5d911a7edc..8486230d99e1 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -513,7 +513,6 @@ nfs4_alloc_state_owner(struct nfs_server *server, nfs4_init_seqid_counter(&sp->so_seqid); atomic_set(&sp->so_count, 1); INIT_LIST_HEAD(&sp->so_lru); - seqcount_spinlock_init(&sp->so_reclaim_seqcount, &sp->so_lock); mutex_init(&sp->so_delegreturn_mutex); return sp; } @@ -1667,7 +1666,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, * server that doesn't support a grace period. */ spin_lock(&sp->so_lock); - raw_write_seqcount_begin(&sp->so_reclaim_seqcount); restart: list_for_each_entry(state, &sp->so_states, open_states) { if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) @@ -1735,7 +1733,6 @@ restart: spin_lock(&sp->so_lock); goto restart; } - raw_write_seqcount_end(&sp->so_reclaim_seqcount); spin_unlock(&sp->so_lock); #ifdef CONFIG_NFS_V4_2 if (found_ssc_copy_state) @@ -1745,7 +1742,6 @@ restart: out_err: nfs4_put_open_state(state); spin_lock(&sp->so_lock); - raw_write_seqcount_end(&sp->so_reclaim_seqcount); spin_unlock(&sp->so_lock); return status; } @@ -1928,9 +1924,12 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov struct nfs_server *server; struct rb_node *pos; LIST_HEAD(freeme); - int status = 0; int lost_locks = 0; + int status; + status = nfs4_begin_drain_session(clp); + if (status < 0) + return status; restart: rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { @@ -2694,6 +2693,9 @@ static void nfs4_state_manager(struct nfs_client *clp) /* Detect expired delegations... */ if (test_and_clear_bit(NFS4CLNT_DELEGATION_EXPIRED, &clp->cl_state)) { section = "detect expired delegations"; + status = nfs4_begin_drain_session(clp); + if (status < 0) + goto out_error; nfs_reap_expired_delegations(clp); continue; } From b326df4a8ec6ef53e2e2f1c2cbf14f8a20e85baa Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 13 Feb 2024 13:31:47 -0500 Subject: [PATCH 739/814] NFS: enable nconnect for RDMA It appears that in certain cases, RDMA capable transports can benefit from the ability to establish multiple connections to increase their throughput. This patch therefore enables the use of the "nconnect" mount option for those use cases. Signed-off-by: Trond Myklebust --- fs/nfs/nfs3client.c | 1 + fs/nfs/nfs4client.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c index 674c012868b1..b0c8a39c2bbd 100644 --- a/fs/nfs/nfs3client.c +++ b/fs/nfs/nfs3client.c @@ -111,6 +111,7 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv, cl_init.hostname = buf; switch (ds_proto) { + case XPRT_TRANSPORT_RDMA: case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_TCP_TLS: if (mds_clp->cl_nconnect > 1) diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 11e3a285594c..84573df5cf5a 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -924,6 +924,7 @@ static int nfs4_set_client(struct nfs_server *server, else cl_init.max_connect = max_connect; switch (proto) { + case XPRT_TRANSPORT_RDMA: case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_TCP_TLS: cl_init.nconnect = nconnect; @@ -1000,6 +1001,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv, cl_init.hostname = buf; switch (ds_proto) { + case XPRT_TRANSPORT_RDMA: case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_TCP_TLS: if (mds_clp->cl_nconnect > 1) { From 094501358e7a165071673e754c3925683683057f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 1 Mar 2024 11:49:56 -0500 Subject: [PATCH 740/814] nfs: properly protect nfs_direct_req fields We protect accesses to the nfs_direct_req fields with the dreq->lock ever where except nfs_direct_commit_complete. This isn't a huge deal, but it does lead to confusion, and we could potentially end up setting NFS_ODIRECT_RESCHED_WRITES in one thread where we've had an error in another. Clean this up to properly protect ->error and ->flags in the commit completion path. Signed-off-by: Josef Bacik Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index c03926a1cc73..befcc167e25f 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -606,6 +606,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) trace_nfs_direct_commit_complete(dreq); + spin_lock(&dreq->lock); if (status < 0) { /* Errors in commit are fatal */ dreq->error = status; @@ -613,6 +614,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) } else { status = dreq->error; } + spin_unlock(&dreq->lock); nfs_init_cinfo_from_dreq(&cinfo, dreq); @@ -625,7 +627,10 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) spin_unlock(&dreq->lock); nfs_release_request(req); } else if (!nfs_write_match_verf(verf, req)) { - dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + spin_lock(&dreq->lock); + if (dreq->flags == 0) + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + spin_unlock(&dreq->lock); /* * Despite the reboot, the write was successful, * so reset wb_nio. From 17f46b803d4f23c66cacce81db35fef3adb8f2af Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 1 Mar 2024 11:49:57 -0500 Subject: [PATCH 741/814] nfs: fix UAF in direct writes In production we have been hitting the following warning consistently ------------[ cut here ]------------ refcount_t: underflow; use-after-free. WARNING: CPU: 17 PID: 1800359 at lib/refcount.c:28 refcount_warn_saturate+0x9c/0xe0 Workqueue: nfsiod nfs_direct_write_schedule_work [nfs] RIP: 0010:refcount_warn_saturate+0x9c/0xe0 PKRU: 55555554 Call Trace: ? __warn+0x9f/0x130 ? refcount_warn_saturate+0x9c/0xe0 ? report_bug+0xcc/0x150 ? handle_bug+0x3d/0x70 ? exc_invalid_op+0x16/0x40 ? asm_exc_invalid_op+0x16/0x20 ? refcount_warn_saturate+0x9c/0xe0 nfs_direct_write_schedule_work+0x237/0x250 [nfs] process_one_work+0x12f/0x4a0 worker_thread+0x14e/0x3b0 ? ZSTD_getCParams_internal+0x220/0x220 kthread+0xdc/0x120 ? __btf_name_valid+0xa0/0xa0 ret_from_fork+0x1f/0x30 This is because we're completing the nfs_direct_request twice in a row. The source of this is when we have our commit requests to submit, we process them and send them off, and then in the completion path for the commit requests we have if (nfs_commit_end(cinfo.mds)) nfs_direct_write_complete(dreq); However since we're submitting asynchronous requests we sometimes have one that completes before we submit the next one, so we end up calling complete on the nfs_direct_request twice. The only other place we use nfs_generic_commit_list() is in __nfs_commit_inode, which wraps this call in a nfs_commit_begin(); nfs_commit_end(); Which is a common pattern for this style of completion handling, one that is also repeated in the direct code with get_dreq()/put_dreq() calls around where we process events as well as in the completion paths. Fix this by using the same pattern for the commit requests. Before with my 200 node rocksdb stress running this warning would pop every 10ish minutes. With my patch the stress test has been running for several hours without popping. Signed-off-by: Josef Bacik Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 11 +++++++++-- fs/nfs/write.c | 2 +- include/linux/nfs_fs.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index befcc167e25f..6b8798d01e3a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -672,10 +672,17 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) LIST_HEAD(mds_list); nfs_init_cinfo_from_dreq(&cinfo, dreq); + nfs_commit_begin(cinfo.mds); nfs_scan_commit(dreq->inode, &mds_list, &cinfo); res = nfs_generic_commit_list(dreq->inode, &mds_list, 0, &cinfo); - if (res < 0) /* res == -ENOMEM */ - nfs_direct_write_reschedule(dreq); + if (res < 0) { /* res == -ENOMEM */ + spin_lock(&dreq->lock); + if (dreq->flags == 0) + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + spin_unlock(&dreq->lock); + } + if (nfs_commit_end(cinfo.mds)) + nfs_direct_write_complete(dreq); } static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 58adbb7709ba..15359bbfa56b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1646,7 +1646,7 @@ static int wait_on_commit(struct nfs_mds_commit_info *cinfo) !atomic_read(&cinfo->rpcs_out)); } -static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo) +void nfs_commit_begin(struct nfs_mds_commit_info *cinfo) { atomic_inc(&cinfo->rpcs_out); } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f5ce7b101146..d59116ac8209 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -611,6 +611,7 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio); extern int nfs_commit_inode(struct inode *, int); extern struct nfs_commit_data *nfs_commitdata_alloc(void); extern void nfs_commit_free(struct nfs_commit_data *data); +void nfs_commit_begin(struct nfs_mds_commit_info *cinfo); bool nfs_commit_end(struct nfs_mds_commit_info *cinfo); static inline bool nfs_have_writebacks(const struct inode *inode) From cdbd321ac15e1e663c15fc0433024f6487531f27 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 6 Mar 2024 18:04:42 -0500 Subject: [PATCH 742/814] NFS: remove unused variable nfs_rpcstat Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a8fad331dff6..de77848ae654 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -76,10 +76,6 @@ const struct rpc_program nfs_program = { .pipe_dir_name = NFS_PIPE_DIRNAME, }; -struct rpc_stat nfs_rpcstat = { - .program = &nfs_program -}; - static struct nfs_subversion *find_nfs_version(unsigned int version) { struct nfs_subversion *nfs; From 11974eec839c167362af685aae5f5e1baaf979eb Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Thu, 7 Mar 2024 09:41:18 -0500 Subject: [PATCH 743/814] NFS: Read unlock folio on nfs_page_create_from_folio() error The netfs conversion lost a folio_unlock() for the case where nfs_page_create_from_folio() returns an error (usually -ENOMEM). Restore it. Reported-by: David Jeffery Cc: # 6.4+ Fixes: 000dbe0bec05 ("NFS: Convert buffered read paths to use netfs when fscache is enabled") Signed-off-by: Benjamin Coddington Acked-by: Dave Wysochanski Signed-off-by: Trond Myklebust --- fs/nfs/read.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 7dc21a48e3e7..a142287d86f6 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -305,6 +305,8 @@ int nfs_read_add_folio(struct nfs_pageio_descriptor *pgio, new = nfs_page_create_from_folio(ctx, folio, 0, aligned_len); if (IS_ERR(new)) { error = PTR_ERR(new); + if (nfs_netfs_folio_unlock(folio)) + folio_unlock(folio); goto out; } From e9efd5fe756dfd9f994d59c96cef1ad134d4a39c Mon Sep 17 00:00:00 2001 From: Chen Hanxiao Date: Wed, 6 Mar 2024 17:39:02 +0800 Subject: [PATCH 744/814] NFS: trace the uniquifier of fscache Trace the mount option fsc=xxx. Signed-off-by: Chen Hanxiao Signed-off-by: Trond Myklebust --- fs/nfs/fs_context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c index 853e8d609bb3..d0a0956f8a13 100644 --- a/fs/nfs/fs_context.c +++ b/fs/nfs/fs_context.c @@ -652,6 +652,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, ctx->fscache_uniq = NULL; break; case Opt_fscache: + trace_nfs_mount_assign(param->key, param->string); ctx->options |= NFS_OPTION_FSCACHE; kfree(ctx->fscache_uniq); ctx->fscache_uniq = param->string; From ccae53aa8aa2d902242555638c5de104aab08879 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 16:38:25 -0300 Subject: [PATCH 745/814] pcmcia: cs: make pcmcia_socket_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the pcmcia_socket_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 2 +- drivers/pcmcia/cs_internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index b33be1e63c98..c75f55e1250a 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -892,7 +892,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = { #endif /* CONFIG_PM */ -struct class pcmcia_socket_class = { +const struct class pcmcia_socket_class = { .name = "pcmcia_socket", .dev_uevent = pcmcia_socket_uevent, .dev_release = pcmcia_release_socket, diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 999332bc4378..02a83ca44e77 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -113,7 +113,7 @@ struct pcmcia_callback{ /* cs.c */ extern struct rw_semaphore pcmcia_socket_list_rwsem; extern struct list_head pcmcia_socket_list; -extern struct class pcmcia_socket_class; +extern const struct class pcmcia_socket_class; int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr); From 3250647eed27ff8c532512aa52829c84fceaaf63 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Mar 2024 18:52:18 +0200 Subject: [PATCH 746/814] watchdog: intel-mid_wdt: Remove unused intel-mid.h intel-mid.h is providing some core parts of the South Complex PM, which are usually are not used by individual drivers. In particular, this driver doesn't use it, so simply remove the unused header. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240305165306.1366823-2-andriy.shevchenko@linux.intel.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/intel-mid_wdt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index fb7fae750181..b41c45582aa4 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -17,7 +17,6 @@ #include #include -#include #define IPC_WATCHDOG 0xf8 From e295eb8235050478fa83199769c53313feb5bbef Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Mar 2024 18:52:19 +0200 Subject: [PATCH 747/814] watchdog: intel-mid_wdt: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240305165306.1366823-3-andriy.shevchenko@linux.intel.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/intel-mid_wdt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index b41c45582aa4..06d5d207a065 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -9,11 +9,17 @@ * Contact: David Cohen */ +#include +#include +#include #include +#include #include -#include +#include #include +#include #include + #include #include From 6fe5aabf7fc645562faec50c79c7a21a4dd1cab6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Mar 2024 18:52:20 +0200 Subject: [PATCH 748/814] watchdog: intel-mid_wdt: Get platform data via dev_get_platdata() Access to platform data via dev_get_platdata() getter to make code cleaner. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20240305165306.1366823-4-andriy.shevchenko@linux.intel.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/intel-mid_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index 06d5d207a065..8d71f6a2236b 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -127,7 +127,7 @@ static int mid_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct watchdog_device *wdt_dev; - struct intel_mid_wdt_pdata *pdata = dev->platform_data; + struct intel_mid_wdt_pdata *pdata = dev_get_platdata(dev); struct mid_wdt *mid; int ret; From a4735d40a5da96a637af6e5bf9f6ec8b9d996acd Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 9 Mar 2024 21:10:08 -0800 Subject: [PATCH 749/814] Input: make input_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the input_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240305-class_cleanup-input-v1-1-0c3d950c25db@marliere.net Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 2 +- include/linux/input.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index de7884a5be39..711485437567 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1918,7 +1918,7 @@ static char *input_devnode(const struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev)); } -struct class input_class = { +const struct class input_class = { .name = "input", .devnode = input_devnode, }; diff --git a/include/linux/input.h b/include/linux/input.h index de6503c0edb8..c22ac465254b 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -514,7 +514,7 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period); bool input_device_enabled(struct input_dev *dev); -extern struct class input_class; +extern const struct class input_class; /** * struct ff_device - force-feedback part of an input device From c0ca3dbd03d66c6b9e044f48720e6ab5cef37ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Sat, 9 Mar 2024 21:18:05 -0800 Subject: [PATCH 750/814] Input: imagis - use FIELD_GET where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of manually extracting certain bits from registers with binary ANDs and shifts, the FIELD_GET macro can be used. With this in mind, the *_SHIFT macros can be dropped. Signed-off-by: Duje Mihanović Link: https://lore.kernel.org/r/20240306-b4-imagis-keys-v3-1-2c429afa8420@skole.hr Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imagis.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index e1fafa561ee3..fe65e083fd49 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include @@ -29,12 +30,9 @@ #define IST3038C_I2C_RETRY_COUNT 3 #define IST3038C_MAX_FINGER_NUM 10 #define IST3038C_X_MASK GENMASK(23, 12) -#define IST3038C_X_SHIFT 12 #define IST3038C_Y_MASK GENMASK(11, 0) #define IST3038C_AREA_MASK GENMASK(27, 24) -#define IST3038C_AREA_SHIFT 24 #define IST3038C_FINGER_COUNT_MASK GENMASK(15, 12) -#define IST3038C_FINGER_COUNT_SHIFT 12 #define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0) struct imagis_properties { @@ -106,8 +104,7 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) goto out; } - finger_count = (intr_message & IST3038C_FINGER_COUNT_MASK) >> - IST3038C_FINGER_COUNT_SHIFT; + finger_count = FIELD_GET(IST3038C_FINGER_COUNT_MASK, intr_message); if (finger_count > IST3038C_MAX_FINGER_NUM) { dev_err(&ts->client->dev, "finger count %d is more than maximum supported\n", @@ -115,7 +112,7 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) goto out; } - finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK; + finger_pressed = FIELD_GET(IST3038C_FINGER_STATUS_MASK, intr_message); for (i = 0; i < finger_count; i++) { if (ts->tdata->protocol_b) @@ -136,12 +133,11 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, finger_pressed & BIT(i)); touchscreen_report_pos(ts->input_dev, &ts->prop, - (finger_status & IST3038C_X_MASK) >> - IST3038C_X_SHIFT, - finger_status & IST3038C_Y_MASK, 1); + FIELD_GET(IST3038C_X_MASK, finger_status), + FIELD_GET(IST3038C_Y_MASK, finger_status), + true); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - (finger_status & IST3038C_AREA_MASK) >> - IST3038C_AREA_SHIFT); + FIELD_GET(IST3038C_AREA_MASK, finger_status)); } input_mt_sync_frame(ts->input_dev); From 44b6cee0417f3a5df003df5e1f96ecebb1184b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Sat, 9 Mar 2024 21:18:55 -0800 Subject: [PATCH 751/814] dt-bindings: input: imagis: Document touch keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IST3032C (and possibly some other models) has touch keys. Document this. Signed-off-by: Duje Mihanović Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240306-b4-imagis-keys-v3-2-2c429afa8420@skole.hr Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/imagis,ist3038c.yaml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml index 2af71cbcc97d..77ba280b3bdc 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml @@ -9,9 +9,6 @@ title: Imagis IST30XXC family touchscreen controller maintainers: - Markuss Broks -allOf: - - $ref: touchscreen.yaml# - properties: $nodename: pattern: "^touchscreen@[0-9a-f]+$" @@ -34,6 +31,10 @@ properties: vddio-supply: description: Power supply regulator for the I2C bus + linux,keycodes: + description: Keycodes for the touch keys + maxItems: 5 + touchscreen-size-x: true touchscreen-size-y: true touchscreen-fuzz-x: true @@ -44,6 +45,18 @@ properties: additionalProperties: false +allOf: + - $ref: touchscreen.yaml# + - if: + not: + properties: + compatible: + contains: + const: imagis,ist3032c + then: + properties: + linux,keycodes: false + required: - compatible - reg From 2d77f70bb7180060072b9c2406d67e4b3872af15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Sat, 9 Mar 2024 21:19:06 -0800 Subject: [PATCH 752/814] Input: imagis - add touch key support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IST3032C (and possibly some other models) has touch keys. Add support for them to the imagis driver. Signed-off-by: Duje Mihanović Link: https://lore.kernel.org/r/20240306-b4-imagis-keys-v3-3-2c429afa8420@skole.hr Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imagis.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index fe65e083fd49..074dd6c342ec 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -34,6 +34,7 @@ #define IST3038C_AREA_MASK GENMASK(27, 24) #define IST3038C_FINGER_COUNT_MASK GENMASK(15, 12) #define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0) +#define IST3032C_KEY_STATUS_MASK GENMASK(20, 16) struct imagis_properties { unsigned int interrupt_msg_cmd; @@ -41,6 +42,7 @@ struct imagis_properties { unsigned int whoami_cmd; unsigned int whoami_val; bool protocol_b; + bool touch_keys_supported; }; struct imagis_ts { @@ -49,6 +51,8 @@ struct imagis_ts { struct input_dev *input_dev; struct touchscreen_properties prop; struct regulator_bulk_data supplies[2]; + u32 keycodes[5]; + int num_keycodes; }; static int imagis_i2c_read_reg(struct imagis_ts *ts, @@ -93,7 +97,7 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) { struct imagis_ts *ts = dev_id; u32 intr_message, finger_status; - unsigned int finger_count, finger_pressed; + unsigned int finger_count, finger_pressed, key_pressed; int i; int error; @@ -140,6 +144,12 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) FIELD_GET(IST3038C_AREA_MASK, finger_status)); } + key_pressed = FIELD_GET(IST3032C_KEY_STATUS_MASK, intr_message); + + for (int i = 0; i < ts->num_keycodes; i++) + input_report_key(ts->input_dev, ts->keycodes[i], + key_pressed & BIT(i)); + input_mt_sync_frame(ts->input_dev); input_sync(ts->input_dev); @@ -225,6 +235,23 @@ static int imagis_init_input_dev(struct imagis_ts *ts) 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_TOUCH_MAJOR, 0, 16, 0, 0); + if (ts->tdata->touch_keys_supported) { + ts->num_keycodes = of_property_read_variable_u32_array( + ts->client->dev.of_node, "linux,keycodes", + ts->keycodes, 0, ARRAY_SIZE(ts->keycodes)); + if (ts->num_keycodes <= 0) { + ts->keycodes[0] = KEY_APPSELECT; + ts->keycodes[1] = KEY_BACK; + ts->num_keycodes = 2; + } + + input_dev->keycodemax = ts->num_keycodes; + input_dev->keycodesize = sizeof(ts->keycodes[0]); + input_dev->keycode = ts->keycodes; + } + + for (int i = 0; i < ts->num_keycodes; i++) + input_set_capability(input_dev, EV_KEY, ts->keycodes[i]); touchscreen_parse_properties(input_dev, true, &ts->prop); if (!ts->prop.max_x || !ts->prop.max_y) { @@ -366,6 +393,7 @@ static const struct imagis_properties imagis_3032c_data = { .touch_coord_cmd = IST3038C_REG_TOUCH_COORD, .whoami_cmd = IST3038C_REG_CHIPID, .whoami_val = IST3032C_WHOAMI, + .touch_keys_supported = true, }; static const struct imagis_properties imagis_3038b_data = { From 4a2b06ca33763b363038d333274e212db6ff0de1 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Mon, 22 Jan 2024 13:39:41 +0800 Subject: [PATCH 753/814] firewire: Kill unnecessary buf check in device_attribute.show Per Documentation/filesystems/sysfs.rst: > sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the > method. So we can kill the unnecessary buf check safely. Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240122053942.80648-1-lizhijian@fujitsu.com Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-device.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 7d3346b3a2bf..3a1a2bf1717c 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -322,7 +322,7 @@ static ssize_t show_immediate(struct device *dev, if (value < 0) return -ENOENT; - return snprintf(buf, buf ? PAGE_SIZE : 0, "0x%06x\n", value); + return snprintf(buf, PAGE_SIZE, "0x%06x\n", value); } #define IMMEDIATE_ATTR(name, key) \ @@ -334,8 +334,6 @@ static ssize_t show_text_leaf(struct device *dev, struct config_rom_attribute *attr = container_of(dattr, struct config_rom_attribute, attr); const u32 *directories[] = {NULL, NULL}; - size_t bufsize; - char dummy_buf[2]; int i, ret = -ENOENT; down_read(&fw_device_rwsem); @@ -357,15 +355,9 @@ static ssize_t show_text_leaf(struct device *dev, } } - if (buf) { - bufsize = PAGE_SIZE - 1; - } else { - buf = dummy_buf; - bufsize = 1; - } - for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { - int result = fw_csr_string(directories[i], attr->key, buf, bufsize); + int result = fw_csr_string(directories[i], attr->key, buf, + PAGE_SIZE - 1); // Detected. if (result >= 0) { ret = result; From d4db89c34521a83371fd46bea34834dff128a5cf Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Mon, 22 Jan 2024 13:39:42 +0800 Subject: [PATCH 754/814] firewire: Convert snprintf/sprintf to sysfs_emit Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > drivers/firewire/core-device.c:326:8-16: WARNING: please use sysfs_emit or sysfs_emit_at No functional change intended Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20240122053942.80648-2-lizhijian@fujitsu.com Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 3a1a2bf1717c..a802c6d4f4fd 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -322,7 +322,7 @@ static ssize_t show_immediate(struct device *dev, if (value < 0) return -ENOENT; - return snprintf(buf, PAGE_SIZE, "0x%06x\n", value); + return sysfs_emit(buf, "0x%06x\n", value); } #define IMMEDIATE_ATTR(name, key) \ @@ -482,7 +482,7 @@ static ssize_t is_local_show(struct device *dev, { struct fw_device *device = fw_device(dev); - return sprintf(buf, "%u\n", device->is_local); + return sysfs_emit(buf, "%u\n", device->is_local); } static int units_sprintf(char *buf, const u32 *directory) From 04f082d39b99f0b7b4b1cada14280f41d99f1e1f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 5 Feb 2024 15:04:48 +0900 Subject: [PATCH 755/814] firewire: core: fix build failure due to the caller of fw_csr_string() A commit 47dc55181dcb ("firewire: core: search descriptor leaf just after vendor directory entry in root directory") for v6.8-rc3 and a commit 67a5a58c0443 ("firewire: Kill unnecessary buf check in device_attribute.show") for v6.9 bring build failure in for-next tree due to the change of the name of local variable. This commit fixes it. Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/lkml/20240202111602.6f6e2c1a@canb.auug.org.au/ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402022343.NkgsMITA-lkp@intel.com/ Link: https://lore.kernel.org/r/20240205060448.13881-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index a802c6d4f4fd..c0976f6268d3 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -366,7 +366,7 @@ static ssize_t show_text_leaf(struct device *dev, // in the root directory follows to the directory entry for vendor ID // instead of the immediate value for vendor ID. result = fw_csr_string(directories[i], CSR_DIRECTORY | attr->key, buf, - bufsize); + PAGE_SIZE - 1); if (result >= 0) ret = result; } From 074fe32e9af1b8720eaf89e069b98ac567e90b99 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 11 Mar 2024 11:45:58 +0200 Subject: [PATCH 756/814] MIPS: ralink: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Fixes: 5804be061848 ("MIPS: ralink: Remove unused of_gpio.h") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202403090727.nLhljNp6-lkp@intel.com/ Signed-off-by: Andy Shevchenko Acked-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/timer.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index 8b485cbe854e..54094f6e033e 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -6,10 +6,16 @@ * Copyright (C) 2013 John Crispin */ -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include From bc75dffadc063eb46200611cc41d1e2373219e11 Mon Sep 17 00:00:00 2001 From: Justin Swartz Date: Fri, 8 Mar 2024 17:56:14 +0200 Subject: [PATCH 757/814] mips: dts: ralink: mt7621: associate uart1_pins with serial0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing pinctrl-name and pinctrl-0 properties to declare that the uart1_pins group is associated with serial0. Acked-by: Sergio Paracuellos Signed-off-by: Justin Swartz Reviewed-by: Arınç ÜNAL Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi index 35a10258f235..dca415fddd90 100644 --- a/arch/mips/boot/dts/ralink/mt7621.dtsi +++ b/arch/mips/boot/dts/ralink/mt7621.dtsi @@ -123,6 +123,9 @@ reg-shift = <2>; reg-io-width = <4>; no-loopback-test; + + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; }; spi0: spi@b00 { From 82394085bf0368a2b2ab9c41d3a5cebf05cff02e Mon Sep 17 00:00:00 2001 From: Justin Swartz Date: Fri, 8 Mar 2024 17:56:15 +0200 Subject: [PATCH 758/814] mips: dts: ralink: mt7621: reorder serial0 properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder serial0 properties according to the guidelines laid out in Documentation/devicetree/bindings/dts-coding-style.rst Acked-by: Sergio Paracuellos Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Justin Swartz Reviewed-by: Arınç ÜNAL Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi index dca415fddd90..68467fca3fc9 100644 --- a/arch/mips/boot/dts/ralink/mt7621.dtsi +++ b/arch/mips/boot/dts/ralink/mt7621.dtsi @@ -115,13 +115,14 @@ compatible = "ns16550a"; reg = <0xc00 0x100>; + reg-io-width = <4>; + reg-shift = <2>; + clocks = <&sysc MT7621_CLK_UART1>; interrupt-parent = <&gic>; interrupts = ; - reg-shift = <2>; - reg-io-width = <4>; no-loopback-test; pinctrl-names = "default"; From 7fdfd3d81b2a02ecbcc4b285311d25e8b5f4cbf9 Mon Sep 17 00:00:00 2001 From: Justin Swartz Date: Fri, 8 Mar 2024 17:56:16 +0200 Subject: [PATCH 759/814] mips: dts: ralink: mt7621: add serial1 and serial2 nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add serial1 and serial2 nodes to define the existence of the MT7621's second and third UARTs. Acked-by: Sergio Paracuellos Signed-off-by: Justin Swartz Reviewed-by: Arınç ÜNAL Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621.dtsi | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi index 68467fca3fc9..02e1f2491db0 100644 --- a/arch/mips/boot/dts/ralink/mt7621.dtsi +++ b/arch/mips/boot/dts/ralink/mt7621.dtsi @@ -129,6 +129,46 @@ pinctrl-0 = <&uart1_pins>; }; + serial1: serial@d00 { + compatible = "ns16550a"; + reg = <0xd00 0x100>; + + reg-io-width = <4>; + reg-shift = <2>; + + clocks = <&sysc MT7621_CLK_UART2>; + + interrupt-parent = <&gic>; + interrupts = ; + + no-loopback-test; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + status = "disabled"; + }; + + serial2: serial@e00 { + compatible = "ns16550a"; + reg = <0xe00 0x100>; + + reg-io-width = <4>; + reg-shift = <2>; + + clocks = <&sysc MT7621_CLK_UART3>; + + interrupt-parent = <&gic>; + interrupts = ; + + no-loopback-test; + + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + + status = "disabled"; + }; + spi0: spi@b00 { status = "disabled"; From 850778617121aa0e1c8f4b3ab4f33eff8a064431 Mon Sep 17 00:00:00 2001 From: Justin Swartz Date: Fri, 8 Mar 2024 18:11:30 +0200 Subject: [PATCH 760/814] mips: dts: ralink: mt7621: add cell count properties to usb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add default #address-cells and #size-cells properties to the usb node, which should be suitable for hubs and devices without explicitly declared interface nodes, as: "#address-cells": description: should be 1 for hub nodes with device nodes, should be 2 for device nodes with interface nodes. enum: [1, 2] "#size-cells": const: 0 -- from Documentation/devicetree/bindings/usb/usb-device.yaml Acked-by: Sergio Paracuellos Signed-off-by: Justin Swartz Reviewed-by: Arınç ÜNAL Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi index 02e1f2491db0..6e95e6f19a6a 100644 --- a/arch/mips/boot/dts/ralink/mt7621.dtsi +++ b/arch/mips/boot/dts/ralink/mt7621.dtsi @@ -307,6 +307,9 @@ 0x1e1d0700 0x0100>; reg-names = "mac", "ippc"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&sysc MT7621_CLK_XTAL>; clock-names = "sys_ck"; From 8bc8db2ab2832daabdd06feeabdd511dc9575bb6 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 26 Feb 2024 13:54:21 +0300 Subject: [PATCH 761/814] mips: cm: Convert __mips_cm_l2sync_phys_base() to weak function The __mips_cm_l2sync_phys_base() and mips_cm_l2sync_phys_base() couple was introduced in commit 9f98f3dd0c51 ("MIPS: Add generic CM probe & access code") where the former method was a weak implementation of the later function. Such design pattern permitted to re-define the original method and to use the weak implementation in the new function. A similar approach was introduced in the framework of another arch-specific programmable interface: mips_cm_phys_base() and __mips_cm_phys_base(). The only difference is that the underscored method of the later couple was declared in the "asm/mips-cm.h" header file, but it wasn't done for the CM L2-sync methods in the subject. Due to the missing global function declaration the "missing prototype" warning was spotted in the framework of the commit 9a2036724cd6 ("mips: mark local function static if possible") and fixed just be re-qualifying the weak method as static. Doing that broke what was originally implied by having the weak implementation globally defined. Let's fix the broken CM2 L2-sync arch-interface by dropping the static qualifier and, seeing the implemented pattern hasn't been used for over 10 years but will be required soon (see the link for the discussion around it), converting it to a single weakly defined method: mips_cm_l2sync_phys_base(). Fixes: 9a2036724cd6 ("mips: mark local function static if possible") Link: https://lore.kernel.org/linux-mips/20240215171740.14550-3-fancer.lancer@gmail.com Signed-off-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mips-cm.h | 13 +++++++++++++ arch/mips/kernel/mips-cm.c | 5 +---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 15d8d69de455..6d132b537f6d 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -33,6 +33,19 @@ extern void __iomem *mips_cm_l2sync_base; */ extern phys_addr_t __mips_cm_phys_base(void); +/** + * mips_cm_l2sync_phys_base - retrieve the physical base address of the CM + * L2-sync region + * + * This function returns the physical base address of the Coherence Manager + * L2-cache only region. It provides a default implementation which reads the + * CMGCRL2OnlySyncBase register where available or returns a 4K region just + * behind the CM GCR base address. It may be overridden by platforms which + * determine this address in a different way by defining a function with the + * same prototype. + */ +extern phys_addr_t mips_cm_l2sync_phys_base(void); + /* * mips_cm_is64 - determine CM register width * diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 84b3affb9de8..268ac0b811e3 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -201,7 +201,7 @@ phys_addr_t __mips_cm_phys_base(void) phys_addr_t mips_cm_phys_base(void) __attribute__((weak, alias("__mips_cm_phys_base"))); -static phys_addr_t __mips_cm_l2sync_phys_base(void) +phys_addr_t __weak mips_cm_l2sync_phys_base(void) { u32 base_reg; @@ -217,9 +217,6 @@ static phys_addr_t __mips_cm_l2sync_phys_base(void) return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; } -phys_addr_t mips_cm_l2sync_phys_base(void) - __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); - static void mips_cm_probe_l2sync(void) { unsigned major_rev; From 732932220078f6312f3ef57c17523d3d7f995655 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 26 Feb 2024 13:54:22 +0300 Subject: [PATCH 762/814] mips: cm: Convert __mips_cm_phys_base() to weak function Based on the design pattern utilized in the CM GCR base address getter implementation, the platform-specific code is capable to re-define the getter and re-use the weakly defined initial version. But since the pattern hasn't been used for over 10 years and another similar case (CM L2-sync only base address getter) has just been fixed, let's unify the interface and convert it to a more traditional single weakly defined method: mips_cm_phys_base() (see the link below for the discussion around this). Link: https://lore.kernel.org/linux-mips/20240215171740.14550-3-fancer.lancer@gmail.com Signed-off-by: Serge Semin Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mips-cm.h | 7 +++---- arch/mips/kernel/mips-cm.c | 5 +---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 6d132b537f6d..c2930a75b7e4 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -22,16 +22,15 @@ extern void __iomem *mips_gcr_base; extern void __iomem *mips_cm_l2sync_base; /** - * __mips_cm_phys_base - retrieve the physical base address of the CM + * mips_cm_phys_base - retrieve the physical base address of the CM * * This function returns the physical base address of the Coherence Manager * global control block, or 0 if no Coherence Manager is present. It provides * a default implementation which reads the CMGCRBase register where available, * and may be overridden by platforms which determine this address in a - * different way by defining a function with the same prototype except for the - * name mips_cm_phys_base (without underscores). + * different way by defining a function with the same prototype. */ -extern phys_addr_t __mips_cm_phys_base(void); +extern phys_addr_t mips_cm_phys_base(void); /** * mips_cm_l2sync_phys_base - retrieve the physical base address of the CM diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 268ac0b811e3..3a115fab5573 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -179,7 +179,7 @@ static char *cm3_causes[32] = { static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); -phys_addr_t __mips_cm_phys_base(void) +phys_addr_t __weak mips_cm_phys_base(void) { unsigned long cmgcr; @@ -198,9 +198,6 @@ phys_addr_t __mips_cm_phys_base(void) return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); } -phys_addr_t mips_cm_phys_base(void) - __attribute__((weak, alias("__mips_cm_phys_base"))); - phys_addr_t __weak mips_cm_l2sync_phys_base(void) { u32 base_reg; From 821b8f6bf84897aeceb230ff4d446b8aa5336acd Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Wed, 6 Mar 2024 12:56:24 +0200 Subject: [PATCH 763/814] vfio/mlx5: Enforce PRE_COPY support Enable live migration only once the firmware supports PRE_COPY. PRE_COPY has been supported by the firmware for a long time already [1] and is required to achieve a low downtime upon live migration. This lets us clean up some old code that is not applicable those days while PRE_COPY is fully supported by the firmware. [1] The minimum firmware version that supports PRE_COPY is 28.36.1010, it was released in January 2023. No firmware without PRE_COPY support ever available to users. Signed-off-by: Yishai Hadas Link: https://lore.kernel.org/r/20240306105624.114830-1-yishaih@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/mlx5/cmd.c | 83 +++++++++++++++++++------- drivers/vfio/pci/mlx5/cmd.h | 6 -- drivers/vfio/pci/mlx5/main.c | 109 +++-------------------------------- 3 files changed, 71 insertions(+), 127 deletions(-) diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index c54bcd5d0917..41a4b0cf4297 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -233,6 +233,10 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev, if (!MLX5_CAP_GEN(mvdev->mdev, migration)) goto end; + if (!(MLX5_CAP_GEN_2(mvdev->mdev, migration_multi_load) && + MLX5_CAP_GEN_2(mvdev->mdev, migration_tracking_state))) + goto end; + mvdev->vf_id = pci_iov_vf_id(pdev); if (mvdev->vf_id < 0) goto end; @@ -262,17 +266,14 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev, mvdev->migrate_cap = 1; mvdev->core_device.vdev.migration_flags = VFIO_MIGRATION_STOP_COPY | - VFIO_MIGRATION_P2P; + VFIO_MIGRATION_P2P | + VFIO_MIGRATION_PRE_COPY; + mvdev->core_device.vdev.mig_ops = mig_ops; init_completion(&mvdev->tracker_comp); if (MLX5_CAP_GEN(mvdev->mdev, adv_virtualization)) mvdev->core_device.vdev.log_ops = log_ops; - if (MLX5_CAP_GEN_2(mvdev->mdev, migration_multi_load) && - MLX5_CAP_GEN_2(mvdev->mdev, migration_tracking_state)) - mvdev->core_device.vdev.migration_flags |= - VFIO_MIGRATION_PRE_COPY; - if (MLX5_CAP_GEN_2(mvdev->mdev, migration_in_chunks)) mvdev->chunk_mode = 1; @@ -414,6 +415,50 @@ void mlx5vf_free_data_buffer(struct mlx5_vhca_data_buffer *buf) kfree(buf); } +static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, + unsigned int npages) +{ + unsigned int to_alloc = npages; + struct page **page_list; + unsigned long filled; + unsigned int to_fill; + int ret; + + to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list)); + page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT); + if (!page_list) + return -ENOMEM; + + do { + filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT, to_fill, + page_list); + if (!filled) { + ret = -ENOMEM; + goto err; + } + to_alloc -= filled; + ret = sg_alloc_append_table_from_pages( + &buf->table, page_list, filled, 0, + filled << PAGE_SHIFT, UINT_MAX, SG_MAX_SINGLE_ALLOC, + GFP_KERNEL_ACCOUNT); + + if (ret) + goto err; + buf->allocated_length += filled * PAGE_SIZE; + /* clean input for another bulk allocation */ + memset(page_list, 0, filled * sizeof(*page_list)); + to_fill = min_t(unsigned int, to_alloc, + PAGE_SIZE / sizeof(*page_list)); + } while (to_alloc > 0); + + kvfree(page_list); + return 0; + +err: + kvfree(page_list); + return ret; +} + struct mlx5_vhca_data_buffer * mlx5vf_alloc_data_buffer(struct mlx5_vf_migration_file *migf, size_t length, @@ -680,22 +725,20 @@ int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev, goto err_out; } - if (MLX5VF_PRE_COPY_SUPP(mvdev)) { - if (async_data->stop_copy_chunk) { - u8 header_idx = buf->stop_copy_chunk_num ? - buf->stop_copy_chunk_num - 1 : 0; + if (async_data->stop_copy_chunk) { + u8 header_idx = buf->stop_copy_chunk_num ? + buf->stop_copy_chunk_num - 1 : 0; - header_buf = migf->buf_header[header_idx]; - migf->buf_header[header_idx] = NULL; - } + header_buf = migf->buf_header[header_idx]; + migf->buf_header[header_idx] = NULL; + } - if (!header_buf) { - header_buf = mlx5vf_get_data_buffer(migf, - sizeof(struct mlx5_vf_migration_header), DMA_NONE); - if (IS_ERR(header_buf)) { - err = PTR_ERR(header_buf); - goto err_free; - } + if (!header_buf) { + header_buf = mlx5vf_get_data_buffer(migf, + sizeof(struct mlx5_vf_migration_header), DMA_NONE); + if (IS_ERR(header_buf)) { + err = PTR_ERR(header_buf); + goto err_free; } } diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h index 707393df36c4..df421dc6de04 100644 --- a/drivers/vfio/pci/mlx5/cmd.h +++ b/drivers/vfio/pci/mlx5/cmd.h @@ -13,9 +13,6 @@ #include #include -#define MLX5VF_PRE_COPY_SUPP(mvdev) \ - ((mvdev)->core_device.vdev.migration_flags & VFIO_MIGRATION_PRE_COPY) - enum mlx5_vf_migf_state { MLX5_MIGF_STATE_ERROR = 1, MLX5_MIGF_STATE_PRE_COPY_ERROR, @@ -25,7 +22,6 @@ enum mlx5_vf_migf_state { }; enum mlx5_vf_load_state { - MLX5_VF_LOAD_STATE_READ_IMAGE_NO_HEADER, MLX5_VF_LOAD_STATE_READ_HEADER, MLX5_VF_LOAD_STATE_PREP_HEADER_DATA, MLX5_VF_LOAD_STATE_READ_HEADER_DATA, @@ -228,8 +224,6 @@ struct mlx5_vhca_data_buffer * mlx5vf_get_data_buffer(struct mlx5_vf_migration_file *migf, size_t length, enum dma_data_direction dma_dir); void mlx5vf_put_data_buffer(struct mlx5_vhca_data_buffer *buf); -int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, - unsigned int npages); struct page *mlx5vf_get_migration_page(struct mlx5_vhca_data_buffer *buf, unsigned long offset); void mlx5vf_state_mutex_unlock(struct mlx5vf_pci_core_device *mvdev); diff --git a/drivers/vfio/pci/mlx5/main.c b/drivers/vfio/pci/mlx5/main.c index 3982fcf60cf2..61d9b0f9146d 100644 --- a/drivers/vfio/pci/mlx5/main.c +++ b/drivers/vfio/pci/mlx5/main.c @@ -65,50 +65,6 @@ mlx5vf_get_migration_page(struct mlx5_vhca_data_buffer *buf, return NULL; } -int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, - unsigned int npages) -{ - unsigned int to_alloc = npages; - struct page **page_list; - unsigned long filled; - unsigned int to_fill; - int ret; - - to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list)); - page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT); - if (!page_list) - return -ENOMEM; - - do { - filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT, to_fill, - page_list); - if (!filled) { - ret = -ENOMEM; - goto err; - } - to_alloc -= filled; - ret = sg_alloc_append_table_from_pages( - &buf->table, page_list, filled, 0, - filled << PAGE_SHIFT, UINT_MAX, SG_MAX_SINGLE_ALLOC, - GFP_KERNEL_ACCOUNT); - - if (ret) - goto err; - buf->allocated_length += filled * PAGE_SIZE; - /* clean input for another bulk allocation */ - memset(page_list, 0, filled * sizeof(*page_list)); - to_fill = min_t(unsigned int, to_alloc, - PAGE_SIZE / sizeof(*page_list)); - } while (to_alloc > 0); - - kvfree(page_list); - return 0; - -err: - kvfree(page_list); - return ret; -} - static void mlx5vf_disable_fd(struct mlx5_vf_migration_file *migf) { mutex_lock(&migf->lock); @@ -777,36 +733,6 @@ mlx5vf_append_page_to_mig_buf(struct mlx5_vhca_data_buffer *vhca_buf, return 0; } -static int -mlx5vf_resume_read_image_no_header(struct mlx5_vhca_data_buffer *vhca_buf, - loff_t requested_length, - const char __user **buf, size_t *len, - loff_t *pos, ssize_t *done) -{ - int ret; - - if (requested_length > MAX_LOAD_SIZE) - return -ENOMEM; - - if (vhca_buf->allocated_length < requested_length) { - ret = mlx5vf_add_migration_pages( - vhca_buf, - DIV_ROUND_UP(requested_length - vhca_buf->allocated_length, - PAGE_SIZE)); - if (ret) - return ret; - } - - while (*len) { - ret = mlx5vf_append_page_to_mig_buf(vhca_buf, buf, len, pos, - done); - if (ret) - return ret; - } - - return 0; -} - static ssize_t mlx5vf_resume_read_image(struct mlx5_vf_migration_file *migf, struct mlx5_vhca_data_buffer *vhca_buf, @@ -1038,13 +964,6 @@ static ssize_t mlx5vf_resume_write(struct file *filp, const char __user *buf, migf->load_state = MLX5_VF_LOAD_STATE_READ_IMAGE; break; } - case MLX5_VF_LOAD_STATE_READ_IMAGE_NO_HEADER: - ret = mlx5vf_resume_read_image_no_header(vhca_buf, - requested_length, - &buf, &len, pos, &done); - if (ret) - goto out_unlock; - break; case MLX5_VF_LOAD_STATE_READ_IMAGE: ret = mlx5vf_resume_read_image(migf, vhca_buf, migf->record_size, @@ -1114,21 +1033,16 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev) } migf->buf[0] = buf; - if (MLX5VF_PRE_COPY_SUPP(mvdev)) { - buf = mlx5vf_alloc_data_buffer(migf, - sizeof(struct mlx5_vf_migration_header), DMA_NONE); - if (IS_ERR(buf)) { - ret = PTR_ERR(buf); - goto out_buf; - } - - migf->buf_header[0] = buf; - migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER; - } else { - /* Initial state will be to read the image */ - migf->load_state = MLX5_VF_LOAD_STATE_READ_IMAGE_NO_HEADER; + buf = mlx5vf_alloc_data_buffer(migf, + sizeof(struct mlx5_vf_migration_header), DMA_NONE); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto out_buf; } + migf->buf_header[0] = buf; + migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER; + stream_open(migf->filp->f_inode, migf->filp); mutex_init(&migf->lock); INIT_LIST_HEAD(&migf->buf_list); @@ -1262,13 +1176,6 @@ mlx5vf_pci_step_device_state_locked(struct mlx5vf_pci_core_device *mvdev, } if (cur == VFIO_DEVICE_STATE_RESUMING && new == VFIO_DEVICE_STATE_STOP) { - if (!MLX5VF_PRE_COPY_SUPP(mvdev)) { - ret = mlx5vf_cmd_load_vhca_state(mvdev, - mvdev->resuming_migf, - mvdev->resuming_migf->buf[0]); - if (ret) - return ERR_PTR(ret); - } mlx5vf_disable_fds(mvdev, NULL); return NULL; } From 9b27b117e29f63d0db3fcc474f645d6f4af6d3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 8 Mar 2024 09:51:19 +0100 Subject: [PATCH 764/814] vfio/platform: 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() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jason Gunthorpe Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/79d3df42fe5b359a05b8061631e72e5ed249b234.1709886922.git.u.kleine-koenig@pengutronix.de Signed-off-by: Alex Williamson --- drivers/vfio/platform/vfio_platform.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c index 8cf22fa65baa..42d1462c5e19 100644 --- a/drivers/vfio/platform/vfio_platform.c +++ b/drivers/vfio/platform/vfio_platform.c @@ -85,14 +85,13 @@ static void vfio_platform_release_dev(struct vfio_device *core_vdev) vfio_platform_release_common(vdev); } -static int vfio_platform_remove(struct platform_device *pdev) +static void vfio_platform_remove(struct platform_device *pdev) { struct vfio_platform_device *vdev = dev_get_drvdata(&pdev->dev); vfio_unregister_group_dev(&vdev->vdev); pm_runtime_disable(vdev->device); vfio_put_device(&vdev->vdev); - return 0; } static const struct vfio_device_ops vfio_platform_ops = { @@ -113,7 +112,7 @@ static const struct vfio_device_ops vfio_platform_ops = { static struct platform_driver vfio_platform_driver = { .probe = vfio_platform_probe, - .remove = vfio_platform_remove, + .remove_new = vfio_platform_remove, .driver = { .name = "vfio-platform", }, From 457f7308254756b6e4b8fc3876cb770dcf0e7cc7 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Mar 2024 10:21:48 -0800 Subject: [PATCH 765/814] vfio/pds: Make sure migration file isn't accessed after reset It's possible the migration file is accessed after reset when it has been cleaned up, especially when it's initiated by the device. This is because the driver doesn't rip out the filep when cleaning up it only frees the related page structures and sets its local struct pds_vfio_lm_file pointer to NULL. This can cause a NULL pointer dereference, which is shown in the example below during a restore after a device initiated reset: BUG: kernel NULL pointer dereference, address: 000000000000000c PF: supervisor read access in kernel mode PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI RIP: 0010:pds_vfio_get_file_page+0x5d/0xf0 [pds_vfio_pci] [...] Call Trace: pds_vfio_restore_write+0xf6/0x160 [pds_vfio_pci] vfs_write+0xc9/0x3f0 ? __fget_light+0xc9/0x110 ksys_write+0xb5/0xf0 __x64_sys_write+0x1a/0x20 do_syscall_64+0x38/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd [...] Add a disabled flag to the driver's struct pds_vfio_lm_file that gets set during cleanup. Then make sure to check the flag when the migration file is accessed via its file_operations. By default this flag will be false as the memory for struct pds_vfio_lm_file is kzalloc'd, which means the struct pds_vfio_lm_file is enabled and accessible. Also, since the file_operations and driver's migration file cleanup happen under the protection of the same pds_vfio_lm_file.lock, using this flag is thread safe. Fixes: 8512ed256334 ("vfio/pds: Always clear the save/restore FDs on reset") Reviewed-by: Shannon Nelson Signed-off-by: Brett Creeley Link: https://lore.kernel.org/r/20240308182149.22036-2-brett.creeley@amd.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/pds/lm.c | 13 +++++++++++++ drivers/vfio/pci/pds/lm.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/vfio/pci/pds/lm.c b/drivers/vfio/pci/pds/lm.c index 79fe2e66bb49..6b94cc0bf45b 100644 --- a/drivers/vfio/pci/pds/lm.c +++ b/drivers/vfio/pci/pds/lm.c @@ -92,8 +92,10 @@ static void pds_vfio_put_lm_file(struct pds_vfio_lm_file *lm_file) { mutex_lock(&lm_file->lock); + lm_file->disabled = true; lm_file->size = 0; lm_file->alloc_size = 0; + lm_file->filep->f_pos = 0; /* Free scatter list of file pages */ sg_free_table(&lm_file->sg_table); @@ -183,6 +185,12 @@ static ssize_t pds_vfio_save_read(struct file *filp, char __user *buf, pos = &filp->f_pos; mutex_lock(&lm_file->lock); + + if (lm_file->disabled) { + done = -ENODEV; + goto out_unlock; + } + if (*pos > lm_file->size) { done = -EINVAL; goto out_unlock; @@ -283,6 +291,11 @@ static ssize_t pds_vfio_restore_write(struct file *filp, const char __user *buf, mutex_lock(&lm_file->lock); + if (lm_file->disabled) { + done = -ENODEV; + goto out_unlock; + } + while (len) { size_t page_offset; struct page *page; diff --git a/drivers/vfio/pci/pds/lm.h b/drivers/vfio/pci/pds/lm.h index 13be893198b7..9511b1afc6a1 100644 --- a/drivers/vfio/pci/pds/lm.h +++ b/drivers/vfio/pci/pds/lm.h @@ -27,6 +27,7 @@ struct pds_vfio_lm_file { struct scatterlist *last_offset_sg; /* Iterator */ unsigned int sg_last_entry; unsigned long last_offset; + bool disabled; }; struct pds_vfio_pci_device; From 6a7e448c6b238c9b256b01eb198b0af93ae3157e Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Mar 2024 10:21:49 -0800 Subject: [PATCH 766/814] vfio/pds: Refactor/simplify reset logic The current logic for handling resets is more complicated than it needs to be. The deferred_reset flag is used to indicate a reset is needed and the deferred_reset_state is the requested, post-reset, state. Also, the deferred_reset logic was added to vfio migration drivers to prevent a circular locking dependency with respect to mm_lock and state mutex. This is mainly because of the copy_to/from_user() functions(which takes mm_lock) invoked under state mutex. Remove all of the deferred reset logic and just pass the requested next state to pds_vfio_reset() so it can be used for VMM and DSC initiated resets. This removes the need for pds_vfio_state_mutex_lock(), so remove that and replace its use with a simple mutex_unlock(). Also, remove the reset_mutex as it's no longer needed since the state_mutex can be the driver's primary protector. Suggested-by: Shameer Kolothum Reviewed-by: Shannon Nelson Signed-off-by: Brett Creeley Link: https://lore.kernel.org/r/20240308182149.22036-3-brett.creeley@amd.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/pds/dirty.c | 6 ++--- drivers/vfio/pci/pds/pci_drv.c | 27 ++++---------------- drivers/vfio/pci/pds/vfio_dev.c | 45 +++++++-------------------------- drivers/vfio/pci/pds/vfio_dev.h | 8 ++---- 4 files changed, 19 insertions(+), 67 deletions(-) diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c index 8ddf4346fcd5..68e8f006dfdb 100644 --- a/drivers/vfio/pci/pds/dirty.c +++ b/drivers/vfio/pci/pds/dirty.c @@ -607,7 +607,7 @@ int pds_vfio_dma_logging_report(struct vfio_device *vdev, unsigned long iova, mutex_lock(&pds_vfio->state_mutex); err = pds_vfio_dirty_sync(pds_vfio, dirty, iova, length); - pds_vfio_state_mutex_unlock(pds_vfio); + mutex_unlock(&pds_vfio->state_mutex); return err; } @@ -624,7 +624,7 @@ int pds_vfio_dma_logging_start(struct vfio_device *vdev, mutex_lock(&pds_vfio->state_mutex); pds_vfio_send_host_vf_lm_status_cmd(pds_vfio, PDS_LM_STA_IN_PROGRESS); err = pds_vfio_dirty_enable(pds_vfio, ranges, nnodes, page_size); - pds_vfio_state_mutex_unlock(pds_vfio); + mutex_unlock(&pds_vfio->state_mutex); return err; } @@ -637,7 +637,7 @@ int pds_vfio_dma_logging_stop(struct vfio_device *vdev) mutex_lock(&pds_vfio->state_mutex); pds_vfio_dirty_disable(pds_vfio, true); - pds_vfio_state_mutex_unlock(pds_vfio); + mutex_unlock(&pds_vfio->state_mutex); return 0; } diff --git a/drivers/vfio/pci/pds/pci_drv.c b/drivers/vfio/pci/pds/pci_drv.c index a34dda516629..16e93b11ab1b 100644 --- a/drivers/vfio/pci/pds/pci_drv.c +++ b/drivers/vfio/pci/pds/pci_drv.c @@ -21,16 +21,13 @@ static void pds_vfio_recovery(struct pds_vfio_pci_device *pds_vfio) { - bool deferred_reset_needed = false; - /* * Documentation states that the kernel migration driver must not * generate asynchronous device state transitions outside of * manipulation by the user or the VFIO_DEVICE_RESET ioctl. * * Since recovery is an asynchronous event received from the device, - * initiate a deferred reset. Issue a deferred reset in the following - * situations: + * initiate a reset in the following situations: * 1. Migration is in progress, which will cause the next step of * the migration to fail. * 2. If the device is in a state that will be set to @@ -42,24 +39,8 @@ static void pds_vfio_recovery(struct pds_vfio_pci_device *pds_vfio) pds_vfio->state != VFIO_DEVICE_STATE_ERROR) || (pds_vfio->state == VFIO_DEVICE_STATE_RUNNING && pds_vfio_dirty_is_enabled(pds_vfio))) - deferred_reset_needed = true; + pds_vfio_reset(pds_vfio, VFIO_DEVICE_STATE_ERROR); mutex_unlock(&pds_vfio->state_mutex); - - /* - * On the next user initiated state transition, the device will - * transition to the VFIO_DEVICE_STATE_ERROR. At this point it's the user's - * responsibility to reset the device. - * - * If a VFIO_DEVICE_RESET is requested post recovery and before the next - * state transition, then the deferred reset state will be set to - * VFIO_DEVICE_STATE_RUNNING. - */ - if (deferred_reset_needed) { - mutex_lock(&pds_vfio->reset_mutex); - pds_vfio->deferred_reset = true; - pds_vfio->deferred_reset_state = VFIO_DEVICE_STATE_ERROR; - mutex_unlock(&pds_vfio->reset_mutex); - } } static int pds_vfio_pci_notify_handler(struct notifier_block *nb, @@ -185,7 +166,9 @@ static void pds_vfio_pci_aer_reset_done(struct pci_dev *pdev) { struct pds_vfio_pci_device *pds_vfio = pds_vfio_pci_drvdata(pdev); - pds_vfio_reset(pds_vfio); + mutex_lock(&pds_vfio->state_mutex); + pds_vfio_reset(pds_vfio, VFIO_DEVICE_STATE_RUNNING); + mutex_unlock(&pds_vfio->state_mutex); } static const struct pci_error_handlers pds_vfio_pci_err_handlers = { diff --git a/drivers/vfio/pci/pds/vfio_dev.c b/drivers/vfio/pci/pds/vfio_dev.c index a286ebcc7112..76a80ae7087b 100644 --- a/drivers/vfio/pci/pds/vfio_dev.c +++ b/drivers/vfio/pci/pds/vfio_dev.c @@ -26,37 +26,14 @@ struct pds_vfio_pci_device *pds_vfio_pci_drvdata(struct pci_dev *pdev) vfio_coredev); } -void pds_vfio_state_mutex_unlock(struct pds_vfio_pci_device *pds_vfio) +void pds_vfio_reset(struct pds_vfio_pci_device *pds_vfio, + enum vfio_device_mig_state state) { -again: - mutex_lock(&pds_vfio->reset_mutex); - if (pds_vfio->deferred_reset) { - pds_vfio->deferred_reset = false; - pds_vfio_put_restore_file(pds_vfio); - pds_vfio_put_save_file(pds_vfio); - if (pds_vfio->state == VFIO_DEVICE_STATE_ERROR) { - pds_vfio_dirty_disable(pds_vfio, false); - } - pds_vfio->state = pds_vfio->deferred_reset_state; - pds_vfio->deferred_reset_state = VFIO_DEVICE_STATE_RUNNING; - mutex_unlock(&pds_vfio->reset_mutex); - goto again; - } - mutex_unlock(&pds_vfio->state_mutex); - mutex_unlock(&pds_vfio->reset_mutex); -} - -void pds_vfio_reset(struct pds_vfio_pci_device *pds_vfio) -{ - mutex_lock(&pds_vfio->reset_mutex); - pds_vfio->deferred_reset = true; - pds_vfio->deferred_reset_state = VFIO_DEVICE_STATE_RUNNING; - if (!mutex_trylock(&pds_vfio->state_mutex)) { - mutex_unlock(&pds_vfio->reset_mutex); - return; - } - mutex_unlock(&pds_vfio->reset_mutex); - pds_vfio_state_mutex_unlock(pds_vfio); + pds_vfio_put_restore_file(pds_vfio); + pds_vfio_put_save_file(pds_vfio); + if (state == VFIO_DEVICE_STATE_ERROR) + pds_vfio_dirty_disable(pds_vfio, false); + pds_vfio->state = state; } static struct file * @@ -97,8 +74,7 @@ pds_vfio_set_device_state(struct vfio_device *vdev, break; } } - pds_vfio_state_mutex_unlock(pds_vfio); - /* still waiting on a deferred_reset */ + mutex_unlock(&pds_vfio->state_mutex); if (pds_vfio->state == VFIO_DEVICE_STATE_ERROR) res = ERR_PTR(-EIO); @@ -114,7 +90,7 @@ static int pds_vfio_get_device_state(struct vfio_device *vdev, mutex_lock(&pds_vfio->state_mutex); *current_state = pds_vfio->state; - pds_vfio_state_mutex_unlock(pds_vfio); + mutex_unlock(&pds_vfio->state_mutex); return 0; } @@ -156,7 +132,6 @@ static int pds_vfio_init_device(struct vfio_device *vdev) pds_vfio->vf_id = vf_id; mutex_init(&pds_vfio->state_mutex); - mutex_init(&pds_vfio->reset_mutex); vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P; vdev->mig_ops = &pds_vfio_lm_ops; @@ -178,7 +153,6 @@ static void pds_vfio_release_device(struct vfio_device *vdev) vfio_coredev.vdev); mutex_destroy(&pds_vfio->state_mutex); - mutex_destroy(&pds_vfio->reset_mutex); vfio_pci_core_release_dev(vdev); } @@ -194,7 +168,6 @@ static int pds_vfio_open_device(struct vfio_device *vdev) return err; pds_vfio->state = VFIO_DEVICE_STATE_RUNNING; - pds_vfio->deferred_reset_state = VFIO_DEVICE_STATE_RUNNING; vfio_pci_core_finish_enable(&pds_vfio->vfio_coredev); diff --git a/drivers/vfio/pci/pds/vfio_dev.h b/drivers/vfio/pci/pds/vfio_dev.h index e7b01080a1ec..803d99d69c73 100644 --- a/drivers/vfio/pci/pds/vfio_dev.h +++ b/drivers/vfio/pci/pds/vfio_dev.h @@ -18,20 +18,16 @@ struct pds_vfio_pci_device { struct pds_vfio_dirty dirty; struct mutex state_mutex; /* protect migration state */ enum vfio_device_mig_state state; - struct mutex reset_mutex; /* protect reset_done flow */ - u8 deferred_reset; - enum vfio_device_mig_state deferred_reset_state; struct notifier_block nb; int vf_id; u16 client_id; }; -void pds_vfio_state_mutex_unlock(struct pds_vfio_pci_device *pds_vfio); - const struct vfio_device_ops *pds_vfio_ops_info(void); struct pds_vfio_pci_device *pds_vfio_pci_drvdata(struct pci_dev *pdev); -void pds_vfio_reset(struct pds_vfio_pci_device *pds_vfio); +void pds_vfio_reset(struct pds_vfio_pci_device *pds_vfio, + enum vfio_device_mig_state state); struct pci_dev *pds_vfio_to_pci_dev(struct pds_vfio_pci_device *pds_vfio); struct device *pds_vfio_to_dev(struct pds_vfio_pci_device *pds_vfio); From fe9a7082684eb059b925c535682e68c34d487d43 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:22 -0700 Subject: [PATCH 767/814] vfio/pci: Disable auto-enable of exclusive INTx IRQ Currently for devices requiring masking at the irqchip for INTx, ie. devices without DisINTx support, the IRQ is enabled in request_irq() and subsequently disabled as necessary to align with the masked status flag. This presents a window where the interrupt could fire between these events, resulting in the IRQ incrementing the disable depth twice. This would be unrecoverable for a user since the masked flag prevents nested enables through vfio. Instead, invert the logic using IRQF_NO_AUTOEN such that exclusive INTx is never auto-enabled, then unmask as required. Cc: Fixes: 89e1f7d4c66d ("vfio: Add PCI device driver") Reviewed-by: Kevin Tian Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-2-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 237beac83809..136101179fcb 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -296,8 +296,15 @@ static int vfio_intx_set_signal(struct vfio_pci_core_device *vdev, int fd) ctx->trigger = trigger; + /* + * Devices without DisINTx support require an exclusive interrupt, + * IRQ masking is performed at the IRQ chip. The masked status is + * protected by vdev->irqlock. Setup the IRQ without auto-enable and + * unmask as necessary below under lock. DisINTx is unmodified by + * the IRQ configuration and may therefore use auto-enable. + */ if (!vdev->pci_2_3) - irqflags = 0; + irqflags = IRQF_NO_AUTOEN; ret = request_irq(pdev->irq, vfio_intx_handler, irqflags, ctx->name, vdev); @@ -308,13 +315,9 @@ static int vfio_intx_set_signal(struct vfio_pci_core_device *vdev, int fd) return ret; } - /* - * INTx disable will stick across the new irq setup, - * disable_irq won't. - */ spin_lock_irqsave(&vdev->irqlock, flags); - if (!vdev->pci_2_3 && ctx->masked) - disable_irq_nosync(pdev->irq); + if (!vdev->pci_2_3 && !ctx->masked) + enable_irq(pdev->irq); spin_unlock_irqrestore(&vdev->irqlock, flags); return 0; From 810cd4bb53456d0503cc4e7934e063835152c1b7 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:23 -0700 Subject: [PATCH 768/814] vfio/pci: Lock external INTx masking ops Mask operations through config space changes to DisINTx may race INTx configuration changes via ioctl. Create wrappers that add locking for paths outside of the core interrupt code. In particular, irq_type is updated holding igate, therefore testing is_intx() requires holding igate. For example clearing DisINTx from config space can otherwise race changes of the interrupt configuration. This aligns interfaces which may trigger the INTx eventfd into two camps, one side serialized by igate and the other only enabled while INTx is configured. A subsequent patch introduces synchronization for the latter flows. Cc: Fixes: 89e1f7d4c66d ("vfio: Add PCI device driver") Reported-by: Reinette Chatre Reviewed-by: Kevin Tian Reviewed-by: Reinette Chatre Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 34 +++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 136101179fcb..75c85eec21b3 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -99,13 +99,15 @@ static void vfio_send_intx_eventfd(void *opaque, void *unused) } /* Returns true if the INTx vfio_pci_irq_ctx.masked value is changed. */ -bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev) +static bool __vfio_pci_intx_mask(struct vfio_pci_core_device *vdev) { struct pci_dev *pdev = vdev->pdev; struct vfio_pci_irq_ctx *ctx; unsigned long flags; bool masked_changed = false; + lockdep_assert_held(&vdev->igate); + spin_lock_irqsave(&vdev->irqlock, flags); /* @@ -143,6 +145,17 @@ out_unlock: return masked_changed; } +bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev) +{ + bool mask_changed; + + mutex_lock(&vdev->igate); + mask_changed = __vfio_pci_intx_mask(vdev); + mutex_unlock(&vdev->igate); + + return mask_changed; +} + /* * If this is triggered by an eventfd, we can't call eventfd_signal * or else we'll deadlock on the eventfd wait queue. Return >0 when @@ -194,12 +207,21 @@ out_unlock: return ret; } -void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) +static void __vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) { + lockdep_assert_held(&vdev->igate); + if (vfio_pci_intx_unmask_handler(vdev, NULL) > 0) vfio_send_intx_eventfd(vdev, NULL); } +void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) +{ + mutex_lock(&vdev->igate); + __vfio_pci_intx_unmask(vdev); + mutex_unlock(&vdev->igate); +} + static irqreturn_t vfio_intx_handler(int irq, void *dev_id) { struct vfio_pci_core_device *vdev = dev_id; @@ -563,11 +585,11 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_core_device *vdev, return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_NONE) { - vfio_pci_intx_unmask(vdev); + __vfio_pci_intx_unmask(vdev); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t unmask = *(uint8_t *)data; if (unmask) - vfio_pci_intx_unmask(vdev); + __vfio_pci_intx_unmask(vdev); } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { struct vfio_pci_irq_ctx *ctx = vfio_irq_ctx_get(vdev, 0); int32_t fd = *(int32_t *)data; @@ -594,11 +616,11 @@ static int vfio_pci_set_intx_mask(struct vfio_pci_core_device *vdev, return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_NONE) { - vfio_pci_intx_mask(vdev); + __vfio_pci_intx_mask(vdev); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t mask = *(uint8_t *)data; if (mask) - vfio_pci_intx_mask(vdev); + __vfio_pci_intx_mask(vdev); } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { return -ENOTTY; /* XXX implement me */ } From b620ecbd17a03cacd06f014a5d3f3a11285ce053 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:24 -0700 Subject: [PATCH 769/814] vfio: Introduce interface to flush virqfd inject workqueue In order to synchronize changes that can affect the thread callback, introduce an interface to force a flush of the inject workqueue. The irqfd pointer is only valid under spinlock, but the workqueue cannot be flushed under spinlock. Therefore the flush work for the irqfd is queued under spinlock. The vfio_irqfd_cleanup_wq workqueue is re-used for queuing this work such that flushing the workqueue is also ordered relative to shutdown. Reviewed-by: Kevin Tian Reviewed-by: Reinette Chatre Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-4-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/virqfd.c | 21 +++++++++++++++++++++ include/linux/vfio.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index 29c564b7a6e1..532269133801 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -101,6 +101,13 @@ static void virqfd_inject(struct work_struct *work) virqfd->thread(virqfd->opaque, virqfd->data); } +static void virqfd_flush_inject(struct work_struct *work) +{ + struct virqfd *virqfd = container_of(work, struct virqfd, flush_inject); + + flush_work(&virqfd->inject); +} + int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *), void (*thread)(void *, void *), @@ -124,6 +131,7 @@ int vfio_virqfd_enable(void *opaque, INIT_WORK(&virqfd->shutdown, virqfd_shutdown); INIT_WORK(&virqfd->inject, virqfd_inject); + INIT_WORK(&virqfd->flush_inject, virqfd_flush_inject); irqfd = fdget(fd); if (!irqfd.file) { @@ -213,3 +221,16 @@ void vfio_virqfd_disable(struct virqfd **pvirqfd) flush_workqueue(vfio_irqfd_cleanup_wq); } EXPORT_SYMBOL_GPL(vfio_virqfd_disable); + +void vfio_virqfd_flush_thread(struct virqfd **pvirqfd) +{ + unsigned long flags; + + spin_lock_irqsave(&virqfd_lock, flags); + if (*pvirqfd && (*pvirqfd)->thread) + queue_work(vfio_irqfd_cleanup_wq, &(*pvirqfd)->flush_inject); + spin_unlock_irqrestore(&virqfd_lock, flags); + + flush_workqueue(vfio_irqfd_cleanup_wq); +} +EXPORT_SYMBOL_GPL(vfio_virqfd_flush_thread); diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 89b265bc6ec3..8b1a29820409 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -356,6 +356,7 @@ struct virqfd { wait_queue_entry_t wait; poll_table pt; struct work_struct shutdown; + struct work_struct flush_inject; struct virqfd **pvirqfd; }; @@ -363,5 +364,6 @@ int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *), void (*thread)(void *, void *), void *data, struct virqfd **pvirqfd, int fd); void vfio_virqfd_disable(struct virqfd **pvirqfd); +void vfio_virqfd_flush_thread(struct virqfd **pvirqfd); #endif /* VFIO_H */ From 18c198c96a815c962adc2b9b77909eec0be7df4d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:25 -0700 Subject: [PATCH 770/814] vfio/pci: Create persistent INTx handler A vulnerability exists where the eventfd for INTx signaling can be deconfigured, which unregisters the IRQ handler but still allows eventfds to be signaled with a NULL context through the SET_IRQS ioctl or through unmask irqfd if the device interrupt is pending. Ideally this could be solved with some additional locking; the igate mutex serializes the ioctl and config space accesses, and the interrupt handler is unregistered relative to the trigger, but the irqfd path runs asynchronous to those. The igate mutex cannot be acquired from the atomic context of the eventfd wake function. Disabling the irqfd relative to the eventfd registration is potentially incompatible with existing userspace. As a result, the solution implemented here moves configuration of the INTx interrupt handler to track the lifetime of the INTx context object and irq_type configuration, rather than registration of a particular trigger eventfd. Synchronization is added between the ioctl path and eventfd_signal() wrapper such that the eventfd trigger can be dynamically updated relative to in-flight interrupts or irqfd callbacks. Cc: Fixes: 89e1f7d4c66d ("vfio: Add PCI device driver") Reported-by: Reinette Chatre Reviewed-by: Kevin Tian Reviewed-by: Reinette Chatre Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-5-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 149 ++++++++++++++++-------------- 1 file changed, 80 insertions(+), 69 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 75c85eec21b3..fb5392b749ff 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -90,11 +90,15 @@ static void vfio_send_intx_eventfd(void *opaque, void *unused) if (likely(is_intx(vdev) && !vdev->virq_disabled)) { struct vfio_pci_irq_ctx *ctx; + struct eventfd_ctx *trigger; ctx = vfio_irq_ctx_get(vdev, 0); if (WARN_ON_ONCE(!ctx)) return; - eventfd_signal(ctx->trigger); + + trigger = READ_ONCE(ctx->trigger); + if (likely(trigger)) + eventfd_signal(trigger); } } @@ -253,100 +257,100 @@ static irqreturn_t vfio_intx_handler(int irq, void *dev_id) return ret; } -static int vfio_intx_enable(struct vfio_pci_core_device *vdev) +static int vfio_intx_enable(struct vfio_pci_core_device *vdev, + struct eventfd_ctx *trigger) { + struct pci_dev *pdev = vdev->pdev; struct vfio_pci_irq_ctx *ctx; + unsigned long irqflags; + char *name; + int ret; if (!is_irq_none(vdev)) return -EINVAL; - if (!vdev->pdev->irq) + if (!pdev->irq) return -ENODEV; + name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)", pci_name(pdev)); + if (!name) + return -ENOMEM; + ctx = vfio_irq_ctx_alloc(vdev, 0); if (!ctx) return -ENOMEM; + ctx->name = name; + ctx->trigger = trigger; + /* - * If the virtual interrupt is masked, restore it. Devices - * supporting DisINTx can be masked at the hardware level - * here, non-PCI-2.3 devices will have to wait until the - * interrupt is enabled. + * Fill the initial masked state based on virq_disabled. After + * enable, changing the DisINTx bit in vconfig directly changes INTx + * masking. igate prevents races during setup, once running masked + * is protected via irqlock. + * + * Devices supporting DisINTx also reflect the current mask state in + * the physical DisINTx bit, which is not affected during IRQ setup. + * + * Devices without DisINTx support require an exclusive interrupt. + * IRQ masking is performed at the IRQ chip. Again, igate protects + * against races during setup and IRQ handlers and irqfds are not + * yet active, therefore masked is stable and can be used to + * conditionally auto-enable the IRQ. + * + * irq_type must be stable while the IRQ handler is registered, + * therefore it must be set before request_irq(). */ ctx->masked = vdev->virq_disabled; - if (vdev->pci_2_3) - pci_intx(vdev->pdev, !ctx->masked); + if (vdev->pci_2_3) { + pci_intx(pdev, !ctx->masked); + irqflags = IRQF_SHARED; + } else { + irqflags = ctx->masked ? IRQF_NO_AUTOEN : 0; + } vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX; + ret = request_irq(pdev->irq, vfio_intx_handler, + irqflags, ctx->name, vdev); + if (ret) { + vdev->irq_type = VFIO_PCI_NUM_IRQS; + kfree(name); + vfio_irq_ctx_free(vdev, ctx, 0); + return ret; + } + return 0; } -static int vfio_intx_set_signal(struct vfio_pci_core_device *vdev, int fd) +static int vfio_intx_set_signal(struct vfio_pci_core_device *vdev, + struct eventfd_ctx *trigger) { struct pci_dev *pdev = vdev->pdev; - unsigned long irqflags = IRQF_SHARED; struct vfio_pci_irq_ctx *ctx; - struct eventfd_ctx *trigger; - unsigned long flags; - int ret; + struct eventfd_ctx *old; ctx = vfio_irq_ctx_get(vdev, 0); if (WARN_ON_ONCE(!ctx)) return -EINVAL; - if (ctx->trigger) { - free_irq(pdev->irq, vdev); - kfree(ctx->name); - eventfd_ctx_put(ctx->trigger); - ctx->trigger = NULL; + old = ctx->trigger; + + WRITE_ONCE(ctx->trigger, trigger); + + /* Releasing an old ctx requires synchronizing in-flight users */ + if (old) { + synchronize_irq(pdev->irq); + vfio_virqfd_flush_thread(&ctx->unmask); + eventfd_ctx_put(old); } - if (fd < 0) /* Disable only */ - return 0; - - ctx->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)", - pci_name(pdev)); - if (!ctx->name) - return -ENOMEM; - - trigger = eventfd_ctx_fdget(fd); - if (IS_ERR(trigger)) { - kfree(ctx->name); - return PTR_ERR(trigger); - } - - ctx->trigger = trigger; - - /* - * Devices without DisINTx support require an exclusive interrupt, - * IRQ masking is performed at the IRQ chip. The masked status is - * protected by vdev->irqlock. Setup the IRQ without auto-enable and - * unmask as necessary below under lock. DisINTx is unmodified by - * the IRQ configuration and may therefore use auto-enable. - */ - if (!vdev->pci_2_3) - irqflags = IRQF_NO_AUTOEN; - - ret = request_irq(pdev->irq, vfio_intx_handler, - irqflags, ctx->name, vdev); - if (ret) { - ctx->trigger = NULL; - kfree(ctx->name); - eventfd_ctx_put(trigger); - return ret; - } - - spin_lock_irqsave(&vdev->irqlock, flags); - if (!vdev->pci_2_3 && !ctx->masked) - enable_irq(pdev->irq); - spin_unlock_irqrestore(&vdev->irqlock, flags); - return 0; } static void vfio_intx_disable(struct vfio_pci_core_device *vdev) { + struct pci_dev *pdev = vdev->pdev; struct vfio_pci_irq_ctx *ctx; ctx = vfio_irq_ctx_get(vdev, 0); @@ -354,10 +358,13 @@ static void vfio_intx_disable(struct vfio_pci_core_device *vdev) if (ctx) { vfio_virqfd_disable(&ctx->unmask); vfio_virqfd_disable(&ctx->mask); + free_irq(pdev->irq, vdev); + if (ctx->trigger) + eventfd_ctx_put(ctx->trigger); + kfree(ctx->name); + vfio_irq_ctx_free(vdev, ctx, 0); } - vfio_intx_set_signal(vdev, -1); vdev->irq_type = VFIO_PCI_NUM_IRQS; - vfio_irq_ctx_free(vdev, ctx, 0); } /* @@ -641,19 +648,23 @@ static int vfio_pci_set_intx_trigger(struct vfio_pci_core_device *vdev, return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { + struct eventfd_ctx *trigger = NULL; int32_t fd = *(int32_t *)data; int ret; + if (fd >= 0) { + trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(trigger)) + return PTR_ERR(trigger); + } + if (is_intx(vdev)) - return vfio_intx_set_signal(vdev, fd); + ret = vfio_intx_set_signal(vdev, trigger); + else + ret = vfio_intx_enable(vdev, trigger); - ret = vfio_intx_enable(vdev); - if (ret) - return ret; - - ret = vfio_intx_set_signal(vdev, fd); - if (ret) - vfio_intx_disable(vdev); + if (ret && trigger) + eventfd_ctx_put(trigger); return ret; } From fcdc0d3d40bc26c105acf8467f7d9018970944ae Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:26 -0700 Subject: [PATCH 771/814] vfio/platform: Disable virqfds on cleanup irqfds for mask and unmask that are not specifically disabled by the user are leaked. Remove any irqfds during cleanup Cc: Eric Auger Cc: Fixes: a7fa7c77cf15 ("vfio/platform: implement IRQ masking/unmasking via an eventfd") Reviewed-by: Kevin Tian Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-6-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/platform/vfio_platform_irq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c index 61a1bfb68ac7..e5dcada9e86c 100644 --- a/drivers/vfio/platform/vfio_platform_irq.c +++ b/drivers/vfio/platform/vfio_platform_irq.c @@ -321,8 +321,11 @@ void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev) { int i; - for (i = 0; i < vdev->num_irqs; i++) + for (i = 0; i < vdev->num_irqs; i++) { + vfio_virqfd_disable(&vdev->irqs[i].mask); + vfio_virqfd_disable(&vdev->irqs[i].unmask); vfio_set_trigger(vdev, i, -1, NULL); + } vdev->num_irqs = 0; kfree(vdev->irqs); From 675daf435e9f8e5a5eab140a9864dfad6668b375 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:27 -0700 Subject: [PATCH 772/814] vfio/platform: Create persistent IRQ handlers The vfio-platform SET_IRQS ioctl currently allows loopback triggering of an interrupt before a signaling eventfd has been configured by the user, which thereby allows a NULL pointer dereference. Rather than register the IRQ relative to a valid trigger, register all IRQs in a disabled state in the device open path. This allows mask operations on the IRQ to nest within the overall enable state governed by a valid eventfd signal. This decouples @masked, protected by the @locked spinlock from @trigger, protected via the @igate mutex. In doing so, it's guaranteed that changes to @trigger cannot race the IRQ handlers because the IRQ handler is synchronously disabled before modifying the trigger, and loopback triggering of the IRQ via ioctl is safe due to serialization with trigger changes via igate. For compatibility, request_irq() failures are maintained to be local to the SET_IRQS ioctl rather than a fatal error in the open device path. This allows, for example, a userspace driver with polling mode support to continue to work regardless of moving the request_irq() call site. This necessarily blocks all SET_IRQS access to the failed index. Cc: Eric Auger Cc: Fixes: 57f972e2b341 ("vfio/platform: trigger an interrupt via eventfd") Reviewed-by: Kevin Tian Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-7-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/platform/vfio_platform_irq.c | 100 +++++++++++++++------- 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c index e5dcada9e86c..ef41ecef83af 100644 --- a/drivers/vfio/platform/vfio_platform_irq.c +++ b/drivers/vfio/platform/vfio_platform_irq.c @@ -136,6 +136,16 @@ static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev, return 0; } +/* + * The trigger eventfd is guaranteed valid in the interrupt path + * and protected by the igate mutex when triggered via ioctl. + */ +static void vfio_send_eventfd(struct vfio_platform_irq *irq_ctx) +{ + if (likely(irq_ctx->trigger)) + eventfd_signal(irq_ctx->trigger); +} + static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id) { struct vfio_platform_irq *irq_ctx = dev_id; @@ -155,7 +165,7 @@ static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id) spin_unlock_irqrestore(&irq_ctx->lock, flags); if (ret == IRQ_HANDLED) - eventfd_signal(irq_ctx->trigger); + vfio_send_eventfd(irq_ctx); return ret; } @@ -164,52 +174,40 @@ static irqreturn_t vfio_irq_handler(int irq, void *dev_id) { struct vfio_platform_irq *irq_ctx = dev_id; - eventfd_signal(irq_ctx->trigger); + vfio_send_eventfd(irq_ctx); return IRQ_HANDLED; } static int vfio_set_trigger(struct vfio_platform_device *vdev, int index, - int fd, irq_handler_t handler) + int fd) { struct vfio_platform_irq *irq = &vdev->irqs[index]; struct eventfd_ctx *trigger; - int ret; if (irq->trigger) { - irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN); - free_irq(irq->hwirq, irq); - kfree(irq->name); + disable_irq(irq->hwirq); eventfd_ctx_put(irq->trigger); irq->trigger = NULL; } if (fd < 0) /* Disable only */ return 0; - irq->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-irq[%d](%s)", - irq->hwirq, vdev->name); - if (!irq->name) - return -ENOMEM; trigger = eventfd_ctx_fdget(fd); - if (IS_ERR(trigger)) { - kfree(irq->name); + if (IS_ERR(trigger)) return PTR_ERR(trigger); - } irq->trigger = trigger; - irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN); - ret = request_irq(irq->hwirq, handler, 0, irq->name, irq); - if (ret) { - kfree(irq->name); - eventfd_ctx_put(trigger); - irq->trigger = NULL; - return ret; - } - - if (!irq->masked) - enable_irq(irq->hwirq); + /* + * irq->masked effectively provides nested disables within the overall + * enable relative to trigger. Specifically request_irq() is called + * with NO_AUTOEN, therefore the IRQ is initially disabled. The user + * may only further disable the IRQ with a MASK operations because + * irq->masked is initially false. + */ + enable_irq(irq->hwirq); return 0; } @@ -228,7 +226,7 @@ static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev, handler = vfio_irq_handler; if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) - return vfio_set_trigger(vdev, index, -1, handler); + return vfio_set_trigger(vdev, index, -1); if (start != 0 || count != 1) return -EINVAL; @@ -236,7 +234,7 @@ static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev, if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { int32_t fd = *(int32_t *)data; - return vfio_set_trigger(vdev, index, fd, handler); + return vfio_set_trigger(vdev, index, fd); } if (flags & VFIO_IRQ_SET_DATA_NONE) { @@ -260,6 +258,14 @@ int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, unsigned start, unsigned count, uint32_t flags, void *data) = NULL; + /* + * For compatibility, errors from request_irq() are local to the + * SET_IRQS path and reflected in the name pointer. This allows, + * for example, polling mode fallback for an exclusive IRQ failure. + */ + if (IS_ERR(vdev->irqs[index].name)) + return PTR_ERR(vdev->irqs[index].name); + switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { case VFIO_IRQ_SET_ACTION_MASK: func = vfio_platform_set_irq_mask; @@ -280,7 +286,7 @@ int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, int vfio_platform_irq_init(struct vfio_platform_device *vdev) { - int cnt = 0, i; + int cnt = 0, i, ret = 0; while (vdev->get_irq(vdev, cnt) >= 0) cnt++; @@ -292,29 +298,54 @@ int vfio_platform_irq_init(struct vfio_platform_device *vdev) for (i = 0; i < cnt; i++) { int hwirq = vdev->get_irq(vdev, i); + irq_handler_t handler = vfio_irq_handler; - if (hwirq < 0) + if (hwirq < 0) { + ret = -EINVAL; goto err; + } spin_lock_init(&vdev->irqs[i].lock); vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD; - if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) + if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) { vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE | VFIO_IRQ_INFO_AUTOMASKED; + handler = vfio_automasked_irq_handler; + } vdev->irqs[i].count = 1; vdev->irqs[i].hwirq = hwirq; vdev->irqs[i].masked = false; + vdev->irqs[i].name = kasprintf(GFP_KERNEL_ACCOUNT, + "vfio-irq[%d](%s)", hwirq, + vdev->name); + if (!vdev->irqs[i].name) { + ret = -ENOMEM; + goto err; + } + + ret = request_irq(hwirq, handler, IRQF_NO_AUTOEN, + vdev->irqs[i].name, &vdev->irqs[i]); + if (ret) { + kfree(vdev->irqs[i].name); + vdev->irqs[i].name = ERR_PTR(ret); + } } vdev->num_irqs = cnt; return 0; err: + for (--i; i >= 0; i--) { + if (!IS_ERR(vdev->irqs[i].name)) { + free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]); + kfree(vdev->irqs[i].name); + } + } kfree(vdev->irqs); - return -EINVAL; + return ret; } void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev) @@ -324,7 +355,12 @@ void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev) for (i = 0; i < vdev->num_irqs; i++) { vfio_virqfd_disable(&vdev->irqs[i].mask); vfio_virqfd_disable(&vdev->irqs[i].unmask); - vfio_set_trigger(vdev, i, -1, NULL); + if (!IS_ERR(vdev->irqs[i].name)) { + free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]); + if (vdev->irqs[i].trigger) + eventfd_ctx_put(vdev->irqs[i].trigger); + kfree(vdev->irqs[i].name); + } } vdev->num_irqs = 0; From 7447d911af699a15f8d050dfcb7c680a86f87012 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 8 Mar 2024 16:05:28 -0700 Subject: [PATCH 773/814] vfio/fsl-mc: Block calling interrupt handler without trigger The eventfd_ctx trigger pointer of the vfio_fsl_mc_irq object is initially NULL and may become NULL if the user sets the trigger eventfd to -1. The interrupt handler itself is guaranteed that trigger is always valid between request_irq() and free_irq(), but the loopback testing mechanisms to invoke the handler function need to test the trigger. The triggering and setting ioctl paths both make use of igate and are therefore mutually exclusive. The vfio-fsl-mc driver does not make use of irqfds, nor does it support any sort of masking operations, therefore unlike vfio-pci and vfio-platform, the flow can remain essentially unchanged. Cc: Diana Craciun Cc: Fixes: cc0ee20bd969 ("vfio/fsl-mc: trigger an interrupt via eventfd") Reviewed-by: Kevin Tian Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20240308230557.805580-8-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c index d62fbfff20b8..82b2afa9b7e3 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c @@ -141,13 +141,14 @@ static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev, irq = &vdev->mc_irqs[index]; if (flags & VFIO_IRQ_SET_DATA_NONE) { - vfio_fsl_mc_irq_handler(hwirq, irq); + if (irq->trigger) + eventfd_signal(irq->trigger); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { u8 trigger = *(u8 *)data; - if (trigger) - vfio_fsl_mc_irq_handler(hwirq, irq); + if (trigger && irq->trigger) + eventfd_signal(irq->trigger); } return 0; From 54c180e73ffa3e17a8289fa531279eeb2034b69f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 11 Mar 2024 12:13:03 -0600 Subject: [PATCH 774/814] of: Move all FDT reserved-memory handling into of_reserved_mem.c The split of /reserved-memory handling between fdt.c and of_reserved_mem.c makes for reading and restructuring the code difficult. As of_reserved_mem.c is only built for CONFIG_OF_EARLY_FLATTREE already, move all the code to one spot. Acked-by: Saravana Kannan Reviewed-by: Oreoluwa Babatunde Link: https://lore.kernel.org/r/20240311181303.1516514-2-robh@kernel.org Signed-off-by: Rob Herring --- drivers/of/fdt.c | 123 +--------------------------------- drivers/of/of_private.h | 5 +- drivers/of/of_reserved_mem.c | 125 ++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 126 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index e5a385285149..a8a04f27915b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -88,7 +87,7 @@ void __init of_fdt_limit_memory(int limit) } } -static bool of_fdt_device_is_available(const void *blob, unsigned long node) +bool of_fdt_device_is_available(const void *blob, unsigned long node) { const char *status = fdt_getprop(blob, node, "status", NULL); @@ -484,126 +483,6 @@ void *initial_boot_params __ro_after_init; static u32 of_fdt_crc32; -static int __init early_init_dt_reserve_memory(phys_addr_t base, - phys_addr_t size, bool nomap) -{ - if (nomap) { - /* - * If the memory is already reserved (by another region), we - * should not allow it to be marked nomap, but don't worry - * if the region isn't memory as it won't be mapped. - */ - if (memblock_overlaps_region(&memblock.memory, base, size) && - memblock_is_region_reserved(base, size)) - return -EBUSY; - - return memblock_mark_nomap(base, size); - } - return memblock_reserve(base, size); -} - -/* - * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property - */ -static int __init __reserved_mem_reserve_reg(unsigned long node, - const char *uname) -{ - int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); - phys_addr_t base, size; - int len; - const __be32 *prop; - int first = 1; - bool nomap; - - prop = of_get_flat_dt_prop(node, "reg", &len); - if (!prop) - return -ENOENT; - - if (len && len % t_len != 0) { - pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", - uname); - return -EINVAL; - } - - nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; - - while (len >= t_len) { - base = dt_mem_next_cell(dt_root_addr_cells, &prop); - size = dt_mem_next_cell(dt_root_size_cells, &prop); - - if (size && - early_init_dt_reserve_memory(base, size, nomap) == 0) - pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", - uname, &base, (unsigned long)(size / SZ_1M)); - else - pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", - uname, &base, (unsigned long)(size / SZ_1M)); - - len -= t_len; - if (first) { - fdt_reserved_mem_save_node(node, uname, base, size); - first = 0; - } - } - return 0; -} - -/* - * __reserved_mem_check_root() - check if #size-cells, #address-cells provided - * in /reserved-memory matches the values supported by the current implementation, - * also check if ranges property has been provided - */ -static int __init __reserved_mem_check_root(unsigned long node) -{ - const __be32 *prop; - - prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - if (!prop || be32_to_cpup(prop) != dt_root_size_cells) - return -EINVAL; - - prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) - return -EINVAL; - - prop = of_get_flat_dt_prop(node, "ranges", NULL); - if (!prop) - return -EINVAL; - return 0; -} - -/* - * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory - */ -static int __init fdt_scan_reserved_mem(void) -{ - int node, child; - const void *fdt = initial_boot_params; - - node = fdt_path_offset(fdt, "/reserved-memory"); - if (node < 0) - return -ENODEV; - - if (__reserved_mem_check_root(node) != 0) { - pr_err("Reserved memory: unsupported node format, ignoring\n"); - return -EINVAL; - } - - fdt_for_each_subnode(child, fdt, node) { - const char *uname; - int err; - - if (!of_fdt_device_is_available(fdt, child)) - continue; - - uname = fdt_get_name(fdt, child, NULL); - - err = __reserved_mem_reserve_reg(child, uname); - if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) - fdt_reserved_mem_save_node(child, uname, 0, 0); - } - return 0; -} - /* * fdt_reserve_elfcorehdr() - reserves memory for elf core header * diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index f38397c7b582..485483524b7f 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -175,8 +175,9 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node * } #endif +int fdt_scan_reserved_mem(void); void fdt_init_reserved_mem(void); -void fdt_reserved_mem_save_node(unsigned long node, const char *uname, - phys_addr_t base, phys_addr_t size); + +bool of_fdt_device_is_available(const void *blob, unsigned long node); #endif /* _LINUX_OF_PRIVATE_H */ diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 7ec94cfcbddb..8236ecae2953 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) "OF: reserved mem: " fmt #include +#include #include #include #include @@ -58,8 +59,8 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, /* * fdt_reserved_mem_save_node() - save fdt node for second pass initialization */ -void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, - phys_addr_t base, phys_addr_t size) +static void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, + phys_addr_t base, phys_addr_t size) { struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; @@ -77,6 +78,126 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, return; } +static int __init early_init_dt_reserve_memory(phys_addr_t base, + phys_addr_t size, bool nomap) +{ + if (nomap) { + /* + * If the memory is already reserved (by another region), we + * should not allow it to be marked nomap, but don't worry + * if the region isn't memory as it won't be mapped. + */ + if (memblock_overlaps_region(&memblock.memory, base, size) && + memblock_is_region_reserved(base, size)) + return -EBUSY; + + return memblock_mark_nomap(base, size); + } + return memblock_reserve(base, size); +} + +/* + * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property + */ +static int __init __reserved_mem_reserve_reg(unsigned long node, + const char *uname) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + phys_addr_t base, size; + int len; + const __be32 *prop; + int first = 1; + bool nomap; + + prop = of_get_flat_dt_prop(node, "reg", &len); + if (!prop) + return -ENOENT; + + if (len && len % t_len != 0) { + pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", + uname); + return -EINVAL; + } + + nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; + + while (len >= t_len) { + base = dt_mem_next_cell(dt_root_addr_cells, &prop); + size = dt_mem_next_cell(dt_root_size_cells, &prop); + + if (size && + early_init_dt_reserve_memory(base, size, nomap) == 0) + pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", + uname, &base, (unsigned long)(size / SZ_1M)); + else + pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", + uname, &base, (unsigned long)(size / SZ_1M)); + + len -= t_len; + if (first) { + fdt_reserved_mem_save_node(node, uname, base, size); + first = 0; + } + } + return 0; +} + +/* + * __reserved_mem_check_root() - check if #size-cells, #address-cells provided + * in /reserved-memory matches the values supported by the current implementation, + * also check if ranges property has been provided + */ +static int __init __reserved_mem_check_root(unsigned long node) +{ + const __be32 *prop; + + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); + if (!prop || be32_to_cpup(prop) != dt_root_size_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, "#address-cells", NULL); + if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, "ranges", NULL); + if (!prop) + return -EINVAL; + return 0; +} + +/* + * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory + */ +int __init fdt_scan_reserved_mem(void) +{ + int node, child; + const void *fdt = initial_boot_params; + + node = fdt_path_offset(fdt, "/reserved-memory"); + if (node < 0) + return -ENODEV; + + if (__reserved_mem_check_root(node) != 0) { + pr_err("Reserved memory: unsupported node format, ignoring\n"); + return -EINVAL; + } + + fdt_for_each_subnode(child, fdt, node) { + const char *uname; + int err; + + if (!of_fdt_device_is_available(fdt, child)) + continue; + + uname = fdt_get_name(fdt, child, NULL); + + err = __reserved_mem_reserve_reg(child, uname); + if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) + fdt_reserved_mem_save_node(child, uname, 0, 0); + } + return 0; +} + /* * __reserved_mem_alloc_in_range() - allocate reserved memory described with * 'alloc-ranges'. Choose bottom-up/top-down depending on nearby existing From 54b9460b0a28c4c76a7b455ec1b3b61a13e97291 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:20 -0700 Subject: [PATCH 775/814] ACPI: HMAT: Remove register of memory node for generic target For generic targets, there's no reason to call register_memory_node_under_compute_node() with the access levels that are only visible to HMAT handling code. Only update the attributes and rename hmat_register_generic_target_initiators() to hmat_update_generic_target(). The original call path ends up triggering register_memory_node_under_compute_node(). Although the access level would be "3" and not impact any current node arrays, it introduces unwanted data into the numa node access_coordinate array. Fixes: a3a3e341f169 ("acpi: numa: Add setting of generic port system locality attributes") Cc: Rafael J. Wysocki Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-2-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/hmat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index d6b85f0f6082..a26e7793ec4e 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -770,12 +770,12 @@ static void __hmat_register_target_initiators(struct memory_target *target, } } -static void hmat_register_generic_target_initiators(struct memory_target *target) +static void hmat_update_generic_target(struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); - __hmat_register_target_initiators(target, p_nodes, - NODE_ACCESS_CLASS_GENPORT_SINK); + hmat_update_target_attrs(target, p_nodes, + NODE_ACCESS_CLASS_GENPORT_SINK); } static void hmat_register_target_initiators(struct memory_target *target) @@ -835,7 +835,7 @@ static void hmat_register_target(struct memory_target *target) */ mutex_lock(&target_lock); if (*(u16 *)target->gen_port_device_handle) { - hmat_register_generic_target_initiators(target); + hmat_update_generic_target(target); target->registered = true; } mutex_unlock(&target_lock); From 11270e526276ffad4c4237acb393da82a3287487 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:21 -0700 Subject: [PATCH 776/814] base/node / ACPI: Enumerate node access class for 'struct access_coordinate' Both generic node and HMAT handling code have been using magic numbers to indicate access classes for 'struct access_coordinate'. Introduce enums to enumerate the access0 and access1 classes shared by the two subsystems. Update the function parameters and callers as appropriate to utilize the new enum. Access0 is named to ACCESS_COORDINATE_LOCAL in order to indicate that the access class is for 'struct access_coordinate' between a target node and the nearest initiator node. Access1 is named to ACCESS_COORDINATE_CPU in order to indicate that the access class is for 'struct access_coordinate' between a target node and the nearest CPU node. Cc: Greg Kroah-Hartman Cc: Rafael J. Wysocki Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Acked-by: Greg Kroah-Hartman Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-3-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/hmat.c | 26 ++++++++++++++------------ drivers/base/node.c | 6 +++--- include/linux/node.h | 18 +++++++++++++++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index a26e7793ec4e..e0144cfbf1f3 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -59,9 +59,7 @@ struct target_cache { }; enum { - NODE_ACCESS_CLASS_0 = 0, - NODE_ACCESS_CLASS_1, - NODE_ACCESS_CLASS_GENPORT_SINK, + NODE_ACCESS_CLASS_GENPORT_SINK = ACCESS_COORDINATE_MAX, NODE_ACCESS_CLASS_MAX, }; @@ -374,11 +372,11 @@ static __init void hmat_update_target(unsigned int tgt_pxm, unsigned int init_px if (target && target->processor_pxm == init_pxm) { hmat_update_target_access(target, type, value, - NODE_ACCESS_CLASS_0); + ACCESS_COORDINATE_LOCAL); /* If the node has a CPU, update access 1 */ if (node_state(pxm_to_node(init_pxm), N_CPU)) hmat_update_target_access(target, type, value, - NODE_ACCESS_CLASS_1); + ACCESS_COORDINATE_CPU); } } @@ -709,7 +707,8 @@ static void hmat_update_target_attrs(struct memory_target *target, */ if (target->processor_pxm != PXM_INVAL) { cpu_nid = pxm_to_node(target->processor_pxm); - if (access == 0 || node_state(cpu_nid, N_CPU)) { + if (access == ACCESS_COORDINATE_LOCAL || + node_state(cpu_nid, N_CPU)) { set_bit(target->processor_pxm, p_nodes); return; } @@ -737,7 +736,8 @@ static void hmat_update_target_attrs(struct memory_target *target, list_for_each_entry(initiator, &initiators, node) { u32 value; - if (access == 1 && !initiator->has_cpu) { + if (access == ACCESS_COORDINATE_CPU && + !initiator->has_cpu) { clear_bit(initiator->processor_pxm, p_nodes); continue; } @@ -782,8 +782,10 @@ static void hmat_register_target_initiators(struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); - __hmat_register_target_initiators(target, p_nodes, 0); - __hmat_register_target_initiators(target, p_nodes, 1); + __hmat_register_target_initiators(target, p_nodes, + ACCESS_COORDINATE_LOCAL); + __hmat_register_target_initiators(target, p_nodes, + ACCESS_COORDINATE_CPU); } static void hmat_register_target_cache(struct memory_target *target) @@ -854,8 +856,8 @@ static void hmat_register_target(struct memory_target *target) if (!target->registered) { hmat_register_target_initiators(target); hmat_register_target_cache(target); - hmat_register_target_perf(target, NODE_ACCESS_CLASS_0); - hmat_register_target_perf(target, NODE_ACCESS_CLASS_1); + hmat_register_target_perf(target, ACCESS_COORDINATE_LOCAL); + hmat_register_target_perf(target, ACCESS_COORDINATE_CPU); target->registered = true; } mutex_unlock(&target_lock); @@ -927,7 +929,7 @@ static int hmat_calculate_adistance(struct notifier_block *self, return NOTIFY_OK; mutex_lock(&target_lock); - hmat_update_target_attrs(target, p_nodes, 1); + hmat_update_target_attrs(target, p_nodes, ACCESS_COORDINATE_CPU); mutex_unlock(&target_lock); perf = &target->coord[1]; diff --git a/drivers/base/node.c b/drivers/base/node.c index 1c05640461dd..a73b0c9a401a 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -126,7 +126,7 @@ static void node_access_release(struct device *dev) } static struct node_access_nodes *node_init_node_access(struct node *node, - unsigned int access) + enum access_coordinate_class access) { struct node_access_nodes *access_node; struct device *dev; @@ -191,7 +191,7 @@ static struct attribute *access_attrs[] = { * @access: The access class the for the given attributes */ void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, - unsigned int access) + enum access_coordinate_class access) { struct node_access_nodes *c; struct node *node; @@ -689,7 +689,7 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid) */ int register_memory_node_under_compute_node(unsigned int mem_nid, unsigned int cpu_nid, - unsigned int access) + enum access_coordinate_class access) { struct node *init_node, *targ_node; struct node_access_nodes *initiator, *target; diff --git a/include/linux/node.h b/include/linux/node.h index 25b66d705ee2..dfc004e4bee7 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -34,6 +34,18 @@ struct access_coordinate { unsigned int write_latency; }; +/* + * ACCESS_COORDINATE_LOCAL correlates to ACCESS CLASS 0 + * - access_coordinate between target node and nearest initiator node + * ACCESS_COORDINATE_CPU correlates to ACCESS CLASS 1 + * - access_coordinate between target node and nearest CPU node + */ +enum access_coordinate_class { + ACCESS_COORDINATE_LOCAL, + ACCESS_COORDINATE_CPU, + ACCESS_COORDINATE_MAX +}; + enum cache_indexing { NODE_CACHE_DIRECT_MAP, NODE_CACHE_INDEXED, @@ -66,7 +78,7 @@ struct node_cache_attrs { #ifdef CONFIG_HMEM_REPORTING void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs); void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, - unsigned access); + enum access_coordinate_class access); #else static inline void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs) @@ -75,7 +87,7 @@ static inline void node_add_cache(unsigned int nid, static inline void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, - unsigned access) + enum access_coordinate_class access) { } #endif @@ -137,7 +149,7 @@ extern void unregister_memory_block_under_nodes(struct memory_block *mem_blk); extern int register_memory_node_under_compute_node(unsigned int mem_nid, unsigned int cpu_nid, - unsigned access); + enum access_coordinate_class access); #else static inline void node_dev_init(void) { From 1745a7b364dfd339ab2696b7d51d7ed950ed2598 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:22 -0700 Subject: [PATCH 777/814] ACPI: HMAT: Introduce 2 levels of generic port access class In order to compute access0 and access1 classes for CXL memory, 2 levels of generic port information must be stored. Access0 will indicate the generic port access coordinates to the closest initiator and access1 will indicate the generic port access coordinates to the cloest CPU. Cc: Rafael J. Wysocki Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-4-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/hmat.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index e0144cfbf1f3..a1257888a6df 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -59,7 +59,8 @@ struct target_cache { }; enum { - NODE_ACCESS_CLASS_GENPORT_SINK = ACCESS_COORDINATE_MAX, + NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL = ACCESS_COORDINATE_MAX, + NODE_ACCESS_CLASS_GENPORT_SINK_CPU, NODE_ACCESS_CLASS_MAX, }; @@ -141,7 +142,7 @@ int acpi_get_genport_coordinates(u32 uid, if (!target) return -ENOENT; - *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK]; + *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL]; return 0; } @@ -695,7 +696,8 @@ static void hmat_update_target_attrs(struct memory_target *target, int i; /* Don't update for generic port if there's no device handle */ - if (access == NODE_ACCESS_CLASS_GENPORT_SINK && + if ((access == NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL || + access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) && !(*(u16 *)target->gen_port_device_handle)) return; @@ -736,7 +738,8 @@ static void hmat_update_target_attrs(struct memory_target *target, list_for_each_entry(initiator, &initiators, node) { u32 value; - if (access == ACCESS_COORDINATE_CPU && + if ((access == ACCESS_COORDINATE_CPU || + access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) && !initiator->has_cpu) { clear_bit(initiator->processor_pxm, p_nodes); continue; @@ -775,7 +778,9 @@ static void hmat_update_generic_target(struct memory_target *target) static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); hmat_update_target_attrs(target, p_nodes, - NODE_ACCESS_CLASS_GENPORT_SINK); + NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL); + hmat_update_target_attrs(target, p_nodes, + NODE_ACCESS_CLASS_GENPORT_SINK_CPU); } static void hmat_register_target_initiators(struct memory_target *target) From bd98cbbbf82a3086423865816e1b5ab4bb4b6c60 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:23 -0700 Subject: [PATCH 778/814] ACPI: HMAT / cxl: Add retrieval of generic port coordinates for both access classes Update acpi_get_genport_coordinates() to allow retrieval of both access classes of the 'struct access_coordinate' for a generic target. The update will allow CXL code to compute access coordinates for both access class. Cc: Rafael J. Wysocki Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-5-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/hmat.c | 8 ++++++-- drivers/cxl/acpi.c | 8 +++++--- drivers/cxl/core/port.c | 2 +- drivers/cxl/cxl.h | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index a1257888a6df..75e9aac43228 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -126,7 +126,8 @@ static struct memory_target *acpi_find_genport_target(u32 uid) /** * acpi_get_genport_coordinates - Retrieve the access coordinates for a generic port * @uid: ACPI unique id - * @coord: The access coordinates written back out for the generic port + * @coord: The access coordinates written back out for the generic port. + * Expect 2 levels array. * * Return: 0 on success. Errno on failure. * @@ -142,7 +143,10 @@ int acpi_get_genport_coordinates(u32 uid, if (!target) return -ENOENT; - *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL]; + coord[ACCESS_COORDINATE_LOCAL] = + target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL]; + coord[ACCESS_COORDINATE_CPU] = + target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_CPU]; return 0; } diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 1a3e6aafbdcc..af5cb818f84d 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -530,13 +530,15 @@ static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport) if (kstrtou32(acpi_device_uid(hb), 0, &uid)) return -EINVAL; - rc = acpi_get_genport_coordinates(uid, &dport->hb_coord); + rc = acpi_get_genport_coordinates(uid, dport->hb_coord); if (rc < 0) return rc; /* Adjust back to picoseconds from nanoseconds */ - dport->hb_coord.read_latency *= 1000; - dport->hb_coord.write_latency *= 1000; + for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { + dport->hb_coord[i].read_latency *= 1000; + dport->hb_coord[i].write_latency *= 1000; + } return 0; } diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e59d9d37aa65..612bf7e1e847 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -2152,7 +2152,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, } /* Augment with the generic port (host bridge) perf data */ - combine_coordinates(&c, &dport->hb_coord); + combine_coordinates(&c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL]); /* Get the calculated PCI paths bandwidth */ pdev = to_pci_dev(port->uport_dev->parent); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 003feebab79b..fe7448f2745e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -671,7 +671,7 @@ struct cxl_dport { struct cxl_port *port; struct cxl_regs regs; struct access_coordinate sw_coord; - struct access_coordinate hb_coord; + struct access_coordinate hb_coord[ACCESS_COORDINATE_MAX]; long link_latency; }; From 032f7b37adff6985e22516053698b77131c2ce96 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:24 -0700 Subject: [PATCH 779/814] cxl: Split out combine_coordinates() for common shared usage Refactor the common code of combining coordinates in order to reduce code. Create a new function cxl_cooordinates_combine() it combine two 'struct access_coordinate'. Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-6-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/cdat.c | 32 +++++++++++++++++++++++--------- drivers/cxl/core/port.c | 18 ++---------------- drivers/cxl/cxl.h | 4 ++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 08fd0baea7a0..c1ede0ef9185 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -185,15 +185,7 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port, xa_for_each(dsmas_xa, index, dent) { int qos_class; - dent->coord.read_latency = dent->coord.read_latency + - c.read_latency; - dent->coord.write_latency = dent->coord.write_latency + - c.write_latency; - dent->coord.read_bandwidth = min_t(int, c.read_bandwidth, - dent->coord.read_bandwidth); - dent->coord.write_bandwidth = min_t(int, c.write_bandwidth, - dent->coord.write_bandwidth); - + cxl_coordinates_combine(&dent->coord, &dent->coord, &c); dent->entries = 1; rc = cxl_root->ops->qos_class(cxl_root, &dent->coord, 1, &qos_class); @@ -484,4 +476,26 @@ void cxl_switch_parse_cdat(struct cxl_port *port) } EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, CXL); +/** + * cxl_coordinates_combine - Combine the two input coordinates + * + * @out: Output coordinate of c1 and c2 combined + * @c1: input coordinates + * @c2: input coordinates + */ +void cxl_coordinates_combine(struct access_coordinate *out, + struct access_coordinate *c1, + struct access_coordinate *c2) +{ + if (c1->write_bandwidth && c2->write_bandwidth) + out->write_bandwidth = min(c1->write_bandwidth, + c2->write_bandwidth); + out->write_latency = c1->write_latency + c2->write_latency; + + if (c1->read_bandwidth && c2->read_bandwidth) + out->read_bandwidth = min(c1->read_bandwidth, + c2->read_bandwidth); + out->read_latency = c1->read_latency + c2->read_latency; +} + MODULE_IMPORT_NS(CXL); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 612bf7e1e847..af9458b2678c 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -2096,20 +2096,6 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL); -static void combine_coordinates(struct access_coordinate *c1, - struct access_coordinate *c2) -{ - if (c2->write_bandwidth) - c1->write_bandwidth = min(c1->write_bandwidth, - c2->write_bandwidth); - c1->write_latency += c2->write_latency; - - if (c2->read_bandwidth) - c1->read_bandwidth = min(c1->read_bandwidth, - c2->read_bandwidth); - c1->read_latency += c2->read_latency; -} - /** * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports * of CXL path @@ -2143,7 +2129,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, * nothing to gather. */ while (iter && !is_cxl_root(to_cxl_port(iter->dev.parent))) { - combine_coordinates(&c, &dport->sw_coord); + cxl_coordinates_combine(&c, &c, &dport->sw_coord); c.write_latency += dport->link_latency; c.read_latency += dport->link_latency; @@ -2152,7 +2138,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, } /* Augment with the generic port (host bridge) perf data */ - combine_coordinates(&c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL]); + cxl_coordinates_combine(&c, &c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL]); /* Get the calculated PCI paths bandwidth */ pdev = to_pci_dev(port->uport_dev->parent); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index fe7448f2745e..fab2da4b1f04 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -882,6 +882,10 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, void cxl_memdev_update_perf(struct cxl_memdev *cxlmd); +void cxl_coordinates_combine(struct access_coordinate *out, + struct access_coordinate *c1, + struct access_coordinate *c2); + /* * Unit test builds overrides this to __weak, find the 'strong' version * of these symbols in tools/testing/cxl/. From 863027d40993f13155451bd898bfe4c4e9b7002f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:25 -0700 Subject: [PATCH 780/814] cxl: Split out host bridge access coordinates The difference between access class 0 and access class 1 for 'struct access_coordinate', if any, is that class 0 is for the distance from the target to the closest initiator and that class 1 is for the distance from the target to the closest CPU. For CXL memory, the nearest initiator may not necessarily be a CPU node. The performance path from the CXL endpoint to the host bridge should remain the same. However, the numbers extracted and stored from HMAT is the difference for the two access classes. Split out the performance numbers for the host bridge (generic target) from the calculation of the entire path in order to allow calculation of both access classes for a CXL region. Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-7-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/cdat.c | 28 ++++++++++++++++++++++------ drivers/cxl/core/port.c | 35 ++++++++++++++++++++++++++++++++--- drivers/cxl/cxl.h | 2 ++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index c1ede0ef9185..04dfda9d1f1b 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -162,15 +162,22 @@ static int cxl_cdat_endpoint_process(struct cxl_port *port, static int cxl_port_perf_data_calculate(struct cxl_port *port, struct xarray *dsmas_xa) { - struct access_coordinate c; + struct access_coordinate ep_c; + struct access_coordinate coord[ACCESS_COORDINATE_MAX]; struct dsmas_entry *dent; int valid_entries = 0; unsigned long index; int rc; - rc = cxl_endpoint_get_perf_coordinates(port, &c); + rc = cxl_endpoint_get_perf_coordinates(port, &ep_c); if (rc) { - dev_dbg(&port->dev, "Failed to retrieve perf coordinates.\n"); + dev_dbg(&port->dev, "Failed to retrieve ep perf coordinates.\n"); + return rc; + } + + rc = cxl_hb_get_perf_coordinates(port, coord); + if (rc) { + dev_dbg(&port->dev, "Failed to retrieve hb perf coordinates.\n"); return rc; } @@ -185,10 +192,19 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port, xa_for_each(dsmas_xa, index, dent) { int qos_class; - cxl_coordinates_combine(&dent->coord, &dent->coord, &c); + cxl_coordinates_combine(&dent->coord, &dent->coord, &ep_c); + /* + * Keeping the host bridge coordinates separate from the dsmas + * coordinates in order to allow calculation of access class + * 0 and 1 for region later. + */ + cxl_coordinates_combine(&coord[ACCESS_COORDINATE_LOCAL], + &coord[ACCESS_COORDINATE_LOCAL], + &dent->coord); dent->entries = 1; - rc = cxl_root->ops->qos_class(cxl_root, &dent->coord, 1, - &qos_class); + rc = cxl_root->ops->qos_class(cxl_root, + &coord[ACCESS_COORDINATE_LOCAL], + 1, &qos_class); if (rc != 1) continue; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index af9458b2678c..b2a2f6c34886 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -2096,6 +2096,38 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL); +/** + * cxl_hb_get_perf_coordinates - Retrieve performance numbers between initiator + * and host bridge + * + * @port: endpoint cxl_port + * @coord: output access coordinates + * + * Return: errno on failure, 0 on success. + */ +int cxl_hb_get_perf_coordinates(struct cxl_port *port, + struct access_coordinate *coord) +{ + struct cxl_port *iter = port; + struct cxl_dport *dport; + + if (!is_cxl_endpoint(port)) + return -EINVAL; + + dport = iter->parent_dport; + while (iter && !is_cxl_root(to_cxl_port(iter->dev.parent))) { + iter = to_cxl_port(iter->dev.parent); + dport = iter->parent_dport; + } + + coord[ACCESS_COORDINATE_LOCAL] = + dport->hb_coord[ACCESS_COORDINATE_LOCAL]; + coord[ACCESS_COORDINATE_CPU] = + dport->hb_coord[ACCESS_COORDINATE_CPU]; + + return 0; +} + /** * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports * of CXL path @@ -2137,9 +2169,6 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, dport = iter->parent_dport; } - /* Augment with the generic port (host bridge) perf data */ - cxl_coordinates_combine(&c, &c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL]); - /* Get the calculated PCI paths bandwidth */ pdev = to_pci_dev(port->uport_dev->parent); bw = pcie_bandwidth_available(pdev, NULL, NULL, NULL); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index fab2da4b1f04..de477eb7f5d5 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -879,6 +879,8 @@ void cxl_switch_parse_cdat(struct cxl_port *port); int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord); +int cxl_hb_get_perf_coordinates(struct cxl_port *port, + struct access_coordinate *coord); void cxl_memdev_update_perf(struct cxl_memdev *cxlmd); From 6ef83c4e19e9ce20a05127eec8a10911cf3516a7 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:26 -0700 Subject: [PATCH 781/814] cxl: Move QoS class to be calculated from the nearest CPU Retrieve the qos_class (QTG ID) using the access coordinates from the nearest CPU rather than the nearst initiator that may not be a CPU. This may be the more appropriate number that applications care about. For most cases, access0 and access1 have the same values. Link: https://lore.kernel.org/linux-cxl/20240112113023.00006c50@Huawei.com/ Suggested-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-8-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/cdat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 04dfda9d1f1b..02e97a90a43c 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -198,12 +198,12 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port, * coordinates in order to allow calculation of access class * 0 and 1 for region later. */ - cxl_coordinates_combine(&coord[ACCESS_COORDINATE_LOCAL], - &coord[ACCESS_COORDINATE_LOCAL], + cxl_coordinates_combine(&coord[ACCESS_COORDINATE_CPU], + &coord[ACCESS_COORDINATE_CPU], &dent->coord); dent->entries = 1; rc = cxl_root->ops->qos_class(cxl_root, - &coord[ACCESS_COORDINATE_LOCAL], + &coord[ACCESS_COORDINATE_CPU], 1, &qos_class); if (rc != 1) continue; From 3d8be8b398e3d315200d6c139f0166fe5f1bd576 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:27 -0700 Subject: [PATCH 782/814] cxl: Set cxlmd->endpoint before adding port device Move setting of cxlmd->endpoint to before calling add_device() on the port device. Otherwise when referencing cxlmd->endpoint in region discovery code that is triggered by the port driver probe function, the endpoint port pointer is not valid. Current code does not hit this issue yet since cxlmd->endpoint is not being referenced during region discovery. However follow on code that does performance calculations will. Tested-by: Wonjae Lee Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-9-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index b2a2f6c34886..9ab542e7af65 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -822,6 +822,7 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host, */ port->reg_map = cxlds->reg_map; port->reg_map.host = &port->dev; + cxlmd->endpoint = port; } else if (parent_dport) { rc = dev_set_name(dev, "port%d", port->id); if (rc) @@ -1374,7 +1375,6 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) get_device(host); get_device(&endpoint->dev); - cxlmd->endpoint = endpoint; cxlmd->depth = endpoint->depth; return devm_add_action_or_reset(dev, delete_endpoint, cxlmd); } From 3d9f4a197230d6f4d5f816bcae0e0497b0eec410 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:28 -0700 Subject: [PATCH 783/814] cxl/region: Calculate performance data for a region Calculate and store the performance data for a CXL region. Find the worst read and write latency for all the included ranges from each of the devices that attributes to the region and designate that as the latency data. Sum all the read and write bandwidth data for each of the device region and that is the total bandwidth for the region. The perf list is expected to be constructed before the endpoint decoders are registered and thus there should be no early reading of the entries from the region assemble action. The calling of the region qos calculate function is under the protection of cxl_dpa_rwsem and will ensure that all DPA associated work has completed. Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-10-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/cdat.c | 65 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/region.c | 2 ++ drivers/cxl/cxl.h | 4 +++ 3 files changed, 71 insertions(+) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 02e97a90a43c..40052666ebf1 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -9,6 +9,7 @@ #include "cxlmem.h" #include "core.h" #include "cxl.h" +#include "core.h" struct dsmas_entry { struct range dpa_range; @@ -515,3 +516,67 @@ void cxl_coordinates_combine(struct access_coordinate *out, } MODULE_IMPORT_NS(CXL); + +void cxl_region_perf_data_calculate(struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled) +{ + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + struct cxl_port *port = cxlmd->endpoint; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct access_coordinate hb_coord[ACCESS_COORDINATE_MAX]; + struct access_coordinate coord; + struct range dpa = { + .start = cxled->dpa_res->start, + .end = cxled->dpa_res->end, + }; + struct cxl_dpa_perf *perf; + int rc; + + switch (cxlr->mode) { + case CXL_DECODER_RAM: + perf = &mds->ram_perf; + break; + case CXL_DECODER_PMEM: + perf = &mds->pmem_perf; + break; + default: + return; + } + + lockdep_assert_held(&cxl_dpa_rwsem); + + if (!range_contains(&perf->dpa_range, &dpa)) + return; + + rc = cxl_hb_get_perf_coordinates(port, hb_coord); + if (rc) { + dev_dbg(&port->dev, "Failed to retrieve hb perf coordinates.\n"); + return; + } + + for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { + /* Pickup the host bridge coords */ + cxl_coordinates_combine(&coord, &hb_coord[i], &perf->coord); + + /* Get total bandwidth and the worst latency for the cxl region */ + cxlr->coord[i].read_latency = max_t(unsigned int, + cxlr->coord[i].read_latency, + coord.read_latency); + cxlr->coord[i].write_latency = max_t(unsigned int, + cxlr->coord[i].write_latency, + coord.write_latency); + cxlr->coord[i].read_bandwidth += coord.read_bandwidth; + cxlr->coord[i].write_bandwidth += coord.write_bandwidth; + + /* + * Convert latency to nanosec from picosec to be consistent + * with the resulting latency coordinates computed by the + * HMAT_REPORTING code. + */ + cxlr->coord[i].read_latency = + DIV_ROUND_UP(cxlr->coord[i].read_latency, 1000); + cxlr->coord[i].write_latency = + DIV_ROUND_UP(cxlr->coord[i].write_latency, 1000); + } +} diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 4c7fd2d5cccb..9a0d2d7621de 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1752,6 +1752,8 @@ static int cxl_region_attach(struct cxl_region *cxlr, return -EINVAL; } + cxl_region_perf_data_calculate(cxlr, cxled); + if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) { int i; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index de477eb7f5d5..95864ce7b394 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -517,6 +517,7 @@ struct cxl_region_params { * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge * @flags: Region state flags * @params: active + config params for the region + * @coord: QoS access coordinates for the region */ struct cxl_region { struct device dev; @@ -527,6 +528,7 @@ struct cxl_region { struct cxl_pmem_region *cxlr_pmem; unsigned long flags; struct cxl_region_params params; + struct access_coordinate coord[ACCESS_COORDINATE_MAX]; }; struct cxl_nvdimm_bridge { @@ -881,6 +883,8 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord); int cxl_hb_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord); +void cxl_region_perf_data_calculate(struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled); void cxl_memdev_update_perf(struct cxl_memdev *cxlmd); From c20eaf44113eac090b0d77fa2036143a836b9f56 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:29 -0700 Subject: [PATCH 784/814] cxl/region: Add sysfs attribute for locality attributes of CXL regions Add read/write latencies and bandwidth sysfs attributes for the enabled CXL region. The bandwidth is the aggregated bandwidth of all devices that contribute to the CXL region. The latency is the worst latency of the device amongst all the devices that contribute to the CXL region. Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-11-dave.jiang@intel.com Signed-off-by: Dan Williams --- Documentation/ABI/testing/sysfs-bus-cxl | 34 +++++++++ drivers/cxl/core/region.c | 94 +++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index fff2581b8033..3f5627a1210a 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -552,3 +552,37 @@ Description: attribute is only visible for devices supporting the capability. The retrieved errors are logged as kernel events when cxl_poison event tracing is enabled. + + +What: /sys/bus/cxl/devices/regionZ/accessY/read_bandwidth + /sys/bus/cxl/devices/regionZ/accessY/write_banwidth +Date: Jan, 2024 +KernelVersion: v6.9 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) The aggregated read or write bandwidth of the region. The + number is the accumulated read or write bandwidth of all CXL memory + devices that contributes to the region in MB/s. It is + identical data that should appear in + /sys/devices/system/node/nodeX/accessY/initiators/read_bandwidth or + /sys/devices/system/node/nodeX/accessY/initiators/write_bandwidth. + See Documentation/ABI/stable/sysfs-devices-node. access0 provides + the number to the closest initiator and access1 provides the + number to the closest CPU. + + +What: /sys/bus/cxl/devices/regionZ/accessY/read_latency + /sys/bus/cxl/devices/regionZ/accessY/write_latency +Date: Jan, 2024 +KernelVersion: v6.9 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) The read or write latency of the region. The number is + the worst read or write latency of all CXL memory devices that + contributes to the region in nanoseconds. It is identical data + that should appear in + /sys/devices/system/node/nodeX/accessY/initiators/read_latency or + /sys/devices/system/node/nodeX/accessY/initiators/write_latency. + See Documentation/ABI/stable/sysfs-devices-node. access0 provides + the number to the closest initiator and access1 provides the + number to the closest CPU. diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 9a0d2d7621de..d4d39536e6c7 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -30,6 +30,98 @@ static struct cxl_region *to_cxl_region(struct device *dev); +#define __ACCESS_ATTR_RO(_level, _name) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _name##_access##_level##_show, \ +} + +#define ACCESS_DEVICE_ATTR_RO(level, name) \ + struct device_attribute dev_attr_access##level##_##name = __ACCESS_ATTR_RO(level, name) + +#define ACCESS_ATTR_RO(level, attrib) \ +static ssize_t attrib##_access##level##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct cxl_region *cxlr = to_cxl_region(dev); \ + \ + if (cxlr->coord[level].attrib == 0) \ + return -ENOENT; \ + \ + return sysfs_emit(buf, "%u\n", cxlr->coord[level].attrib); \ +} \ +static ACCESS_DEVICE_ATTR_RO(level, attrib) + +ACCESS_ATTR_RO(0, read_bandwidth); +ACCESS_ATTR_RO(0, read_latency); +ACCESS_ATTR_RO(0, write_bandwidth); +ACCESS_ATTR_RO(0, write_latency); + +#define ACCESS_ATTR_DECLARE(level, attrib) \ + (&dev_attr_access##level##_##attrib.attr) + +static struct attribute *access0_coordinate_attrs[] = { + ACCESS_ATTR_DECLARE(0, read_bandwidth), + ACCESS_ATTR_DECLARE(0, write_bandwidth), + ACCESS_ATTR_DECLARE(0, read_latency), + ACCESS_ATTR_DECLARE(0, write_latency), + NULL +}; + +ACCESS_ATTR_RO(1, read_bandwidth); +ACCESS_ATTR_RO(1, read_latency); +ACCESS_ATTR_RO(1, write_bandwidth); +ACCESS_ATTR_RO(1, write_latency); + +static struct attribute *access1_coordinate_attrs[] = { + ACCESS_ATTR_DECLARE(1, read_bandwidth), + ACCESS_ATTR_DECLARE(1, write_bandwidth), + ACCESS_ATTR_DECLARE(1, read_latency), + ACCESS_ATTR_DECLARE(1, write_latency), + NULL +}; + +#define ACCESS_VISIBLE(level) \ +static umode_t cxl_region_access##level##_coordinate_visible( \ + struct kobject *kobj, struct attribute *a, int n) \ +{ \ + struct device *dev = kobj_to_dev(kobj); \ + struct cxl_region *cxlr = to_cxl_region(dev); \ + \ + if (a == &dev_attr_access##level##_read_latency.attr && \ + cxlr->coord[level].read_latency == 0) \ + return 0; \ + \ + if (a == &dev_attr_access##level##_write_latency.attr && \ + cxlr->coord[level].write_latency == 0) \ + return 0; \ + \ + if (a == &dev_attr_access##level##_read_bandwidth.attr && \ + cxlr->coord[level].read_bandwidth == 0) \ + return 0; \ + \ + if (a == &dev_attr_access##level##_write_bandwidth.attr && \ + cxlr->coord[level].write_bandwidth == 0) \ + return 0; \ + \ + return a->mode; \ +} + +ACCESS_VISIBLE(0); +ACCESS_VISIBLE(1); + +static const struct attribute_group cxl_region_access0_coordinate_group = { + .name = "access0", + .attrs = access0_coordinate_attrs, + .is_visible = cxl_region_access0_coordinate_visible, +}; + +static const struct attribute_group cxl_region_access1_coordinate_group = { + .name = "access1", + .attrs = access1_coordinate_attrs, + .is_visible = cxl_region_access1_coordinate_visible, +}; + static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2069,6 +2161,8 @@ static const struct attribute_group *region_groups[] = { &cxl_base_attribute_group, &cxl_region_group, &cxl_region_target_group, + &cxl_region_access0_coordinate_group, + &cxl_region_access1_coordinate_group, NULL, }; From 067353a46d8ccdac279ebab97c038c3658e97541 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:30 -0700 Subject: [PATCH 785/814] cxl/region: Add memory hotplug notifier for cxl region When the CXL region is formed, the driver computes the performance data for the region. However this data is not available at the node data collection that has been populated by the HMAT during kernel initialization. Add a memory hotplug notifier to update the access coordinates to the 'struct memory_target' context kept by the HMAT_REPORTING code. Add CXL_CALLBACK_PRI for a memory hotplug callback priority. Set the priority number to be called before HMAT_CALLBACK_PRI. The CXL update must happen before hmat_callback(). A new HMAT_REPORTING helper hmat_update_target_coordinates() is added in order to allow CXL to update the memory_target access coordinates. A new ext_updated member is added to the memory_target to indicate that the access coordinates within the memory_target has been updated by an external agent such as CXL. This prevents data being overwritten by the hmat_update_target_attrs() triggered by hmat_callback(). Cc: Andrew Morton Cc: Rafael J. Wysocki Reviewed-by: Huang, Ying Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-12-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/hmat.c | 34 ++++++++++++++++++++ drivers/cxl/core/cdat.c | 6 ++++ drivers/cxl/core/core.h | 3 ++ drivers/cxl/core/region.c | 68 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 3 ++ include/linux/acpi.h | 12 +++++++ include/linux/memory.h | 1 + 7 files changed, 127 insertions(+) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index 75e9aac43228..2c8ccc91ebe6 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -74,6 +74,7 @@ struct memory_target { struct node_cache_attrs cache_attrs; u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE]; bool registered; + bool ext_updated; /* externally updated */ }; struct memory_initiator { @@ -328,6 +329,35 @@ static void hmat_update_target_access(struct memory_target *target, } } +int hmat_update_target_coordinates(int nid, struct access_coordinate *coord, + enum access_coordinate_class access) +{ + struct memory_target *target; + int pxm; + + if (nid == NUMA_NO_NODE) + return -EINVAL; + + pxm = node_to_pxm(nid); + guard(mutex)(&target_lock); + target = find_mem_target(pxm); + if (!target) + return -ENODEV; + + hmat_update_target_access(target, ACPI_HMAT_READ_LATENCY, + coord->read_latency, access); + hmat_update_target_access(target, ACPI_HMAT_WRITE_LATENCY, + coord->write_latency, access); + hmat_update_target_access(target, ACPI_HMAT_READ_BANDWIDTH, + coord->read_bandwidth, access); + hmat_update_target_access(target, ACPI_HMAT_WRITE_BANDWIDTH, + coord->write_bandwidth, access); + target->ext_updated = true; + + return 0; +} +EXPORT_SYMBOL_GPL(hmat_update_target_coordinates); + static __init void hmat_add_locality(struct acpi_hmat_locality *hmat_loc) { struct memory_locality *loc; @@ -699,6 +729,10 @@ static void hmat_update_target_attrs(struct memory_target *target, u32 best = 0; int i; + /* Don't update if an external agent has changed the data. */ + if (target->ext_updated) + return; + /* Don't update for generic port if there's no device handle */ if ((access == NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL || access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) && diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 40052666ebf1..ee1bc8fa396b 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -580,3 +580,9 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr, DIV_ROUND_UP(cxlr->coord[i].write_latency, 1000); } } + +int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, + enum access_coordinate_class access) +{ + return hmat_update_target_coordinates(nid, &cxlr->coord[access], access); +} diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 3b64fb1b9ed0..e19800a7ce06 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -90,4 +90,7 @@ enum cxl_poison_trace_type { long cxl_pci_get_latency(struct pci_dev *pdev); +int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, + enum access_coordinate_class access); + #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index d4d39536e6c7..535492ec8529 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -116,12 +117,22 @@ static const struct attribute_group cxl_region_access0_coordinate_group = { .is_visible = cxl_region_access0_coordinate_visible, }; +static const struct attribute_group *get_cxl_region_access0_group(void) +{ + return &cxl_region_access0_coordinate_group; +} + static const struct attribute_group cxl_region_access1_coordinate_group = { .name = "access1", .attrs = access1_coordinate_attrs, .is_visible = cxl_region_access1_coordinate_visible, }; +static const struct attribute_group *get_cxl_region_access1_group(void) +{ + return &cxl_region_access1_coordinate_group; +} + static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2216,6 +2227,7 @@ static void unregister_region(void *_cxlr) struct cxl_region_params *p = &cxlr->params; int i; + unregister_memory_notifier(&cxlr->memory_notifier); device_del(&cxlr->dev); /* @@ -2260,6 +2272,58 @@ static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int i return cxlr; } +static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid) +{ + int cset = 0; + int rc; + + for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { + if (cxlr->coord[i].read_bandwidth) { + rc = cxl_update_hmat_access_coordinates(nid, cxlr, i); + if (rc == 0) + cset++; + } + } + + if (!cset) + return false; + + rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_access0_group()); + if (rc) + dev_dbg(&cxlr->dev, "Failed to update access0 group\n"); + + rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_access1_group()); + if (rc) + dev_dbg(&cxlr->dev, "Failed to update access1 group\n"); + + return true; +} + +static int cxl_region_perf_attrs_callback(struct notifier_block *nb, + unsigned long action, void *arg) +{ + struct cxl_region *cxlr = container_of(nb, struct cxl_region, + memory_notifier); + struct cxl_region_params *p = &cxlr->params; + struct cxl_endpoint_decoder *cxled = p->targets[0]; + struct cxl_decoder *cxld = &cxled->cxld; + struct memory_notify *mnb = arg; + int nid = mnb->status_change_nid; + int region_nid; + + if (nid == NUMA_NO_NODE || action != MEM_ONLINE) + return NOTIFY_DONE; + + region_nid = phys_to_target_node(cxld->hpa_range.start); + if (nid != region_nid) + return NOTIFY_DONE; + + if (!cxl_region_update_coordinates(cxlr, nid)) + return NOTIFY_DONE; + + return NOTIFY_OK; +} + /** * devm_cxl_add_region - Adds a region to a decoder * @cxlrd: root decoder @@ -2307,6 +2371,10 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, if (rc) goto err; + cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback; + cxlr->memory_notifier.priority = CXL_CALLBACK_PRI; + register_memory_notifier(&cxlr->memory_notifier); + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr); if (rc) return ERR_PTR(rc); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 95864ce7b394..534e25e2f0a4 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -518,6 +519,7 @@ struct cxl_region_params { * @flags: Region state flags * @params: active + config params for the region * @coord: QoS access coordinates for the region + * @memory_notifier: notifier for setting the access coordinates to node */ struct cxl_region { struct device dev; @@ -529,6 +531,7 @@ struct cxl_region { unsigned long flags; struct cxl_region_params params; struct access_coordinate coord[ACCESS_COORDINATE_MAX]; + struct notifier_block memory_notifier; }; struct cxl_nvdimm_bridge { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index b7165e52b3c6..c84c2f34b8ee 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1547,4 +1547,16 @@ static inline void acpi_use_parent_companion(struct device *dev) ACPI_COMPANION_SET(dev, ACPI_COMPANION(dev->parent)); } +#ifdef CONFIG_ACPI_HMAT +int hmat_update_target_coordinates(int nid, struct access_coordinate *coord, + enum access_coordinate_class access); +#else +static inline int hmat_update_target_coordinates(int nid, + struct access_coordinate *coord, + enum access_coordinate_class access) +{ + return -EOPNOTSUPP; +} +#endif + #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/memory.h b/include/linux/memory.h index f53cfdaaaa41..d8588256578a 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -114,6 +114,7 @@ struct mem_section; #define DEFAULT_CALLBACK_PRI 0 #define SLAB_CALLBACK_PRI 1 #define HMAT_CALLBACK_PRI 2 +#define CXL_CALLBACK_PRI 5 #define MM_COMPUTE_BATCH_PRI 10 #define CPUSET_CALLBACK_PRI 10 #define MEMTIER_HOTPLUG_PRI 100 From debdce20c4f28b7e5aa48512e7abf270a00e9051 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 Mar 2024 14:59:31 -0700 Subject: [PATCH 786/814] cxl/region: Deal with numa nodes not enumerated by SRAT For the numa nodes that are not created by SRAT, no memory_target is allocated and is not managed by the HMAT_REPORTING code. Therefore hmat_callback() memory hotplug notifier will exit early on those NUMA nodes. The CXL memory hotplug notifier will need to call node_set_perf_attrs() directly in order to setup the access sysfs attributes. In acpi_numa_init(), the last proximity domain (pxm) id created by SRAT is stored. Add a helper function acpi_node_backed_by_real_pxm() in order to check if a NUMA node id is defined by SRAT or created by CFMWS. node_set_perf_attrs() symbol is exported to allow update of perf attribs for a node. The sysfs path of /sys/devices/system/node/nodeX/access0/initiators/* is created by node_set_perf_attrs() for the various attributes where nodeX is matched to the NUMA node of the CXL region. Cc: Rafael J. Wysocki Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Tested-by: Jonathan Cameron Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/20240308220055.2172956-13-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/acpi/numa/srat.c | 11 +++++++++++ drivers/base/node.c | 1 + drivers/cxl/core/cdat.c | 5 +++++ drivers/cxl/core/core.h | 1 + drivers/cxl/core/region.c | 7 ++++++- include/linux/acpi.h | 9 +++++++++ 6 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 0214518fc582..e45e64993c50 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -29,6 +29,8 @@ static int node_to_pxm_map[MAX_NUMNODES] unsigned char acpi_srat_revision __initdata; static int acpi_numa __initdata; +static int last_real_pxm; + void __init disable_srat(void) { acpi_numa = -1; @@ -536,6 +538,7 @@ int __init acpi_numa_init(void) if (node_to_pxm_map[i] > fake_pxm) fake_pxm = node_to_pxm_map[i]; } + last_real_pxm = fake_pxm; fake_pxm++; acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws, &fake_pxm); @@ -547,6 +550,14 @@ int __init acpi_numa_init(void) return 0; } +bool acpi_node_backed_by_real_pxm(int nid) +{ + int pxm = node_to_pxm(nid); + + return pxm <= last_real_pxm; +} +EXPORT_SYMBOL_GPL(acpi_node_backed_by_real_pxm); + static int acpi_get_pxm(acpi_handle h) { unsigned long long pxm; diff --git a/drivers/base/node.c b/drivers/base/node.c index a73b0c9a401a..eb72580288e6 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -215,6 +215,7 @@ void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, } } } +EXPORT_SYMBOL_GPL(node_set_perf_attrs); /** * struct node_cache_info - Internal tracking for memory node caches diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index ee1bc8fa396b..10d4f1d7dad1 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -586,3 +586,8 @@ int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, { return hmat_update_target_coordinates(nid, &cxlr->coord[access], access); } + +bool cxl_need_node_perf_attrs_update(int nid) +{ + return !acpi_node_backed_by_real_pxm(nid); +} diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index e19800a7ce06..bc5a95665aa0 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -92,5 +92,6 @@ long cxl_pci_get_latency(struct pci_dev *pdev); int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, enum access_coordinate_class access); +bool cxl_need_node_perf_attrs_update(int nid); #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 535492ec8529..5c186e0a39b9 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2279,7 +2279,12 @@ static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid) for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { if (cxlr->coord[i].read_bandwidth) { - rc = cxl_update_hmat_access_coordinates(nid, cxlr, i); + rc = 0; + if (cxl_need_node_perf_attrs_update(nid)) + node_set_perf_attrs(nid, &cxlr->coord[i], i); + else + rc = cxl_update_hmat_access_coordinates(nid, cxlr, i); + if (rc == 0) cset++; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c84c2f34b8ee..2a7c4b90d589 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1559,4 +1559,13 @@ static inline int hmat_update_target_coordinates(int nid, } #endif +#ifdef CONFIG_ACPI_NUMA +bool acpi_node_backed_by_real_pxm(int nid); +#else +static inline bool acpi_node_backed_by_real_pxm(int nid) +{ + return false; +} +#endif + #endif /*_LINUX_ACPI_H*/ From 6a8dbd71a70620c42d4fa82509204ba18231f28d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 13 Mar 2024 09:49:37 +0800 Subject: [PATCH 787/814] Revert "crypto: remove CONFIG_CRYPTO_STATS" This reverts commit 2beb81fbf0c01a62515a1bcef326168494ee2bd0. While removing CONFIG_CRYPTO_STATS is a worthy goal, this also removed unrelated infrastructure such as crypto_comp_alg_common. Signed-off-by: Herbert Xu --- arch/s390/configs/debug_defconfig | 1 + arch/s390/configs/defconfig | 1 + crypto/Kconfig | 20 +++ crypto/Makefile | 2 + crypto/acompress.c | 47 ++++- crypto/aead.c | 84 ++++++++- crypto/ahash.c | 65 ++++++- crypto/akcipher.c | 31 ++++ crypto/compress.h | 5 + crypto/{crypto_user.c => crypto_user_base.c} | 10 +- crypto/crypto_user_stat.c | 176 +++++++++++++++++++ crypto/hash.h | 30 ++++ crypto/kpp.c | 30 ++++ crypto/lskcipher.c | 73 +++++++- crypto/rng.c | 44 ++++- crypto/scompress.c | 8 +- crypto/shash.c | 75 +++++++- crypto/sig.c | 13 ++ crypto/skcipher.c | 86 ++++++++- crypto/skcipher.h | 10 ++ include/crypto/acompress.h | 90 +++++++++- include/crypto/aead.h | 21 +++ include/crypto/akcipher.h | 78 +++++++- include/crypto/algapi.h | 3 + include/crypto/hash.h | 22 +++ include/crypto/internal/acompress.h | 7 +- include/crypto/internal/cryptouser.h | 16 ++ include/crypto/internal/scompress.h | 8 +- include/crypto/kpp.h | 58 +++++- include/crypto/rng.h | 51 +++++- include/crypto/skcipher.h | 25 +++ include/uapi/linux/cryptouser.h | 28 ++- 32 files changed, 1140 insertions(+), 78 deletions(-) rename crypto/{crypto_user.c => crypto_user_base.c} (98%) create mode 100644 crypto/crypto_user_stat.c create mode 100644 include/crypto/internal/cryptouser.h diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 063f0c11087d..cae2dd34fbb4 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -766,6 +766,7 @@ CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_STATS=y CONFIG_CRYPTO_CRC32_S390=y CONFIG_CRYPTO_SHA512_S390=m CONFIG_CRYPTO_SHA1_S390=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index ab608ce768b7..42b988873e54 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -752,6 +752,7 @@ CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_STATS=y CONFIG_CRYPTO_CRC32_S390=y CONFIG_CRYPTO_SHA512_S390=m CONFIG_CRYPTO_SHA1_S390=m diff --git a/crypto/Kconfig b/crypto/Kconfig index f937142aa94d..44661c2e30ca 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1456,6 +1456,26 @@ config CRYPTO_USER_API_ENABLE_OBSOLETE already been phased out from internal use by the kernel, and are only useful for userspace clients that still rely on them. +config CRYPTO_STATS + bool "Crypto usage statistics" + depends on CRYPTO_USER + help + Enable the gathering of crypto stats. + + Enabling this option reduces the performance of the crypto API. It + should only be enabled when there is actually a use case for it. + + This collects data sizes, numbers of requests, and numbers + of errors processed by: + - AEAD ciphers (encrypt, decrypt) + - asymmetric key ciphers (encrypt, decrypt, verify, sign) + - symmetric key ciphers (encrypt, decrypt) + - compression algorithms (compress, decompress) + - hash algorithms (hash) + - key-agreement protocol primitives (setsecret, generate + public key, compute shared secret) + - RNG (generate, seed) + endmenu config CRYPTO_HASH_INFO diff --git a/crypto/Makefile b/crypto/Makefile index de9a3312a2c8..408f0a1f9ab9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -69,6 +69,8 @@ cryptomgr-y := algboss.o testmgr.o obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o obj-$(CONFIG_CRYPTO_USER) += crypto_user.o +crypto_user-y := crypto_user_base.o +crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o obj-$(CONFIG_CRYPTO_CMAC) += cmac.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o obj-$(CONFIG_CRYPTO_VMAC) += vmac.o diff --git a/crypto/acompress.c b/crypto/acompress.c index 484a865b23cd..1c682810a484 100644 --- a/crypto/acompress.c +++ b/crypto/acompress.c @@ -25,7 +25,7 @@ static const struct crypto_type crypto_acomp_type; static inline struct acomp_alg *__crypto_acomp_alg(struct crypto_alg *alg) { - return container_of(alg, struct acomp_alg, base); + return container_of(alg, struct acomp_alg, calg.base); } static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm) @@ -93,6 +93,32 @@ static unsigned int crypto_acomp_extsize(struct crypto_alg *alg) return extsize; } +static inline int __crypto_acomp_report_stat(struct sk_buff *skb, + struct crypto_alg *alg) +{ + struct comp_alg_common *calg = __crypto_comp_alg_common(alg); + struct crypto_istat_compress *istat = comp_get_stat(calg); + struct crypto_stat_compress racomp; + + memset(&racomp, 0, sizeof(racomp)); + + strscpy(racomp.type, "acomp", sizeof(racomp.type)); + racomp.stat_compress_cnt = atomic64_read(&istat->compress_cnt); + racomp.stat_compress_tlen = atomic64_read(&istat->compress_tlen); + racomp.stat_decompress_cnt = atomic64_read(&istat->decompress_cnt); + racomp.stat_decompress_tlen = atomic64_read(&istat->decompress_tlen); + racomp.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp); +} + +#ifdef CONFIG_CRYPTO_STATS +int crypto_acomp_report_stat(struct sk_buff *skb, struct crypto_alg *alg) +{ + return __crypto_acomp_report_stat(skb, alg); +} +#endif + static const struct crypto_type crypto_acomp_type = { .extsize = crypto_acomp_extsize, .init_tfm = crypto_acomp_init_tfm, @@ -101,6 +127,9 @@ static const struct crypto_type crypto_acomp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_acomp_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_acomp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_ACOMPRESS_MASK, @@ -153,12 +182,24 @@ void acomp_request_free(struct acomp_req *req) } EXPORT_SYMBOL_GPL(acomp_request_free); -int crypto_register_acomp(struct acomp_alg *alg) +void comp_prepare_alg(struct comp_alg_common *alg) { + struct crypto_istat_compress *istat = comp_get_stat(alg); struct crypto_alg *base = &alg->base; - base->cra_type = &crypto_acomp_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); +} + +int crypto_register_acomp(struct acomp_alg *alg) +{ + struct crypto_alg *base = &alg->calg.base; + + comp_prepare_alg(&alg->calg); + + base->cra_type = &crypto_acomp_type; base->cra_flags |= CRYPTO_ALG_TYPE_ACOMPRESS; return crypto_register_alg(base); diff --git a/crypto/aead.c b/crypto/aead.c index 0e75a69189df..54906633566a 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -20,6 +20,15 @@ #include "internal.h" +static inline struct crypto_istat_aead *aead_get_stat(struct aead_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { @@ -81,28 +90,62 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) } EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); +static inline int crypto_aead_errstat(struct crypto_istat_aead *istat, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&istat->err_cnt); + + return err; +} + int crypto_aead_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct aead_alg *alg = crypto_aead_alg(aead); + struct crypto_istat_aead *istat; + int ret; + + istat = aead_get_stat(alg); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + atomic64_inc(&istat->encrypt_cnt); + atomic64_add(req->cryptlen, &istat->encrypt_tlen); + } if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; + ret = -ENOKEY; + else + ret = alg->encrypt(req); - return crypto_aead_alg(aead)->encrypt(req); + return crypto_aead_errstat(istat, ret); } EXPORT_SYMBOL_GPL(crypto_aead_encrypt); int crypto_aead_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct aead_alg *alg = crypto_aead_alg(aead); + struct crypto_istat_aead *istat; + int ret; + + istat = aead_get_stat(alg); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + atomic64_inc(&istat->encrypt_cnt); + atomic64_add(req->cryptlen, &istat->encrypt_tlen); + } if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; + ret = -ENOKEY; + else if (req->cryptlen < crypto_aead_authsize(aead)) + ret = -EINVAL; + else + ret = alg->decrypt(req); - if (req->cryptlen < crypto_aead_authsize(aead)) - return -EINVAL; - - return crypto_aead_alg(aead)->decrypt(req); + return crypto_aead_errstat(istat, ret); } EXPORT_SYMBOL_GPL(crypto_aead_decrypt); @@ -172,6 +215,26 @@ static void crypto_aead_free_instance(struct crypto_instance *inst) aead->free(aead); } +static int __maybe_unused crypto_aead_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct aead_alg *aead = container_of(alg, struct aead_alg, base); + struct crypto_istat_aead *istat = aead_get_stat(aead); + struct crypto_stat_aead raead; + + memset(&raead, 0, sizeof(raead)); + + strscpy(raead.type, "aead", sizeof(raead.type)); + + raead.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); + raead.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); + raead.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); + raead.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); + raead.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead); +} + static const struct crypto_type crypto_aead_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_aead_init_tfm, @@ -181,6 +244,9 @@ static const struct crypto_type crypto_aead_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_aead_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_aead_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -211,6 +277,7 @@ EXPORT_SYMBOL_GPL(crypto_has_aead); static int aead_prepare_alg(struct aead_alg *alg) { + struct crypto_istat_aead *istat = aead_get_stat(alg); struct crypto_alg *base = &alg->base; if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) > @@ -224,6 +291,9 @@ static int aead_prepare_alg(struct aead_alg *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); + return 0; } diff --git a/crypto/ahash.c b/crypto/ahash.c index bcd9de009a91..0ac83f7f701d 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -27,6 +27,22 @@ #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e +static inline struct crypto_istat_hash *ahash_get_stat(struct ahash_alg *alg) +{ + return hash_get_stat(&alg->halg); +} + +static inline int crypto_ahash_errstat(struct ahash_alg *alg, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&ahash_get_stat(alg)->err_cnt); + + return err; +} + /* * For an ahash tfm that is using an shash algorithm (instead of an ahash * algorithm), this returns the underlying shash tfm. @@ -328,47 +344,75 @@ static void ahash_restore_req(struct ahash_request *req, int err) int crypto_ahash_update(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ahash_alg *alg; if (likely(tfm->using_shash)) return shash_ahash_update(req, ahash_request_ctx(req)); - return crypto_ahash_alg(tfm)->update(req); + alg = crypto_ahash_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_add(req->nbytes, &ahash_get_stat(alg)->hash_tlen); + return crypto_ahash_errstat(alg, alg->update(req)); } EXPORT_SYMBOL_GPL(crypto_ahash_update); int crypto_ahash_final(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ahash_alg *alg; if (likely(tfm->using_shash)) return crypto_shash_final(ahash_request_ctx(req), req->result); - return crypto_ahash_alg(tfm)->final(req); + alg = crypto_ahash_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&ahash_get_stat(alg)->hash_cnt); + return crypto_ahash_errstat(alg, alg->final(req)); } EXPORT_SYMBOL_GPL(crypto_ahash_final); int crypto_ahash_finup(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ahash_alg *alg; if (likely(tfm->using_shash)) return shash_ahash_finup(req, ahash_request_ctx(req)); - return crypto_ahash_alg(tfm)->finup(req); + alg = crypto_ahash_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = ahash_get_stat(alg); + + atomic64_inc(&istat->hash_cnt); + atomic64_add(req->nbytes, &istat->hash_tlen); + } + return crypto_ahash_errstat(alg, alg->finup(req)); } EXPORT_SYMBOL_GPL(crypto_ahash_finup); int crypto_ahash_digest(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ahash_alg *alg; + int err; if (likely(tfm->using_shash)) return shash_ahash_digest(req, prepare_shash_desc(req, tfm)); - if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; + alg = crypto_ahash_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = ahash_get_stat(alg); - return crypto_ahash_alg(tfm)->digest(req); + atomic64_inc(&istat->hash_cnt); + atomic64_add(req->nbytes, &istat->hash_tlen); + } + + if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) + err = -ENOKEY; + else + err = alg->digest(req); + + return crypto_ahash_errstat(alg, err); } EXPORT_SYMBOL_GPL(crypto_ahash_digest); @@ -527,6 +571,12 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) __crypto_hash_alg_common(alg)->digestsize); } +static int __maybe_unused crypto_ahash_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + return crypto_hash_report_stat(skb, alg, "ahash"); +} + static const struct crypto_type crypto_ahash_type = { .extsize = crypto_ahash_extsize, .init_tfm = crypto_ahash_init_tfm, @@ -536,6 +586,9 @@ static const struct crypto_type crypto_ahash_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_ahash_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_ahash_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, diff --git a/crypto/akcipher.c b/crypto/akcipher.c index e0ff5f4dda6d..52813f0b19e4 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -70,6 +70,30 @@ static void crypto_akcipher_free_instance(struct crypto_instance *inst) akcipher->free(akcipher); } +static int __maybe_unused crypto_akcipher_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct akcipher_alg *akcipher = __crypto_akcipher_alg(alg); + struct crypto_istat_akcipher *istat; + struct crypto_stat_akcipher rakcipher; + + istat = akcipher_get_stat(akcipher); + + memset(&rakcipher, 0, sizeof(rakcipher)); + + strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); + rakcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); + rakcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); + rakcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); + rakcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); + rakcipher.stat_sign_cnt = atomic64_read(&istat->sign_cnt); + rakcipher.stat_verify_cnt = atomic64_read(&istat->verify_cnt); + rakcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, + sizeof(rakcipher), &rakcipher); +} + static const struct crypto_type crypto_akcipher_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_akcipher_init_tfm, @@ -79,6 +103,9 @@ static const struct crypto_type crypto_akcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_akcipher_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_akcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, @@ -104,11 +131,15 @@ EXPORT_SYMBOL_GPL(crypto_alloc_akcipher); static void akcipher_prepare_alg(struct akcipher_alg *alg) { + struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); struct crypto_alg *base = &alg->base; base->cra_type = &crypto_akcipher_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AKCIPHER; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); } static int akcipher_default_op(struct akcipher_request *req) diff --git a/crypto/compress.h b/crypto/compress.h index 23ea43810810..19f65516d699 100644 --- a/crypto/compress.h +++ b/crypto/compress.h @@ -12,10 +12,15 @@ #include "internal.h" struct acomp_req; +struct comp_alg_common; struct sk_buff; int crypto_init_scomp_ops_async(struct crypto_tfm *tfm); struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req); void crypto_acomp_scomp_free_ctx(struct acomp_req *req); +int crypto_acomp_report_stat(struct sk_buff *skb, struct crypto_alg *alg); + +void comp_prepare_alg(struct comp_alg_common *alg); + #endif /* _LOCAL_CRYPTO_COMPRESS_H */ diff --git a/crypto/crypto_user.c b/crypto/crypto_user_base.c similarity index 98% rename from crypto/crypto_user.c rename to crypto/crypto_user_base.c index 6c571834e86a..3fa20f12989f 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user_base.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "internal.h" @@ -32,7 +33,7 @@ struct crypto_dump_info { u16 nlmsg_flags; }; -static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) +struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) { struct crypto_alg *q, *alg = NULL; @@ -386,13 +387,6 @@ static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh, return crypto_del_default_rng(); } -static int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, - struct nlattr **attrs) -{ - /* No longer supported */ - return -ENOTSUPP; -} - #define MSGSIZE(type) sizeof(struct type) static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = { diff --git a/crypto/crypto_user_stat.c b/crypto/crypto_user_stat.c new file mode 100644 index 000000000000..d4f3d39b5137 --- /dev/null +++ b/crypto/crypto_user_stat.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Crypto user configuration API. + * + * Copyright (C) 2017-2018 Corentin Labbe + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define null_terminated(x) (strnlen(x, sizeof(x)) < sizeof(x)) + +struct crypto_dump_info { + struct sk_buff *in_skb; + struct sk_buff *out_skb; + u32 nlmsg_seq; + u16 nlmsg_flags; +}; + +static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat_cipher rcipher; + + memset(&rcipher, 0, sizeof(rcipher)); + + strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); + + return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); +} + +static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat_compress rcomp; + + memset(&rcomp, 0, sizeof(rcomp)); + + strscpy(rcomp.type, "compression", sizeof(rcomp.type)); + + return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp); +} + +static int crypto_reportstat_one(struct crypto_alg *alg, + struct crypto_user_alg *ualg, + struct sk_buff *skb) +{ + memset(ualg, 0, sizeof(*ualg)); + + strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name)); + strscpy(ualg->cru_driver_name, alg->cra_driver_name, + sizeof(ualg->cru_driver_name)); + strscpy(ualg->cru_module_name, module_name(alg->cra_module), + sizeof(ualg->cru_module_name)); + + ualg->cru_type = 0; + ualg->cru_mask = 0; + ualg->cru_flags = alg->cra_flags; + ualg->cru_refcnt = refcount_read(&alg->cra_refcnt); + + if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority)) + goto nla_put_failure; + if (alg->cra_flags & CRYPTO_ALG_LARVAL) { + struct crypto_stat_larval rl; + + memset(&rl, 0, sizeof(rl)); + strscpy(rl.type, "larval", sizeof(rl.type)); + if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl)) + goto nla_put_failure; + goto out; + } + + if (alg->cra_type && alg->cra_type->report_stat) { + if (alg->cra_type->report_stat(skb, alg)) + goto nla_put_failure; + goto out; + } + + switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { + case CRYPTO_ALG_TYPE_CIPHER: + if (crypto_report_cipher(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_COMPRESS: + if (crypto_report_comp(skb, alg)) + goto nla_put_failure; + break; + default: + pr_err("ERROR: Unhandled alg %d in %s\n", + alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL), + __func__); + } + +out: + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_reportstat_alg(struct crypto_alg *alg, + struct crypto_dump_info *info) +{ + struct sk_buff *in_skb = info->in_skb; + struct sk_buff *skb = info->out_skb; + struct nlmsghdr *nlh; + struct crypto_user_alg *ualg; + int err = 0; + + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq, + CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags); + if (!nlh) { + err = -EMSGSIZE; + goto out; + } + + ualg = nlmsg_data(nlh); + + err = crypto_reportstat_one(alg, ualg, skb); + if (err) { + nlmsg_cancel(skb, nlh); + goto out; + } + + nlmsg_end(skb, nlh); + +out: + return err; +} + +int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(in_skb->sk); + struct crypto_user_alg *p = nlmsg_data(in_nlh); + struct crypto_alg *alg; + struct sk_buff *skb; + struct crypto_dump_info info; + int err; + + if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) + return -EINVAL; + + alg = crypto_alg_match(p, 0); + if (!alg) + return -ENOENT; + + err = -ENOMEM; + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + goto drop_alg; + + info.in_skb = in_skb; + info.out_skb = skb; + info.nlmsg_seq = in_nlh->nlmsg_seq; + info.nlmsg_flags = 0; + + err = crypto_reportstat_alg(alg, &info); + +drop_alg: + crypto_mod_put(alg); + + if (err) { + kfree_skb(skb); + return err; + } + + return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid); +} + +MODULE_LICENSE("GPL"); diff --git a/crypto/hash.h b/crypto/hash.h index cf9aee07f77d..93f6ba0df263 100644 --- a/crypto/hash.h +++ b/crypto/hash.h @@ -8,9 +8,39 @@ #define _LOCAL_CRYPTO_HASH_H #include +#include #include "internal.h" +static inline struct crypto_istat_hash *hash_get_stat( + struct hash_alg_common *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + +static inline int crypto_hash_report_stat(struct sk_buff *skb, + struct crypto_alg *alg, + const char *type) +{ + struct hash_alg_common *halg = __crypto_hash_alg_common(alg); + struct crypto_istat_hash *istat = hash_get_stat(halg); + struct crypto_stat_hash rhash; + + memset(&rhash, 0, sizeof(rhash)); + + strscpy(rhash.type, type, sizeof(rhash.type)); + + rhash.stat_hash_cnt = atomic64_read(&istat->hash_cnt); + rhash.stat_hash_tlen = atomic64_read(&istat->hash_tlen); + rhash.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash); +} + extern const struct crypto_type crypto_shash_type; int hash_prepare_alg(struct hash_alg_common *alg); diff --git a/crypto/kpp.c b/crypto/kpp.c index ecc63a1a948d..33d44e59387f 100644 --- a/crypto/kpp.c +++ b/crypto/kpp.c @@ -66,6 +66,29 @@ static void crypto_kpp_free_instance(struct crypto_instance *inst) kpp->free(kpp); } +static int __maybe_unused crypto_kpp_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct kpp_alg *kpp = __crypto_kpp_alg(alg); + struct crypto_istat_kpp *istat; + struct crypto_stat_kpp rkpp; + + istat = kpp_get_stat(kpp); + + memset(&rkpp, 0, sizeof(rkpp)); + + strscpy(rkpp.type, "kpp", sizeof(rkpp.type)); + + rkpp.stat_setsecret_cnt = atomic64_read(&istat->setsecret_cnt); + rkpp.stat_generate_public_key_cnt = + atomic64_read(&istat->generate_public_key_cnt); + rkpp.stat_compute_shared_secret_cnt = + atomic64_read(&istat->compute_shared_secret_cnt); + rkpp.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp); +} + static const struct crypto_type crypto_kpp_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_kpp_init_tfm, @@ -75,6 +98,9 @@ static const struct crypto_type crypto_kpp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_kpp_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_kpp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -105,11 +131,15 @@ EXPORT_SYMBOL_GPL(crypto_has_kpp); static void kpp_prepare_alg(struct kpp_alg *alg) { + struct crypto_istat_kpp *istat = kpp_get_stat(alg); struct crypto_alg *base = &alg->base; base->cra_type = &crypto_kpp_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_KPP; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); } int crypto_register_kpp(struct kpp_alg *alg) diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index 0a800292ca4e..0b6dd8aa21f2 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -29,6 +29,25 @@ static inline struct lskcipher_alg *__crypto_lskcipher_alg( return container_of(alg, struct lskcipher_alg, co.base); } +static inline struct crypto_istat_cipher *lskcipher_get_stat( + struct lskcipher_alg *alg) +{ + return skcipher_get_stat_common(&alg->co); +} + +static inline int crypto_lskcipher_errstat(struct lskcipher_alg *alg, int err) +{ + struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); + + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err) + atomic64_inc(&istat->err_cnt); + + return err; +} + static int lskcipher_setkey_unaligned(struct crypto_lskcipher *tfm, const u8 *key, unsigned int keylen) { @@ -128,13 +147,20 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, u32 flags)) { unsigned long alignmask = crypto_lskcipher_alignmask(tfm); + struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); + int ret; if (((unsigned long)src | (unsigned long)dst | (unsigned long)iv) & - alignmask) - return crypto_lskcipher_crypt_unaligned(tfm, src, dst, len, iv, - crypt); + alignmask) { + ret = crypto_lskcipher_crypt_unaligned(tfm, src, dst, len, iv, + crypt); + goto out; + } - return crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); + ret = crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); + +out: + return crypto_lskcipher_errstat(alg, ret); } int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, @@ -142,6 +168,13 @@ int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, { struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); + + atomic64_inc(&istat->encrypt_cnt); + atomic64_add(len, &istat->encrypt_tlen); + } + return crypto_lskcipher_crypt(tfm, src, dst, len, iv, alg->encrypt); } EXPORT_SYMBOL_GPL(crypto_lskcipher_encrypt); @@ -151,6 +184,13 @@ int crypto_lskcipher_decrypt(struct crypto_lskcipher *tfm, const u8 *src, { struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_cipher *istat = lskcipher_get_stat(alg); + + atomic64_inc(&istat->decrypt_cnt); + atomic64_add(len, &istat->decrypt_tlen); + } + return crypto_lskcipher_crypt(tfm, src, dst, len, iv, alg->decrypt); } EXPORT_SYMBOL_GPL(crypto_lskcipher_decrypt); @@ -282,6 +322,28 @@ static int __maybe_unused crypto_lskcipher_report( sizeof(rblkcipher), &rblkcipher); } +static int __maybe_unused crypto_lskcipher_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct lskcipher_alg *skcipher = __crypto_lskcipher_alg(alg); + struct crypto_istat_cipher *istat; + struct crypto_stat_cipher rcipher; + + istat = lskcipher_get_stat(skcipher); + + memset(&rcipher, 0, sizeof(rcipher)); + + strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); + + rcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); + rcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); + rcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); + rcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); + rcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); +} + static const struct crypto_type crypto_lskcipher_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_lskcipher_init_tfm, @@ -291,6 +353,9 @@ static const struct crypto_type crypto_lskcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_lskcipher_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_lskcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, diff --git a/crypto/rng.c b/crypto/rng.c index 9d8804e46422..279dffdebf59 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -30,24 +30,30 @@ static int crypto_default_rng_refcnt; int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) { + struct rng_alg *alg = crypto_rng_alg(tfm); u8 *buf = NULL; int err; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&rng_get_stat(alg)->seed_cnt); + if (!seed && slen) { buf = kmalloc(slen, GFP_KERNEL); + err = -ENOMEM; if (!buf) - return -ENOMEM; + goto out; err = get_random_bytes_wait(buf, slen); if (err) - goto out; + goto free_buf; seed = buf; } - err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); -out: + err = alg->seed(tfm, seed, slen); +free_buf: kfree_sensitive(buf); - return err; +out: + return crypto_rng_errstat(alg, err); } EXPORT_SYMBOL_GPL(crypto_rng_reset); @@ -85,6 +91,27 @@ static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "seedsize : %u\n", seedsize(alg)); } +static int __maybe_unused crypto_rng_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct rng_alg *rng = __crypto_rng_alg(alg); + struct crypto_istat_rng *istat; + struct crypto_stat_rng rrng; + + istat = rng_get_stat(rng); + + memset(&rrng, 0, sizeof(rrng)); + + strscpy(rrng.type, "rng", sizeof(rrng.type)); + + rrng.stat_generate_cnt = atomic64_read(&istat->generate_cnt); + rrng.stat_generate_tlen = atomic64_read(&istat->generate_tlen); + rrng.stat_seed_cnt = atomic64_read(&istat->seed_cnt); + rrng.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng); +} + static const struct crypto_type crypto_rng_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_rng_init_tfm, @@ -93,6 +120,9 @@ static const struct crypto_type crypto_rng_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_rng_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_rng_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -169,6 +199,7 @@ EXPORT_SYMBOL_GPL(crypto_del_default_rng); int crypto_register_rng(struct rng_alg *alg) { + struct crypto_istat_rng *istat = rng_get_stat(alg); struct crypto_alg *base = &alg->base; if (alg->seedsize > PAGE_SIZE / 8) @@ -178,6 +209,9 @@ int crypto_register_rng(struct rng_alg *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_RNG; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); + return crypto_register_alg(base); } EXPORT_SYMBOL_GPL(crypto_register_rng); diff --git a/crypto/scompress.c b/crypto/scompress.c index 93daf3eb9842..60bbb7ea4060 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -270,6 +270,9 @@ static const struct crypto_type crypto_scomp_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_scomp_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_acomp_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -279,10 +282,11 @@ static const struct crypto_type crypto_scomp_type = { int crypto_register_scomp(struct scomp_alg *alg) { - struct crypto_alg *base = &alg->base; + struct crypto_alg *base = &alg->calg.base; + + comp_prepare_alg(&alg->calg); base->cra_type = &crypto_scomp_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_SCOMPRESS; return crypto_register_alg(base); diff --git a/crypto/shash.c b/crypto/shash.c index 0ffe671b519e..c3f7f6a25280 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -16,6 +16,18 @@ #include "hash.h" +static inline struct crypto_istat_hash *shash_get_stat(struct shash_alg *alg) +{ + return hash_get_stat(&alg->halg); +} + +static inline int crypto_shash_errstat(struct shash_alg *alg, int err) +{ + if (IS_ENABLED(CONFIG_CRYPTO_STATS) && err) + atomic64_inc(&shash_get_stat(alg)->err_cnt); + return err; +} + int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { @@ -49,13 +61,29 @@ EXPORT_SYMBOL_GPL(crypto_shash_setkey); int crypto_shash_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return crypto_shash_alg(desc->tfm)->update(desc, data, len); + struct shash_alg *shash = crypto_shash_alg(desc->tfm); + int err; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_add(len, &shash_get_stat(shash)->hash_tlen); + + err = shash->update(desc, data, len); + + return crypto_shash_errstat(shash, err); } EXPORT_SYMBOL_GPL(crypto_shash_update); int crypto_shash_final(struct shash_desc *desc, u8 *out) { - return crypto_shash_alg(desc->tfm)->final(desc, out); + struct shash_alg *shash = crypto_shash_alg(desc->tfm); + int err; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&shash_get_stat(shash)->hash_cnt); + + err = shash->final(desc, out); + + return crypto_shash_errstat(shash, err); } EXPORT_SYMBOL_GPL(crypto_shash_final); @@ -71,7 +99,20 @@ static int shash_default_finup(struct shash_desc *desc, const u8 *data, int crypto_shash_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return crypto_shash_alg(desc->tfm)->finup(desc, data, len, out); + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + int err; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = shash_get_stat(shash); + + atomic64_inc(&istat->hash_cnt); + atomic64_add(len, &istat->hash_tlen); + } + + err = shash->finup(desc, data, len, out); + + return crypto_shash_errstat(shash, err); } EXPORT_SYMBOL_GPL(crypto_shash_finup); @@ -88,11 +129,22 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + int err; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = shash_get_stat(shash); + + atomic64_inc(&istat->hash_cnt); + atomic64_add(len, &istat->hash_tlen); + } if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; + err = -ENOKEY; + else + err = shash->digest(desc, data, len, out); - return crypto_shash_alg(desc->tfm)->digest(desc, data, len, out); + return crypto_shash_errstat(shash, err); } EXPORT_SYMBOL_GPL(crypto_shash_digest); @@ -213,6 +265,12 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "digestsize : %u\n", salg->digestsize); } +static int __maybe_unused crypto_shash_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + return crypto_hash_report_stat(skb, alg, "shash"); +} + const struct crypto_type crypto_shash_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_shash_init_tfm, @@ -222,6 +280,9 @@ const struct crypto_type crypto_shash_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_shash_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_shash_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_MASK, @@ -289,6 +350,7 @@ EXPORT_SYMBOL_GPL(crypto_clone_shash); int hash_prepare_alg(struct hash_alg_common *alg) { + struct crypto_istat_hash *istat = hash_get_stat(alg); struct crypto_alg *base = &alg->base; if (alg->digestsize > HASH_MAX_DIGESTSIZE) @@ -300,6 +362,9 @@ int hash_prepare_alg(struct hash_alg_common *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); + return 0; } diff --git a/crypto/sig.c b/crypto/sig.c index 7645bedf3a1f..224c47019297 100644 --- a/crypto/sig.c +++ b/crypto/sig.c @@ -45,6 +45,16 @@ static int __maybe_unused crypto_sig_report(struct sk_buff *skb, return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rsig), &rsig); } +static int __maybe_unused crypto_sig_report_stat(struct sk_buff *skb, + struct crypto_alg *alg) +{ + struct crypto_stat_akcipher rsig = {}; + + strscpy(rsig.type, "sig", sizeof(rsig.type)); + + return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, sizeof(rsig), &rsig); +} + static const struct crypto_type crypto_sig_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_sig_init_tfm, @@ -53,6 +63,9 @@ static const struct crypto_type crypto_sig_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_sig_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_sig_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_SIG_MASK, diff --git a/crypto/skcipher.c b/crypto/skcipher.c index ceed7f33a67b..bc70e159d27d 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -89,6 +89,25 @@ static inline struct skcipher_alg *__crypto_skcipher_alg( return container_of(alg, struct skcipher_alg, base); } +static inline struct crypto_istat_cipher *skcipher_get_stat( + struct skcipher_alg *alg) +{ + return skcipher_get_stat_common(&alg->co); +} + +static inline int crypto_skcipher_errstat(struct skcipher_alg *alg, int err) +{ + struct crypto_istat_cipher *istat = skcipher_get_stat(alg); + + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&istat->err_cnt); + + return err; +} + static int skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) { u8 *addr; @@ -635,12 +654,23 @@ int crypto_skcipher_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + int ret; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_cipher *istat = skcipher_get_stat(alg); + + atomic64_inc(&istat->encrypt_cnt); + atomic64_add(req->cryptlen, &istat->encrypt_tlen); + } if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - if (alg->co.base.cra_type != &crypto_skcipher_type) - return crypto_lskcipher_encrypt_sg(req); - return alg->encrypt(req); + ret = -ENOKEY; + else if (alg->co.base.cra_type != &crypto_skcipher_type) + ret = crypto_lskcipher_encrypt_sg(req); + else + ret = alg->encrypt(req); + + return crypto_skcipher_errstat(alg, ret); } EXPORT_SYMBOL_GPL(crypto_skcipher_encrypt); @@ -648,12 +678,23 @@ int crypto_skcipher_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + int ret; + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_cipher *istat = skcipher_get_stat(alg); + + atomic64_inc(&istat->decrypt_cnt); + atomic64_add(req->cryptlen, &istat->decrypt_tlen); + } if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - if (alg->co.base.cra_type != &crypto_skcipher_type) - return crypto_lskcipher_decrypt_sg(req); - return alg->decrypt(req); + ret = -ENOKEY; + else if (alg->co.base.cra_type != &crypto_skcipher_type) + ret = crypto_lskcipher_decrypt_sg(req); + else + ret = alg->decrypt(req); + + return crypto_skcipher_errstat(alg, ret); } EXPORT_SYMBOL_GPL(crypto_skcipher_decrypt); @@ -805,6 +846,28 @@ static int __maybe_unused crypto_skcipher_report( sizeof(rblkcipher), &rblkcipher); } +static int __maybe_unused crypto_skcipher_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + struct skcipher_alg *skcipher = __crypto_skcipher_alg(alg); + struct crypto_istat_cipher *istat; + struct crypto_stat_cipher rcipher; + + istat = skcipher_get_stat(skcipher); + + memset(&rcipher, 0, sizeof(rcipher)); + + strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); + + rcipher.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); + rcipher.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); + rcipher.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); + rcipher.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); + rcipher.stat_err_cnt = atomic64_read(&istat->err_cnt); + + return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); +} + static const struct crypto_type crypto_skcipher_type = { .extsize = crypto_skcipher_extsize, .init_tfm = crypto_skcipher_init_tfm, @@ -814,6 +877,9 @@ static const struct crypto_type crypto_skcipher_type = { #endif #if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_skcipher_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_skcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_SKCIPHER_MASK, @@ -869,6 +935,7 @@ EXPORT_SYMBOL_GPL(crypto_has_skcipher); int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) { + struct crypto_istat_cipher *istat = skcipher_get_stat_common(alg); struct crypto_alg *base = &alg->base; if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8 || @@ -881,6 +948,9 @@ int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + memset(istat, 0, sizeof(*istat)); + return 0; } diff --git a/crypto/skcipher.h b/crypto/skcipher.h index 703651367dd8..16c9484360da 100644 --- a/crypto/skcipher.h +++ b/crypto/skcipher.h @@ -10,6 +10,16 @@ #include #include "internal.h" +static inline struct crypto_istat_cipher *skcipher_get_stat_common( + struct skcipher_alg_common *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + int crypto_lskcipher_encrypt_sg(struct skcipher_request *req); int crypto_lskcipher_decrypt_sg(struct skcipher_request *req); int crypto_init_lskcipher_ops_sg(struct crypto_tfm *tfm); diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h index d042c90e0907..574cffc90730 100644 --- a/include/crypto/acompress.h +++ b/include/crypto/acompress.h @@ -56,6 +56,35 @@ struct crypto_acomp { struct crypto_tfm base; }; +/* + * struct crypto_istat_compress - statistics for compress algorithm + * @compress_cnt: number of compress requests + * @compress_tlen: total data size handled by compress requests + * @decompress_cnt: number of decompress requests + * @decompress_tlen: total data size handled by decompress requests + * @err_cnt: number of error for compress requests + */ +struct crypto_istat_compress { + atomic64_t compress_cnt; + atomic64_t compress_tlen; + atomic64_t decompress_cnt; + atomic64_t decompress_tlen; + atomic64_t err_cnt; +}; + +#ifdef CONFIG_CRYPTO_STATS +#define COMP_ALG_COMMON_STATS struct crypto_istat_compress stat; +#else +#define COMP_ALG_COMMON_STATS +#endif + +#define COMP_ALG_COMMON { \ + COMP_ALG_COMMON_STATS \ + \ + struct crypto_alg base; \ +} +struct comp_alg_common COMP_ALG_COMMON; + /** * DOC: Asynchronous Compression API * @@ -103,11 +132,23 @@ static inline struct crypto_tfm *crypto_acomp_tfm(struct crypto_acomp *tfm) return &tfm->base; } +static inline struct comp_alg_common *__crypto_comp_alg_common( + struct crypto_alg *alg) +{ + return container_of(alg, struct comp_alg_common, base); +} + static inline struct crypto_acomp *__crypto_acomp_tfm(struct crypto_tfm *tfm) { return container_of(tfm, struct crypto_acomp, base); } +static inline struct comp_alg_common *crypto_comp_alg_common( + struct crypto_acomp *tfm) +{ + return __crypto_comp_alg_common(crypto_acomp_tfm(tfm)->__crt_alg); +} + static inline unsigned int crypto_acomp_reqsize(struct crypto_acomp *tfm) { return tfm->reqsize; @@ -214,6 +255,27 @@ static inline void acomp_request_set_params(struct acomp_req *req, req->flags |= CRYPTO_ACOMP_ALLOC_OUTPUT; } +static inline struct crypto_istat_compress *comp_get_stat( + struct comp_alg_common *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + +static inline int crypto_comp_errstat(struct comp_alg_common *alg, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&comp_get_stat(alg)->err_cnt); + + return err; +} + /** * crypto_acomp_compress() -- Invoke asynchronous compress operation * @@ -225,7 +287,19 @@ static inline void acomp_request_set_params(struct acomp_req *req, */ static inline int crypto_acomp_compress(struct acomp_req *req) { - return crypto_acomp_reqtfm(req)->compress(req); + struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + struct comp_alg_common *alg; + + alg = crypto_comp_alg_common(tfm); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_compress *istat = comp_get_stat(alg); + + atomic64_inc(&istat->compress_cnt); + atomic64_add(req->slen, &istat->compress_tlen); + } + + return crypto_comp_errstat(alg, tfm->compress(req)); } /** @@ -239,7 +313,19 @@ static inline int crypto_acomp_compress(struct acomp_req *req) */ static inline int crypto_acomp_decompress(struct acomp_req *req) { - return crypto_acomp_reqtfm(req)->decompress(req); + struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + struct comp_alg_common *alg; + + alg = crypto_comp_alg_common(tfm); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_compress *istat = comp_get_stat(alg); + + atomic64_inc(&istat->decompress_cnt); + atomic64_add(req->slen, &istat->decompress_tlen); + } + + return crypto_comp_errstat(alg, tfm->decompress(req)); } #endif diff --git a/include/crypto/aead.h b/include/crypto/aead.h index 0e8a41638678..51382befbe37 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -101,6 +101,22 @@ struct aead_request { void *__ctx[] CRYPTO_MINALIGN_ATTR; }; +/* + * struct crypto_istat_aead - statistics for AEAD algorithm + * @encrypt_cnt: number of encrypt requests + * @encrypt_tlen: total data size handled by encrypt requests + * @decrypt_cnt: number of decrypt requests + * @decrypt_tlen: total data size handled by decrypt requests + * @err_cnt: number of error for AEAD requests + */ +struct crypto_istat_aead { + atomic64_t encrypt_cnt; + atomic64_t encrypt_tlen; + atomic64_t decrypt_cnt; + atomic64_t decrypt_tlen; + atomic64_t err_cnt; +}; + /** * struct aead_alg - AEAD cipher definition * @maxauthsize: Set the maximum authentication tag size supported by the @@ -119,6 +135,7 @@ struct aead_request { * @setkey: see struct skcipher_alg * @encrypt: see struct skcipher_alg * @decrypt: see struct skcipher_alg + * @stat: statistics for AEAD algorithm * @ivsize: see struct skcipher_alg * @chunksize: see struct skcipher_alg * @init: Initialize the cryptographic transformation object. This function @@ -145,6 +162,10 @@ struct aead_alg { int (*init)(struct crypto_aead *tfm); void (*exit)(struct crypto_aead *tfm); +#ifdef CONFIG_CRYPTO_STATS + struct crypto_istat_aead stat; +#endif + unsigned int ivsize; unsigned int maxauthsize; unsigned int chunksize; diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 18a10cad07aa..31c111bebb68 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -54,6 +54,26 @@ struct crypto_akcipher { struct crypto_tfm base; }; +/* + * struct crypto_istat_akcipher - statistics for akcipher algorithm + * @encrypt_cnt: number of encrypt requests + * @encrypt_tlen: total data size handled by encrypt requests + * @decrypt_cnt: number of decrypt requests + * @decrypt_tlen: total data size handled by decrypt requests + * @verify_cnt: number of verify operation + * @sign_cnt: number of sign requests + * @err_cnt: number of error for akcipher requests + */ +struct crypto_istat_akcipher { + atomic64_t encrypt_cnt; + atomic64_t encrypt_tlen; + atomic64_t decrypt_cnt; + atomic64_t decrypt_tlen; + atomic64_t verify_cnt; + atomic64_t sign_cnt; + atomic64_t err_cnt; +}; + /** * struct akcipher_alg - generic public key algorithm * @@ -90,6 +110,7 @@ struct crypto_akcipher { * @exit: Deinitialize the cryptographic transformation object. This is a * counterpart to @init, used to remove various changes set in * @init. + * @stat: Statistics for akcipher algorithm * * @base: Common crypto API algorithm data structure */ @@ -106,6 +127,10 @@ struct akcipher_alg { int (*init)(struct crypto_akcipher *tfm); void (*exit)(struct crypto_akcipher *tfm); +#ifdef CONFIG_CRYPTO_STATS + struct crypto_istat_akcipher stat; +#endif + struct crypto_alg base; }; @@ -277,6 +302,27 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm) return alg->max_size(tfm); } +static inline struct crypto_istat_akcipher *akcipher_get_stat( + struct akcipher_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + +static inline int crypto_akcipher_errstat(struct akcipher_alg *alg, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&akcipher_get_stat(alg)->err_cnt); + + return err; +} + /** * crypto_akcipher_encrypt() - Invoke public key encrypt operation * @@ -290,8 +336,16 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm) static inline int crypto_akcipher_encrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - return crypto_akcipher_alg(tfm)->encrypt(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); + + atomic64_inc(&istat->encrypt_cnt); + atomic64_add(req->src_len, &istat->encrypt_tlen); + } + + return crypto_akcipher_errstat(alg, alg->encrypt(req)); } /** @@ -307,8 +361,16 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req) static inline int crypto_akcipher_decrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - return crypto_akcipher_alg(tfm)->decrypt(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_akcipher *istat = akcipher_get_stat(alg); + + atomic64_inc(&istat->decrypt_cnt); + atomic64_add(req->src_len, &istat->decrypt_tlen); + } + + return crypto_akcipher_errstat(alg, alg->decrypt(req)); } /** @@ -360,8 +422,12 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, static inline int crypto_akcipher_sign(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - return crypto_akcipher_alg(tfm)->sign(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&akcipher_get_stat(alg)->sign_cnt); + + return crypto_akcipher_errstat(alg, alg->sign(req)); } /** @@ -381,8 +447,12 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req) static inline int crypto_akcipher_verify(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - return crypto_akcipher_alg(tfm)->verify(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&akcipher_get_stat(alg)->verify_cnt); + + return crypto_akcipher_errstat(alg, alg->verify(req)); } /** diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 156de41ca760..7a4a71af653f 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -61,6 +61,9 @@ struct crypto_type { void (*show)(struct seq_file *m, struct crypto_alg *alg); int (*report)(struct sk_buff *skb, struct crypto_alg *alg); void (*free)(struct crypto_instance *inst); +#ifdef CONFIG_CRYPTO_STATS + int (*report_stat)(struct sk_buff *skb, struct crypto_alg *alg); +#endif unsigned int type; unsigned int maskclear; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 0014bdd81ab7..5d61f576cfc8 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -23,8 +23,27 @@ struct crypto_ahash; * crypto_unregister_shash(). */ +/* + * struct crypto_istat_hash - statistics for has algorithm + * @hash_cnt: number of hash requests + * @hash_tlen: total data size hashed + * @err_cnt: number of error for hash requests + */ +struct crypto_istat_hash { + atomic64_t hash_cnt; + atomic64_t hash_tlen; + atomic64_t err_cnt; +}; + +#ifdef CONFIG_CRYPTO_STATS +#define HASH_ALG_COMMON_STAT struct crypto_istat_hash stat; +#else +#define HASH_ALG_COMMON_STAT +#endif + /* * struct hash_alg_common - define properties of message digest + * @stat: Statistics for hash algorithm. * @digestsize: Size of the result of the transformation. A buffer of this size * must be available to the @final and @finup calls, so they can * store the resulting hash into it. For various predefined sizes, @@ -41,6 +60,8 @@ struct crypto_ahash; * information. */ #define HASH_ALG_COMMON { \ + HASH_ALG_COMMON_STAT \ + \ unsigned int digestsize; \ unsigned int statesize; \ \ @@ -222,6 +243,7 @@ struct shash_alg { }; }; #undef HASH_ALG_COMMON +#undef HASH_ALG_COMMON_STAT struct crypto_ahash { bool using_shash; /* Underlying algorithm is shash, not ahash */ diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h index 475e60a9f9ea..4ac46bafba9d 100644 --- a/include/crypto/internal/acompress.h +++ b/include/crypto/internal/acompress.h @@ -31,7 +31,9 @@ * @init. * * @reqsize: Context size for (de)compression requests + * @stat: Statistics for compress algorithm * @base: Common crypto API algorithm data structure + * @calg: Cmonn algorithm data structure shared with scomp */ struct acomp_alg { int (*compress)(struct acomp_req *req); @@ -42,7 +44,10 @@ struct acomp_alg { unsigned int reqsize; - struct crypto_alg base; + union { + struct COMP_ALG_COMMON; + struct comp_alg_common calg; + }; }; /* diff --git a/include/crypto/internal/cryptouser.h b/include/crypto/internal/cryptouser.h new file mode 100644 index 000000000000..fd54074332f5 --- /dev/null +++ b/include/crypto/internal/cryptouser.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact); + +#ifdef CONFIG_CRYPTO_STATS +int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs); +#else +static inline int crypto_reportstat(struct sk_buff *in_skb, + struct nlmsghdr *in_nlh, + struct nlattr **attrs) +{ + return -ENOTSUPP; +} +#endif diff --git a/include/crypto/internal/scompress.h b/include/crypto/internal/scompress.h index 5a75f2db18ce..858fe3965ae3 100644 --- a/include/crypto/internal/scompress.h +++ b/include/crypto/internal/scompress.h @@ -27,7 +27,9 @@ struct crypto_scomp { * @free_ctx: Function frees context allocated with alloc_ctx * @compress: Function performs a compress operation * @decompress: Function performs a de-compress operation + * @stat: Statistics for compress algorithm * @base: Common crypto API algorithm data structure + * @calg: Cmonn algorithm data structure shared with acomp */ struct scomp_alg { void *(*alloc_ctx)(struct crypto_scomp *tfm); @@ -38,7 +40,11 @@ struct scomp_alg { int (*decompress)(struct crypto_scomp *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen, void *ctx); - struct crypto_alg base; + + union { + struct COMP_ALG_COMMON; + struct comp_alg_common calg; + }; }; static inline struct scomp_alg *__crypto_scomp_alg(struct crypto_alg *alg) diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h index 2d9c4de57b69..1988e24a0d1d 100644 --- a/include/crypto/kpp.h +++ b/include/crypto/kpp.h @@ -51,6 +51,20 @@ struct crypto_kpp { struct crypto_tfm base; }; +/* + * struct crypto_istat_kpp - statistics for KPP algorithm + * @setsecret_cnt: number of setsecrey operation + * @generate_public_key_cnt: number of generate_public_key operation + * @compute_shared_secret_cnt: number of compute_shared_secret operation + * @err_cnt: number of error for KPP requests + */ +struct crypto_istat_kpp { + atomic64_t setsecret_cnt; + atomic64_t generate_public_key_cnt; + atomic64_t compute_shared_secret_cnt; + atomic64_t err_cnt; +}; + /** * struct kpp_alg - generic key-agreement protocol primitives * @@ -73,6 +87,7 @@ struct crypto_kpp { * @exit: Undo everything @init did. * * @base: Common crypto API algorithm data structure + * @stat: Statistics for KPP algorithm */ struct kpp_alg { int (*set_secret)(struct crypto_kpp *tfm, const void *buffer, @@ -85,6 +100,10 @@ struct kpp_alg { int (*init)(struct crypto_kpp *tfm); void (*exit)(struct crypto_kpp *tfm); +#ifdef CONFIG_CRYPTO_STATS + struct crypto_istat_kpp stat; +#endif + struct crypto_alg base; }; @@ -272,6 +291,26 @@ struct kpp_secret { unsigned short len; }; +static inline struct crypto_istat_kpp *kpp_get_stat(struct kpp_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + +static inline int crypto_kpp_errstat(struct kpp_alg *alg, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&kpp_get_stat(alg)->err_cnt); + + return err; +} + /** * crypto_kpp_set_secret() - Invoke kpp operation * @@ -290,7 +329,12 @@ struct kpp_secret { static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, const void *buffer, unsigned int len) { - return crypto_kpp_alg(tfm)->set_secret(tfm, buffer, len); + struct kpp_alg *alg = crypto_kpp_alg(tfm); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&kpp_get_stat(alg)->setsecret_cnt); + + return crypto_kpp_errstat(alg, alg->set_secret(tfm, buffer, len)); } /** @@ -309,8 +353,12 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, static inline int crypto_kpp_generate_public_key(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct kpp_alg *alg = crypto_kpp_alg(tfm); - return crypto_kpp_alg(tfm)->generate_public_key(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&kpp_get_stat(alg)->generate_public_key_cnt); + + return crypto_kpp_errstat(alg, alg->generate_public_key(req)); } /** @@ -326,8 +374,12 @@ static inline int crypto_kpp_generate_public_key(struct kpp_request *req) static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct kpp_alg *alg = crypto_kpp_alg(tfm); - return crypto_kpp_alg(tfm)->compute_shared_secret(req); + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&kpp_get_stat(alg)->compute_shared_secret_cnt); + + return crypto_kpp_errstat(alg, alg->compute_shared_secret(req)); } /** diff --git a/include/crypto/rng.h b/include/crypto/rng.h index 5ac4388f50e1..6abe5102e5fb 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -15,6 +15,20 @@ struct crypto_rng; +/* + * struct crypto_istat_rng: statistics for RNG algorithm + * @generate_cnt: number of RNG generate requests + * @generate_tlen: total data size of generated data by the RNG + * @seed_cnt: number of times the RNG was seeded + * @err_cnt: number of error for RNG requests + */ +struct crypto_istat_rng { + atomic64_t generate_cnt; + atomic64_t generate_tlen; + atomic64_t seed_cnt; + atomic64_t err_cnt; +}; + /** * struct rng_alg - random number generator definition * @@ -32,6 +46,7 @@ struct crypto_rng; * size of the seed is defined with @seedsize . * @set_ent: Set entropy that would otherwise be obtained from * entropy source. Internal use only. + * @stat: Statistics for rng algorithm * @seedsize: The seed size required for a random number generator * initialization defined with this variable. Some * random number generators does not require a seed @@ -48,6 +63,10 @@ struct rng_alg { void (*set_ent)(struct crypto_rng *tfm, const u8 *data, unsigned int len); +#ifdef CONFIG_CRYPTO_STATS + struct crypto_istat_rng stat; +#endif + unsigned int seedsize; struct crypto_alg base; @@ -125,6 +144,26 @@ static inline void crypto_free_rng(struct crypto_rng *tfm) crypto_destroy_tfm(tfm, crypto_rng_tfm(tfm)); } +static inline struct crypto_istat_rng *rng_get_stat(struct rng_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + return &alg->stat; +#else + return NULL; +#endif +} + +static inline int crypto_rng_errstat(struct rng_alg *alg, int err) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) + return err; + + if (err && err != -EINPROGRESS && err != -EBUSY) + atomic64_inc(&rng_get_stat(alg)->err_cnt); + + return err; +} + /** * crypto_rng_generate() - get random number * @tfm: cipher handle @@ -143,7 +182,17 @@ static inline int crypto_rng_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { - return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); + struct rng_alg *alg = crypto_rng_alg(tfm); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_rng *istat = rng_get_stat(alg); + + atomic64_inc(&istat->generate_cnt); + atomic64_add(dlen, &istat->generate_tlen); + } + + return crypto_rng_errstat(alg, + alg->generate(tfm, src, slen, dst, dlen)); } /** diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 74d47e23374e..c8857d7bdb37 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -64,6 +64,28 @@ struct crypto_lskcipher { struct crypto_tfm base; }; +/* + * struct crypto_istat_cipher - statistics for cipher algorithm + * @encrypt_cnt: number of encrypt requests + * @encrypt_tlen: total data size handled by encrypt requests + * @decrypt_cnt: number of decrypt requests + * @decrypt_tlen: total data size handled by decrypt requests + * @err_cnt: number of error for cipher requests + */ +struct crypto_istat_cipher { + atomic64_t encrypt_cnt; + atomic64_t encrypt_tlen; + atomic64_t decrypt_cnt; + atomic64_t decrypt_tlen; + atomic64_t err_cnt; +}; + +#ifdef CONFIG_CRYPTO_STATS +#define SKCIPHER_ALG_COMMON_STAT struct crypto_istat_cipher stat; +#else +#define SKCIPHER_ALG_COMMON_STAT +#endif + /* * struct skcipher_alg_common - common properties of skcipher_alg * @min_keysize: Minimum key size supported by the transformation. This is the @@ -81,6 +103,7 @@ struct crypto_lskcipher { * @chunksize: Equal to the block size except for stream ciphers such as * CTR where it is set to the underlying block size. * @statesize: Size of the internal state for the algorithm. + * @stat: Statistics for cipher algorithm * @base: Definition of a generic crypto algorithm. */ #define SKCIPHER_ALG_COMMON { \ @@ -90,6 +113,8 @@ struct crypto_lskcipher { unsigned int chunksize; \ unsigned int statesize; \ \ + SKCIPHER_ALG_COMMON_STAT \ + \ struct crypto_alg base; \ } struct skcipher_alg_common SKCIPHER_ALG_COMMON; diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h index e163670d60f7..5730c67f0617 100644 --- a/include/uapi/linux/cryptouser.h +++ b/include/uapi/linux/cryptouser.h @@ -54,16 +54,16 @@ enum crypto_attr_type_t { CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */ - CRYPTOCFGA_STAT_LARVAL, /* No longer supported */ - CRYPTOCFGA_STAT_HASH, /* No longer supported */ - CRYPTOCFGA_STAT_BLKCIPHER, /* No longer supported */ - CRYPTOCFGA_STAT_AEAD, /* No longer supported */ - CRYPTOCFGA_STAT_COMPRESS, /* No longer supported */ - CRYPTOCFGA_STAT_RNG, /* No longer supported */ - CRYPTOCFGA_STAT_CIPHER, /* No longer supported */ - CRYPTOCFGA_STAT_AKCIPHER, /* No longer supported */ - CRYPTOCFGA_STAT_KPP, /* No longer supported */ - CRYPTOCFGA_STAT_ACOMP, /* No longer supported */ + CRYPTOCFGA_STAT_LARVAL, /* struct crypto_stat */ + CRYPTOCFGA_STAT_HASH, /* struct crypto_stat */ + CRYPTOCFGA_STAT_BLKCIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_AEAD, /* struct crypto_stat */ + CRYPTOCFGA_STAT_COMPRESS, /* struct crypto_stat */ + CRYPTOCFGA_STAT_RNG, /* struct crypto_stat */ + CRYPTOCFGA_STAT_CIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_AKCIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_KPP, /* struct crypto_stat */ + CRYPTOCFGA_STAT_ACOMP, /* struct crypto_stat */ __CRYPTOCFGA_MAX #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) @@ -79,7 +79,6 @@ struct crypto_user_alg { __u32 cru_flags; }; -/* No longer supported, do not use. */ struct crypto_stat_aead { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -89,7 +88,6 @@ struct crypto_stat_aead { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_akcipher { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -101,7 +99,6 @@ struct crypto_stat_akcipher { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_cipher { char type[CRYPTO_MAX_NAME]; __u64 stat_encrypt_cnt; @@ -111,7 +108,6 @@ struct crypto_stat_cipher { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_compress { char type[CRYPTO_MAX_NAME]; __u64 stat_compress_cnt; @@ -121,7 +117,6 @@ struct crypto_stat_compress { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_hash { char type[CRYPTO_MAX_NAME]; __u64 stat_hash_cnt; @@ -129,7 +124,6 @@ struct crypto_stat_hash { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_kpp { char type[CRYPTO_MAX_NAME]; __u64 stat_setsecret_cnt; @@ -138,7 +132,6 @@ struct crypto_stat_kpp { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_rng { char type[CRYPTO_MAX_NAME]; __u64 stat_generate_cnt; @@ -147,7 +140,6 @@ struct crypto_stat_rng { __u64 stat_err_cnt; }; -/* No longer supported, do not use. */ struct crypto_stat_larval { char type[CRYPTO_MAX_NAME]; }; From 5621fafaac0031e8813be4873f8efa097591b026 Mon Sep 17 00:00:00 2001 From: Ben Cheatham Date: Mon, 11 Mar 2024 09:25:05 -0500 Subject: [PATCH 788/814] EINJ: Migrate to a platform driver Change the EINJ module to install a platform device/driver on module init and move the module init() and exit() functions to driver probe and remove. This change allows the EINJ module to load regardless of whether setting up EINJ succeeds, which allows dependent modules to still load (i.e. the CXL core). Since EINJ may no longer be initialized when the module loads, any functions that are called from dependent/external modules should safegaurd against the case EINJ didn't load. Reviewed-by: Jonathan Cameron Reviewed-by: Dan Williams Signed-off-by: Ben Cheatham Link: https://lore.kernel.org/r/20240311142508.31717-2-Benjamin.Cheatham@amd.com Signed-off-by: Dan Williams --- drivers/acpi/apei/einj.c | 48 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 89fb9331c611..937c69844dac 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "apei-internal.h" @@ -137,6 +138,11 @@ static struct apei_exec_ins_type einj_ins_type[] = { */ static DEFINE_MUTEX(einj_mutex); +/* + * Exported APIs use this flag to exit early if einj_probe() failed. + */ +static bool einj_initialized __ro_after_init; + static void *einj_param; static void einj_exec_ctx_init(struct apei_exec_context *ctx) @@ -703,21 +709,21 @@ static int einj_check_table(struct acpi_table_einj *einj_tab) return 0; } -static int __init einj_init(void) +static int __init einj_probe(struct platform_device *pdev) { int rc; acpi_status status; struct apei_exec_context ctx; if (acpi_disabled) { - pr_info("ACPI disabled.\n"); + pr_debug("ACPI disabled.\n"); return -ENODEV; } status = acpi_get_table(ACPI_SIG_EINJ, 0, (struct acpi_table_header **)&einj_tab); if (status == AE_NOT_FOUND) { - pr_warn("EINJ table not found.\n"); + pr_debug("EINJ table not found.\n"); return -ENODEV; } else if (ACPI_FAILURE(status)) { pr_err("Failed to get EINJ table: %s\n", @@ -805,7 +811,7 @@ err_put_table: return rc; } -static void __exit einj_exit(void) +static void __exit einj_remove(struct platform_device *pdev) { struct apei_exec_context ctx; @@ -826,6 +832,40 @@ static void __exit einj_exit(void) acpi_put_table((struct acpi_table_header *)einj_tab); } +static struct platform_device *einj_dev; +static struct platform_driver einj_driver = { + .remove_new = einj_remove, + .driver = { + .name = "acpi-einj", + }, +}; + +static int __init einj_init(void) +{ + struct platform_device_info einj_dev_info = { + .name = "acpi-einj", + .id = -1, + }; + int rc; + + einj_dev = platform_device_register_full(&einj_dev_info); + if (IS_ERR(einj_dev)) + return PTR_ERR(einj_dev); + + rc = platform_driver_probe(&einj_driver, einj_probe); + einj_initialized = rc == 0; + + return 0; +} + +static void __exit einj_exit(void) +{ + if (einj_initialized) + platform_driver_unregister(&einj_driver); + + platform_device_del(einj_dev); +} + module_init(einj_init); module_exit(einj_exit); From 12fb28ea6b1cf24bde27c406eb38ee3c108d73f9 Mon Sep 17 00:00:00 2001 From: Ben Cheatham Date: Mon, 11 Mar 2024 09:25:06 -0500 Subject: [PATCH 789/814] EINJ: Add CXL error type support Move CXL protocol error types from einj.c (now einj-core.c) to einj-cxl.c. einj-cxl.c implements the necessary handling for CXL protocol error injection and exposes an API for the CXL core to use said functionality, while also allowing the EINJ module to be built without CXL support. Because CXL error types targeting CXL 1.0/1.1 ports require special handling, only allow them to be injected through the new cxl debugfs interface (next commit) and return an error when attempting to inject through the legacy interface. Reviewed-by: Jonathan Cameron Signed-off-by: Ben Cheatham Link: https://lore.kernel.org/r/20240311142508.31717-3-Benjamin.Cheatham@amd.com Signed-off-by: Dan Williams --- MAINTAINERS | 1 + drivers/acpi/apei/Kconfig | 13 +++ drivers/acpi/apei/Makefile | 2 + drivers/acpi/apei/apei-internal.h | 18 ++++ drivers/acpi/apei/{einj.c => einj-core.c} | 76 +++++++++++---- drivers/acpi/apei/einj-cxl.c | 113 ++++++++++++++++++++++ include/linux/einj-cxl.h | 44 +++++++++ 7 files changed, 249 insertions(+), 18 deletions(-) rename drivers/acpi/apei/{einj.c => einj-core.c} (93%) create mode 100644 drivers/acpi/apei/einj-cxl.c create mode 100644 include/linux/einj-cxl.h diff --git a/MAINTAINERS b/MAINTAINERS index 2ecaaec6a6bf..90cf8403dd17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5289,6 +5289,7 @@ M: Dan Williams L: linux-cxl@vger.kernel.org S: Maintained F: drivers/cxl/ +F: include/linux/cxl-einj.h F: include/linux/cxl-event.h F: include/uapi/linux/cxl_mem.h F: tools/testing/cxl/ diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 6b18f8bc7be3..3cfe7e7475f2 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -60,6 +60,19 @@ config ACPI_APEI_EINJ mainly used for debugging and testing the other parts of APEI and some other RAS features. +config ACPI_APEI_EINJ_CXL + bool "CXL Error INJection Support" + default ACPI_APEI_EINJ + depends on ACPI_APEI_EINJ + depends on CXL_BUS && CXL_BUS <= ACPI_APEI_EINJ + help + Support for CXL protocol Error INJection through debugfs/cxl. + Availability and which errors are supported is dependent on + the host platform. Look to ACPI v6.5 section 18.6.4 and kernel + EINJ documentation for more information. + + If unsure say 'n' + config ACPI_APEI_ERST_DEBUG tristate "APEI Error Record Serialization Table (ERST) Debug Support" depends on ACPI_APEI diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile index 4dfac2128737..2c474e6477e1 100644 --- a/drivers/acpi/apei/Makefile +++ b/drivers/acpi/apei/Makefile @@ -2,6 +2,8 @@ obj-$(CONFIG_ACPI_APEI) += apei.o obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o +einj-y := einj-core.o +einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o apei-y := apei-base.o hest.o erst.o bert.o diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 67c2c3b959e1..cd2766c69d78 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -130,4 +130,22 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) } int apei_osc_setup(void); + +int einj_get_available_error_type(u32 *type); +int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, + u64 param4); +int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4); +bool einj_is_cxl_error_type(u64 type); +int einj_validate_error_type(u64 type); + +#ifndef ACPI_EINJ_CXL_CACHE_CORRECTABLE +#define ACPI_EINJ_CXL_CACHE_CORRECTABLE BIT(12) +#define ACPI_EINJ_CXL_CACHE_UNCORRECTABLE BIT(13) +#define ACPI_EINJ_CXL_CACHE_FATAL BIT(14) +#define ACPI_EINJ_CXL_MEM_CORRECTABLE BIT(15) +#define ACPI_EINJ_CXL_MEM_UNCORRECTABLE BIT(16) +#define ACPI_EINJ_CXL_MEM_FATAL BIT(17) +#endif + #endif diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj-core.c similarity index 93% rename from drivers/acpi/apei/einj.c rename to drivers/acpi/apei/einj-core.c index 937c69844dac..66e7f529e92f 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj-core.c @@ -37,6 +37,12 @@ #define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \ ACPI_EINJ_MEMORY_UNCORRECTABLE | \ ACPI_EINJ_MEMORY_FATAL) +#define CXL_ERROR_MASK (ACPI_EINJ_CXL_CACHE_CORRECTABLE | \ + ACPI_EINJ_CXL_CACHE_UNCORRECTABLE | \ + ACPI_EINJ_CXL_CACHE_FATAL | \ + ACPI_EINJ_CXL_MEM_CORRECTABLE | \ + ACPI_EINJ_CXL_MEM_UNCORRECTABLE | \ + ACPI_EINJ_CXL_MEM_FATAL) /* * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action. @@ -141,7 +147,7 @@ static DEFINE_MUTEX(einj_mutex); /* * Exported APIs use this flag to exit early if einj_probe() failed. */ -static bool einj_initialized __ro_after_init; +bool einj_initialized __ro_after_init; static void *einj_param; @@ -166,7 +172,7 @@ static int __einj_get_available_error_type(u32 *type) } /* Get error injection capabilities of the platform */ -static int einj_get_available_error_type(u32 *type) +int einj_get_available_error_type(u32 *type) { int rc; @@ -536,8 +542,8 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, } /* Inject the specified hardware error */ -static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, - u64 param3, u64 param4) +int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, + u64 param4) { int rc; u64 base_addr, size; @@ -560,8 +566,17 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, if (type & ACPI5_VENDOR_BIT) { if (vendor_flags != SETWA_FLAGS_MEM) goto inject; - } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) + } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) { goto inject; + } + + /* + * Injections targeting a CXL 1.0/1.1 port have to be injected + * via the einj_cxl_rch_error_inject() path as that does the proper + * validation of the given RCRB base (MMIO) address. + */ + if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) + return -EINVAL; /* * Disallow crazy address masks that give BIOS leeway to pick @@ -593,6 +608,21 @@ inject: return rc; } +int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4) +{ + int rc; + + if (!(einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))) + return -EINVAL; + + mutex_lock(&einj_mutex); + rc = __einj_error_inject(type, flags, param1, param2, param3, param4); + mutex_unlock(&einj_mutex); + + return rc; +} + static u32 error_type; static u32 error_flags; static u64 error_param1; @@ -613,12 +643,6 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = { { BIT(9), "Platform Correctable" }, { BIT(10), "Platform Uncorrectable non-fatal" }, { BIT(11), "Platform Uncorrectable fatal"}, - { BIT(12), "CXL.cache Protocol Correctable" }, - { BIT(13), "CXL.cache Protocol Uncorrectable non-fatal" }, - { BIT(14), "CXL.cache Protocol Uncorrectable fatal" }, - { BIT(15), "CXL.mem Protocol Correctable" }, - { BIT(16), "CXL.mem Protocol Uncorrectable non-fatal" }, - { BIT(17), "CXL.mem Protocol Uncorrectable fatal" }, { BIT(31), "Vendor Defined Error Types" }, }; @@ -647,22 +671,26 @@ static int error_type_get(void *data, u64 *val) return 0; } -static int error_type_set(void *data, u64 val) +bool einj_is_cxl_error_type(u64 type) { + return (type & CXL_ERROR_MASK) && (!(type & ACPI5_VENDOR_BIT)); +} + +int einj_validate_error_type(u64 type) +{ + u32 tval, vendor, available_error_type = 0; int rc; - u32 available_error_type = 0; - u32 tval, vendor; /* Only low 32 bits for error type are valid */ - if (val & GENMASK_ULL(63, 32)) + if (type & GENMASK_ULL(63, 32)) return -EINVAL; /* * Vendor defined types have 0x80000000 bit set, and * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE */ - vendor = val & ACPI5_VENDOR_BIT; - tval = val & 0x7fffffff; + vendor = type & ACPI5_VENDOR_BIT; + tval = type & GENMASK(30, 0); /* Only one error type can be specified */ if (tval & (tval - 1)) @@ -671,9 +699,21 @@ static int error_type_set(void *data, u64 val) rc = einj_get_available_error_type(&available_error_type); if (rc) return rc; - if (!(val & available_error_type)) + if (!(type & available_error_type)) return -EINVAL; } + + return 0; +} + +static int error_type_set(void *data, u64 val) +{ + int rc; + + rc = einj_validate_error_type(val); + if (rc) + return rc; + error_type = val; return 0; diff --git a/drivers/acpi/apei/einj-cxl.c b/drivers/acpi/apei/einj-cxl.c new file mode 100644 index 000000000000..8b8be0c90709 --- /dev/null +++ b/drivers/acpi/apei/einj-cxl.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * CXL Error INJection support. Used by CXL core to inject + * protocol errors into CXL ports. + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Ben Cheatham + */ +#include +#include +#include + +#include "apei-internal.h" + +/* Defined in einj-core.c */ +extern bool einj_initialized; + +static struct { u32 mask; const char *str; } const einj_cxl_error_type_string[] = { + { ACPI_EINJ_CXL_CACHE_CORRECTABLE, "CXL.cache Protocol Correctable" }, + { ACPI_EINJ_CXL_CACHE_UNCORRECTABLE, "CXL.cache Protocol Uncorrectable non-fatal" }, + { ACPI_EINJ_CXL_CACHE_FATAL, "CXL.cache Protocol Uncorrectable fatal" }, + { ACPI_EINJ_CXL_MEM_CORRECTABLE, "CXL.mem Protocol Correctable" }, + { ACPI_EINJ_CXL_MEM_UNCORRECTABLE, "CXL.mem Protocol Uncorrectable non-fatal" }, + { ACPI_EINJ_CXL_MEM_FATAL, "CXL.mem Protocol Uncorrectable fatal" }, +}; + +int einj_cxl_available_error_type_show(struct seq_file *m, void *v) +{ + int cxl_err, rc; + u32 available_error_type = 0; + + rc = einj_get_available_error_type(&available_error_type); + if (rc) + return rc; + + for (int pos = 0; pos < ARRAY_SIZE(einj_cxl_error_type_string); pos++) { + cxl_err = ACPI_EINJ_CXL_CACHE_CORRECTABLE << pos; + + if (available_error_type & cxl_err) + seq_printf(m, "0x%08x\t%s\n", + einj_cxl_error_type_string[pos].mask, + einj_cxl_error_type_string[pos].str); + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(einj_cxl_available_error_type_show, CXL); + +static int cxl_dport_get_sbdf(struct pci_dev *dport_dev, u64 *sbdf) +{ + struct pci_bus *pbus; + struct pci_host_bridge *bridge; + u64 seg = 0, bus; + + pbus = dport_dev->bus; + bridge = pci_find_host_bridge(pbus); + + if (!bridge) + return -ENODEV; + + if (bridge->domain_nr != PCI_DOMAIN_NR_NOT_SET) + seg = bridge->domain_nr; + + bus = pbus->number; + *sbdf = (seg << 24) | (bus << 16) | dport_dev->devfn; + + return 0; +} + +int einj_cxl_inject_rch_error(u64 rcrb, u64 type) +{ + int rc; + + /* Only CXL error types can be specified */ + if (!einj_is_cxl_error_type(type)) + return -EINVAL; + + rc = einj_validate_error_type(type); + if (rc) + return rc; + + return einj_cxl_rch_error_inject(type, 0x2, rcrb, GENMASK_ULL(63, 0), + 0, 0); +} +EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_rch_error, CXL); + +int einj_cxl_inject_error(struct pci_dev *dport, u64 type) +{ + u64 param4 = 0; + int rc; + + /* Only CXL error types can be specified */ + if (!einj_is_cxl_error_type(type)) + return -EINVAL; + + rc = einj_validate_error_type(type); + if (rc) + return rc; + + rc = cxl_dport_get_sbdf(dport, ¶m4); + if (rc) + return rc; + + return einj_error_inject(type, 0x4, 0, 0, 0, param4); +} +EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_error, CXL); + +bool einj_cxl_is_initialized(void) +{ + return einj_initialized; +} +EXPORT_SYMBOL_NS_GPL(einj_cxl_is_initialized, CXL); diff --git a/include/linux/einj-cxl.h b/include/linux/einj-cxl.h new file mode 100644 index 000000000000..624ff6ff41f9 --- /dev/null +++ b/include/linux/einj-cxl.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * CXL protocol Error INJection support. + * + * Copyright (c) 2023 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Ben Cheatham + */ +#ifndef EINJ_CXL_H +#define EINJ_CXL_H + +#include +#include + +struct pci_dev; +struct seq_file; + +#if IS_ENABLED(CONFIG_ACPI_APEI_EINJ_CXL) +int einj_cxl_available_error_type_show(struct seq_file *m, void *v); +int einj_cxl_inject_error(struct pci_dev *dport_dev, u64 type); +int einj_cxl_inject_rch_error(u64 rcrb, u64 type); +bool einj_cxl_is_initialized(void); +#else /* !IS_ENABLED(CONFIG_ACPI_APEI_EINJ_CXL) */ +static inline int einj_cxl_available_error_type_show(struct seq_file *m, + void *v) +{ + return -ENXIO; +} + +static inline int einj_cxl_inject_error(struct pci_dev *dport_dev, u64 type) +{ + return -ENXIO; +} + +static inline int einj_cxl_inject_rch_error(u64 rcrb, u64 type) +{ + return -ENXIO; +} + +static inline bool einj_cxl_is_initialized(void) { return false; } +#endif /* CONFIG_ACPI_APEI_EINJ_CXL */ + +#endif /* EINJ_CXL_H */ From a0563f58300360ef2a00b8fcfea91711594d70be Mon Sep 17 00:00:00 2001 From: Ben Cheatham Date: Mon, 11 Mar 2024 09:25:08 -0500 Subject: [PATCH 790/814] EINJ, Documentation: Update EINJ kernel doc Update EINJ kernel document to include how to inject CXL protocol error types, build the kernel to include CXL error types, and give an example injection. Reviewed-by: Jonathan Cameron Signed-off-by: Ben Cheatham Link: https://lore.kernel.org/r/20240311142508.31717-5-Benjamin.Cheatham@amd.com Signed-off-by: Dan Williams --- .../firmware-guide/acpi/apei/einj.rst | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/firmware-guide/acpi/apei/einj.rst b/Documentation/firmware-guide/acpi/apei/einj.rst index d6b61d22f525..c52b9da08fa9 100644 --- a/Documentation/firmware-guide/acpi/apei/einj.rst +++ b/Documentation/firmware-guide/acpi/apei/einj.rst @@ -32,6 +32,10 @@ configuration:: CONFIG_ACPI_APEI CONFIG_ACPI_APEI_EINJ +...and to (optionally) enable CXL protocol error injection set:: + + CONFIG_ACPI_APEI_EINJ_CXL + The EINJ user interface is in /apei/einj. The following files belong to it: @@ -118,6 +122,24 @@ The following files belong to it: this actually works depends on what operations the BIOS actually includes in the trigger phase. +CXL error types are supported from ACPI 6.5 onwards (given a CXL port +is present). The EINJ user interface for CXL error types is at +/cxl. The following files belong to it: + +- einj_types: + + Provides the same functionality as available_error_types above, but + for CXL error types + +- $dport_dev/einj_inject: + + Injects a CXL error type into the CXL port represented by $dport_dev, + where $dport_dev is the name of the CXL port (usually a PCIe device name). + Error injections targeting a CXL 2.0+ port can use the legacy interface + under /apei/einj, while CXL 1.1/1.0 port injections + must use this file. + + BIOS versions based on the ACPI 4.0 specification have limited options in controlling where the errors are injected. Your BIOS may support an extension (enabled with the param_extension=1 module parameter, or boot @@ -181,6 +203,18 @@ You should see something like this in dmesg:: [22715.834759] EDAC sbridge MC3: PROCESSOR 0:306e7 TIME 1422553404 SOCKET 0 APIC 0 [22716.616173] EDAC MC3: 1 CE memory read error on CPU_SrcID#0_Channel#0_DIMM#0 (channel:0 slot:0 page:0x12345 offset:0x0 grain:32 syndrome:0x0 - area:DRAM err_code:0001:0090 socket:0 channel_mask:1 rank:0) +A CXL error injection example with $dport_dev=0000:e0:01.1:: + + # cd /sys/kernel/debug/cxl/ + # ls + 0000:e0:01.1 0000:0c:00.0 + # cat einj_types # See which errors can be injected + 0x00008000 CXL.mem Protocol Correctable + 0x00010000 CXL.mem Protocol Uncorrectable non-fatal + 0x00020000 CXL.mem Protocol Uncorrectable fatal + # cd 0000:e0:01.1 # Navigate to dport to inject into + # echo 0x8000 > einj_inject # Inject error + Special notes for injection into SGX enclaves: There may be a separate BIOS setup option to enable SGX injection. From 8039804cfa7314ad50085a779923aa5469889f88 Mon Sep 17 00:00:00 2001 From: Ben Cheatham Date: Mon, 11 Mar 2024 09:25:07 -0500 Subject: [PATCH 791/814] cxl/core: Add CXL EINJ debugfs files Export CXL helper functions in einj-cxl.c for getting/injecting available CXL protocol error types to sysfs under kernel/debug/cxl. The kernel/debug/cxl/einj_types file will print the available CXL protocol errors in the same format as the available_error_types file provided by the einj module. The kernel/debug/cxl/$dport_dev/einj_inject file is functionally the same as the error_type and error_inject files provided by the EINJ module, i.e.: writing an error type into $dport_dev/einj_inject will inject said error type into the CXL dport represented by $dport_dev. Reviewed-by: Jonathan Cameron Signed-off-by: Ben Cheatham Link: https://lore.kernel.org/r/20240311142508.31717-4-Benjamin.Cheatham@amd.com Signed-off-by: Dan Williams --- Documentation/ABI/testing/debugfs-cxl | 30 ++++++++++++++++++++ drivers/cxl/core/port.c | 41 +++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl index fe61d372e3fa..4c0f62f881ca 100644 --- a/Documentation/ABI/testing/debugfs-cxl +++ b/Documentation/ABI/testing/debugfs-cxl @@ -33,3 +33,33 @@ Description: device cannot clear poison from the address, -ENXIO is returned. The clear_poison attribute is only visible for devices supporting the capability. + +What: /sys/kernel/debug/cxl/einj_types +Date: January, 2024 +KernelVersion: v6.9 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) Prints the CXL protocol error types made available by + the platform in the format "0x ". + The possible error types are (as of ACPI v6.5): + 0x1000 CXL.cache Protocol Correctable + 0x2000 CXL.cache Protocol Uncorrectable non-fatal + 0x4000 CXL.cache Protocol Uncorrectable fatal + 0x8000 CXL.mem Protocol Correctable + 0x10000 CXL.mem Protocol Uncorrectable non-fatal + 0x20000 CXL.mem Protocol Uncorrectable fatal + + The can be written to einj_inject to inject + into a chosen dport. + +What: /sys/kernel/debug/cxl/$dport_dev/einj_inject +Date: January, 2024 +KernelVersion: v6.9 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) Writing an integer to this file injects the corresponding + CXL protocol error into $dport_dev ($dport_dev will be a device + name from /sys/bus/pci/devices). The integer to type mapping for + injection can be found by reading from einj_types. If the dport + was enumerated in RCH mode, a CXL 1.1 error is injected, otherwise + a CXL 2.0 error is injected. diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e59d9d37aa65..01e64b83a78c 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -793,6 +794,40 @@ static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport, return rc; } +DEFINE_SHOW_ATTRIBUTE(einj_cxl_available_error_type); + +static int cxl_einj_inject(void *data, u64 type) +{ + struct cxl_dport *dport = data; + + if (dport->rch) + return einj_cxl_inject_rch_error(dport->rcrb.base, type); + + return einj_cxl_inject_error(to_pci_dev(dport->dport_dev), type); +} +DEFINE_DEBUGFS_ATTRIBUTE(cxl_einj_inject_fops, NULL, cxl_einj_inject, + "0x%llx\n"); + +static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport) +{ + struct dentry *dir; + + if (!einj_cxl_is_initialized()) + return; + + /* + * dport_dev needs to be a PCIe port for CXL 2.0+ ports because + * EINJ expects a dport SBDF to be specified for 2.0 error injection. + */ + if (!dport->rch && !dev_is_pci(dport->dport_dev)) + return; + + dir = cxl_debugfs_create_dir(dev_name(dport->dport_dev)); + + debugfs_create_file("einj_inject", 0200, dir, dport, + &cxl_einj_inject_fops); +} + static struct cxl_port *__devm_cxl_add_port(struct device *host, struct device *uport_dev, resource_size_t component_reg_phys, @@ -1149,6 +1184,8 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, if (dev_is_pci(dport_dev)) dport->link_latency = cxl_pci_get_latency(to_pci_dev(dport_dev)); + cxl_debugfs_create_dport_dir(dport); + return dport; } @@ -2221,6 +2258,10 @@ static __init int cxl_core_init(void) cxl_debugfs = debugfs_create_dir("cxl", NULL); + if (einj_cxl_is_initialized()) + debugfs_create_file("einj_types", 0400, cxl_debugfs, NULL, + &einj_cxl_available_error_type_fops); + cxl_mbox_init(); rc = cxl_memdev_init(); From 99b52aac2d40203d0f6468325018f68e2c494c24 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 1 Mar 2024 14:09:48 -0700 Subject: [PATCH 792/814] cxl: Fix the incorrect assignment of SSLBIS entry pointer initial location The 'entry' pointer in cdat_sslbis_handler() is set to header + sizeof(common header). However, the math missed the addition of the SSLBIS main header. It should be header + sizeof(common header) + sizeof(*sslbis). Use a defined struct for all the SSLBIS parts in order to avoid pointer math errors. The bug causes incorrect parsing of the SSLBIS table and introduces incorrect performance values to the access_coordinates during the CXL access_coordinate calculation path if there are CXL switches present in the topology. The issue was found during testing of new code being added to add additional checks for invalid CDAT values during CXL access_coordinate calculation. The testing was done on qemu with a CXL topology including a CXL switch. Fixes: 80aa780dda20 ("cxl: Add callback to parse the SSLBIS subtable from CDAT") Signed-off-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Link: https://lore.kernel.org/r/20240301210948.1298075-1-dave.jiang@intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/cdat.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 08fd0baea7a0..0363ca434ef4 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -389,36 +389,38 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL); static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, const unsigned long end) { + struct acpi_cdat_sslbis_table { + struct acpi_cdat_header header; + struct acpi_cdat_sslbis sslbis_header; + struct acpi_cdat_sslbe entries[]; + } *tbl = (struct acpi_cdat_sslbis_table *)header; + int size = sizeof(header->cdat) + sizeof(tbl->sslbis_header); struct acpi_cdat_sslbis *sslbis; - int size = sizeof(header->cdat) + sizeof(*sslbis); struct cxl_port *port = arg; struct device *dev = &port->dev; - struct acpi_cdat_sslbe *entry; int remain, entries, i; u16 len; len = le16_to_cpu((__force __le16)header->cdat.length); remain = len - size; - if (!remain || remain % sizeof(*entry) || + if (!remain || remain % sizeof(tbl->entries[0]) || (unsigned long)header + len > end) { dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len); return -EINVAL; } - /* Skip common header */ - sslbis = (struct acpi_cdat_sslbis *)((unsigned long)header + - sizeof(header->cdat)); - + sslbis = &tbl->sslbis_header; /* Unrecognized data type, we can skip */ if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH) return 0; - entries = remain / sizeof(*entry); - entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis)); + entries = remain / sizeof(tbl->entries[0]); + if (struct_size(tbl, entries, entries) != len) + return -EINVAL; for (i = 0; i < entries; i++) { - u16 x = le16_to_cpu((__force __le16)entry->portx_id); - u16 y = le16_to_cpu((__force __le16)entry->porty_id); + u16 x = le16_to_cpu((__force __le16)tbl->entries[i].portx_id); + u16 y = le16_to_cpu((__force __le16)tbl->entries[i].porty_id); __le64 le_base; __le16 le_val; struct cxl_dport *dport; @@ -448,8 +450,8 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, break; } - le_base = (__force __le64)sslbis->entry_base_unit; - le_val = (__force __le16)entry->latency_or_bandwidth; + le_base = (__force __le64)tbl->sslbis_header.entry_base_unit; + le_val = (__force __le16)tbl->entries[i].latency_or_bandwidth; if (check_mul_overflow(le64_to_cpu(le_base), le16_to_cpu(le_val), &val)) @@ -462,8 +464,6 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, sslbis->data_type, val); } - - entry++; } return 0; From ec8ffff3a9f86435996f71299ce729126a7ac8a2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 16 Feb 2024 16:58:42 +0100 Subject: [PATCH 793/814] cxl/pci: Rename DOE mailbox handle to doe_mb Trivial variable rename for the DOE mailbox handle from cdat_doe to doe_mb. The variable name cdat_doe is too ambiguous, use doe_mb that is commonly used for the mailbox. Signed-off-by: Robert Richter Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240216155844.406996-2-rrichter@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/pci.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index e9e6c81ce034..c8214990c230 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -518,14 +518,14 @@ EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL); FIELD_PREP(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, (entry_handle))) static int cxl_cdat_get_length(struct device *dev, - struct pci_doe_mb *cdat_doe, + struct pci_doe_mb *doe_mb, size_t *length) { __le32 request = CDAT_DOE_REQ(0); __le32 response[2]; int rc; - rc = pci_doe(cdat_doe, PCI_DVSEC_VENDOR_ID_CXL, + rc = pci_doe(doe_mb, PCI_DVSEC_VENDOR_ID_CXL, CXL_DOE_PROTOCOL_TABLE_ACCESS, &request, sizeof(request), &response, sizeof(response)); @@ -543,7 +543,7 @@ static int cxl_cdat_get_length(struct device *dev, } static int cxl_cdat_read_table(struct device *dev, - struct pci_doe_mb *cdat_doe, + struct pci_doe_mb *doe_mb, void *cdat_table, size_t *cdat_length) { size_t length = *cdat_length + sizeof(__le32); @@ -557,7 +557,7 @@ static int cxl_cdat_read_table(struct device *dev, size_t entry_dw; int rc; - rc = pci_doe(cdat_doe, PCI_DVSEC_VENDOR_ID_CXL, + rc = pci_doe(doe_mb, PCI_DVSEC_VENDOR_ID_CXL, CXL_DOE_PROTOCOL_TABLE_ACCESS, &request, sizeof(request), data, length); @@ -617,7 +617,7 @@ void read_cdat_data(struct cxl_port *port) { struct device *uport = port->uport_dev; struct device *dev = &port->dev; - struct pci_doe_mb *cdat_doe; + struct pci_doe_mb *doe_mb; struct pci_dev *pdev = NULL; struct cxl_memdev *cxlmd; size_t cdat_length; @@ -638,16 +638,16 @@ void read_cdat_data(struct cxl_port *port) if (!pdev) return; - cdat_doe = pci_find_doe_mailbox(pdev, PCI_DVSEC_VENDOR_ID_CXL, - CXL_DOE_PROTOCOL_TABLE_ACCESS); - if (!cdat_doe) { + doe_mb = pci_find_doe_mailbox(pdev, PCI_DVSEC_VENDOR_ID_CXL, + CXL_DOE_PROTOCOL_TABLE_ACCESS); + if (!doe_mb) { dev_dbg(dev, "No CDAT mailbox\n"); return; } port->cdat_available = true; - if (cxl_cdat_get_length(dev, cdat_doe, &cdat_length)) { + if (cxl_cdat_get_length(dev, doe_mb, &cdat_length)) { dev_dbg(dev, "No CDAT length\n"); return; } @@ -656,7 +656,7 @@ void read_cdat_data(struct cxl_port *port) if (!cdat_buf) return; - rc = cxl_cdat_read_table(dev, cdat_doe, cdat_buf, &cdat_length); + rc = cxl_cdat_read_table(dev, doe_mb, cdat_buf, &cdat_length); if (rc) goto err; From e0c818e00443ce4a704519d85a21e3c14179e3a6 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 16 Feb 2024 16:58:43 +0100 Subject: [PATCH 794/814] cxl/pci: Get rid of pointer arithmetic reading CDAT table Reading the CDAT table using DOE requires a Table Access Response Header in addition to the CDAT entry. In current implementation this has caused offsets with sizeof(__le32) to the actual buffers. This led to hardly readable code and even bugs. E.g., see fix of devm_kfree() in read_cdat_data(): commit c65efe3685f5 ("cxl/cdat: Free correct buffer on checksum error") Rework code to avoid calculations with sizeof(__le32). Introduce struct cdat_doe_rsp for this which contains the Table Access Response Header and a variable payload size for various data structures afterwards to access the CDAT table and its CDAT Data Structures without recalculating buffer offsets. Cc: Lukas Wunner Cc: Fan Ni Reviewed-by: Dave Jiang Signed-off-by: Robert Richter Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240216155844.406996-3-rrichter@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/pci.c | 77 ++++++++++++++++++++++-------------------- drivers/cxl/cxlpci.h | 24 +++++++++++++ 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index c8214990c230..184deff887d0 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -544,55 +544,57 @@ static int cxl_cdat_get_length(struct device *dev, static int cxl_cdat_read_table(struct device *dev, struct pci_doe_mb *doe_mb, - void *cdat_table, size_t *cdat_length) + struct cdat_doe_rsp *rsp, size_t *length) { - size_t length = *cdat_length + sizeof(__le32); - __le32 *data = cdat_table; - int entry_handle = 0; + size_t received, remaining = *length; + unsigned int entry_handle = 0; + union cdat_data *data; __le32 saved_dw = 0; do { __le32 request = CDAT_DOE_REQ(entry_handle); - struct cdat_entry_header *entry; - size_t entry_dw; int rc; rc = pci_doe(doe_mb, PCI_DVSEC_VENDOR_ID_CXL, CXL_DOE_PROTOCOL_TABLE_ACCESS, &request, sizeof(request), - data, length); + rsp, sizeof(*rsp) + remaining); if (rc < 0) { dev_err(dev, "DOE failed: %d", rc); return rc; } - /* 1 DW Table Access Response Header + CDAT entry */ - entry = (struct cdat_entry_header *)(data + 1); - if ((entry_handle == 0 && - rc != sizeof(__le32) + sizeof(struct cdat_header)) || - (entry_handle > 0 && - (rc < sizeof(__le32) + sizeof(*entry) || - rc != sizeof(__le32) + le16_to_cpu(entry->length)))) + if (rc < sizeof(*rsp)) return -EIO; + data = (union cdat_data *)rsp->data; + received = rc - sizeof(*rsp); + + if (entry_handle == 0) { + if (received != sizeof(data->header)) + return -EIO; + } else { + if (received < sizeof(data->entry) || + received != le16_to_cpu(data->entry.length)) + return -EIO; + } + /* Get the CXL table access header entry handle */ entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, - le32_to_cpu(data[0])); - entry_dw = rc / sizeof(__le32); - /* Skip Header */ - entry_dw -= 1; + le32_to_cpu(rsp->doe_header)); + /* * Table Access Response Header overwrote the last DW of * previous entry, so restore that DW */ - *data = saved_dw; - length -= entry_dw * sizeof(__le32); - data += entry_dw; - saved_dw = *data; + rsp->doe_header = saved_dw; + remaining -= received; + rsp = (void *)rsp + received; + saved_dw = rsp->doe_header; } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY); /* Length in CDAT header may exceed concatenation of CDAT entries */ - *cdat_length -= length - sizeof(__le32); + *length -= remaining; return 0; } @@ -620,8 +622,8 @@ void read_cdat_data(struct cxl_port *port) struct pci_doe_mb *doe_mb; struct pci_dev *pdev = NULL; struct cxl_memdev *cxlmd; - size_t cdat_length; - void *cdat_table, *cdat_buf; + struct cdat_doe_rsp *buf; + size_t length; int rc; if (is_cxl_memdev(uport)) { @@ -647,30 +649,33 @@ void read_cdat_data(struct cxl_port *port) port->cdat_available = true; - if (cxl_cdat_get_length(dev, doe_mb, &cdat_length)) { + if (cxl_cdat_get_length(dev, doe_mb, &length)) { dev_dbg(dev, "No CDAT length\n"); return; } - cdat_buf = devm_kzalloc(dev, cdat_length + sizeof(__le32), GFP_KERNEL); - if (!cdat_buf) - return; + /* + * The begin of the CDAT buffer needs space for additional 4 + * bytes for the DOE header. Table data starts afterwards. + */ + buf = devm_kzalloc(dev, sizeof(*buf) + length, GFP_KERNEL); + if (!buf) + goto err; - rc = cxl_cdat_read_table(dev, doe_mb, cdat_buf, &cdat_length); + rc = cxl_cdat_read_table(dev, doe_mb, buf, &length); if (rc) goto err; - cdat_table = cdat_buf + sizeof(__le32); - if (cdat_checksum(cdat_table, cdat_length)) + if (cdat_checksum(buf->data, length)) goto err; - port->cdat.table = cdat_table; - port->cdat.length = cdat_length; - return; + port->cdat.table = buf->data; + port->cdat.length = length; + return; err: /* Don't leave table data allocated on error */ - devm_kfree(dev, cdat_buf); + devm_kfree(dev, buf); dev_err(dev, "Failed to read/validate CDAT.\n"); } EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL); diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index 711b05d9a370..93992a1c8eec 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -71,6 +71,15 @@ enum cxl_regloc_type { CXL_REGLOC_RBI_TYPES }; +/* + * Table Access DOE, CDAT Read Entry Response + * + * Spec refs: + * + * CXL 3.1 8.1.11, Table 8-14: Read Entry Response + * CDAT Specification 1.03: 2 CDAT Data Structures + */ + struct cdat_header { __le32 length; u8 revision; @@ -85,6 +94,21 @@ struct cdat_entry_header { __le16 length; } __packed; +/* + * The DOE CDAT read response contains a CDAT read entry (either the + * CDAT header or a structure). + */ +union cdat_data { + struct cdat_header header; + struct cdat_entry_header entry; +} __packed; + +/* There is an additional CDAT response header of 4 bytes. */ +struct cdat_doe_rsp { + __le32 doe_header; + u8 data[]; +} __packed; + /* * CXL v3.0 6.2.3 Table 6-4 * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits From c6c3187d66bc4e87086036266def4170742d7214 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sat, 17 Feb 2024 22:39:46 +0100 Subject: [PATCH 795/814] lib/firmware_table: Provide buffer length argument to cdat_table_parse() There exist card implementations with a CDAT table using a fixed size buffer, but with entries filled in that do not fill the whole table length size. Then, the last entry in the CDAT table may not mark the end of the CDAT table buffer specified by the length field in the CDAT header. It can be shorter with trailing unused (zero'ed) data. The actual table length is determined while reading all CDAT entries of the table with DOE. If the table is greater than expected (containing zero'ed trailing data), the CDAT parser fails with: [ 48.691717] Malformed DSMAS table length: (24:0) [ 48.702084] [CDAT:0x00] Invalid zero length [ 48.711460] cxl_port endpoint1: Failed to parse CDAT: -22 In addition, a check of the table buffer length is missing to prevent an out-of-bound access then parsing the CDAT table. Hardening code against device returning borked table. Fix that by providing an optional buffer length argument to acpi_parse_entries_array() that can be used by cdat_table_parse() to propagate the buffer size down to its users to check the buffer length. This also prevents a possible out-of-bound access mentioned. Add a check to warn about a malformed CDAT table length. Cc: Rafael J. Wysocki Cc: Len Brown Reviewed-by: Dave Jiang Signed-off-by: Robert Richter Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/ZdEnopFO0Tl3t2O1@rric.localdomain Signed-off-by: Dan Williams --- drivers/acpi/tables.c | 2 +- drivers/cxl/core/cdat.c | 6 +++--- drivers/cxl/core/pci.c | 8 +++++++- include/linux/fw_table.h | 4 +++- lib/fw_table.c | 15 ++++++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index b07f7d091d13..b976e5fc3fbc 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -253,7 +253,7 @@ int __init_or_acpilib acpi_table_parse_entries_array( count = acpi_parse_entries_array(id, table_size, (union fw_table_header *)table_header, - proc, proc_num, max_entries); + 0, proc, proc_num, max_entries); acpi_put_table(table_header); return count; diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index 08fd0baea7a0..c8737e480789 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -149,13 +149,13 @@ static int cxl_cdat_endpoint_process(struct cxl_port *port, int rc; rc = cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler, - dsmas_xa, port->cdat.table); + dsmas_xa, port->cdat.table, port->cdat.length); rc = cdat_table_parse_output(rc); if (rc) return rc; rc = cdat_table_parse(ACPI_CDAT_TYPE_DSLBIS, cdat_dslbis_handler, - dsmas_xa, port->cdat.table); + dsmas_xa, port->cdat.table, port->cdat.length); return cdat_table_parse_output(rc); } @@ -477,7 +477,7 @@ void cxl_switch_parse_cdat(struct cxl_port *port) return; rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler, - port, port->cdat.table); + port, port->cdat.table, port->cdat.length); rc = cdat_table_parse_output(rc); if (rc) dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc); diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 184deff887d0..0df09bd79408 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -623,7 +623,7 @@ void read_cdat_data(struct cxl_port *port) struct pci_dev *pdev = NULL; struct cxl_memdev *cxlmd; struct cdat_doe_rsp *buf; - size_t length; + size_t table_length, length; int rc; if (is_cxl_memdev(uport)) { @@ -662,10 +662,16 @@ void read_cdat_data(struct cxl_port *port) if (!buf) goto err; + table_length = length; + rc = cxl_cdat_read_table(dev, doe_mb, buf, &length); if (rc) goto err; + if (table_length != length) + dev_warn(dev, "Malformed CDAT table length (%zu:%zu), discarding trailing data\n", + table_length, length); + if (cdat_checksum(buf->data, length)) goto err; diff --git a/include/linux/fw_table.h b/include/linux/fw_table.h index 95421860397a..3ff4c277296f 100644 --- a/include/linux/fw_table.h +++ b/include/linux/fw_table.h @@ -40,12 +40,14 @@ union acpi_subtable_headers { int acpi_parse_entries_array(char *id, unsigned long table_size, union fw_table_header *table_header, + unsigned long max_length, struct acpi_subtable_proc *proc, int proc_num, unsigned int max_entries); int cdat_table_parse(enum acpi_cdat_type type, acpi_tbl_entry_handler_arg handler_arg, void *arg, - struct acpi_table_cdat *table_header); + struct acpi_table_cdat *table_header, + unsigned long length); /* CXL is the only non-ACPI consumer of the FIRMWARE_TABLE library */ #if IS_ENABLED(CONFIG_ACPI) && !IS_ENABLED(CONFIG_CXL_BUS) diff --git a/lib/fw_table.c b/lib/fw_table.c index c3569d2ba503..16291814450e 100644 --- a/lib/fw_table.c +++ b/lib/fw_table.c @@ -127,6 +127,7 @@ static __init_or_fwtbl_lib int call_handler(struct acpi_subtable_proc *proc, * * @id: table id (for debugging purposes) * @table_size: size of the root table + * @max_length: maximum size of the table (ignore if 0) * @table_header: where does the table start? * @proc: array of acpi_subtable_proc struct containing entry id * and associated handler with it @@ -148,18 +149,21 @@ static __init_or_fwtbl_lib int call_handler(struct acpi_subtable_proc *proc, int __init_or_fwtbl_lib acpi_parse_entries_array(char *id, unsigned long table_size, union fw_table_header *table_header, + unsigned long max_length, struct acpi_subtable_proc *proc, int proc_num, unsigned int max_entries) { - unsigned long table_end, subtable_len, entry_len; + unsigned long table_len, table_end, subtable_len, entry_len; struct acpi_subtable_entry entry; enum acpi_subtable_type type; int count = 0; int i; type = acpi_get_subtable_type(id); - table_end = (unsigned long)table_header + - acpi_table_get_length(type, table_header); + table_len = acpi_table_get_length(type, table_header); + if (max_length && max_length < table_len) + table_len = max_length; + table_end = (unsigned long)table_header + table_len; /* Parse all entries looking for a match. */ @@ -208,7 +212,8 @@ int __init_or_fwtbl_lib cdat_table_parse(enum acpi_cdat_type type, acpi_tbl_entry_handler_arg handler_arg, void *arg, - struct acpi_table_cdat *table_header) + struct acpi_table_cdat *table_header, + unsigned long length) { struct acpi_subtable_proc proc = { .id = type, @@ -222,6 +227,6 @@ cdat_table_parse(enum acpi_cdat_type type, return acpi_parse_entries_array(ACPI_SIG_CDAT, sizeof(struct acpi_table_cdat), (union fw_table_header *)table_header, - &proc, 1, 0); + length, &proc, 1, 0); } EXPORT_SYMBOL_FWTBL_LIB(cdat_table_parse); From 29297ffffb0bf388778bd4b581a43cee6929ae65 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Mon, 29 Jan 2024 16:36:25 +0530 Subject: [PATCH 796/814] perf/x86/amd/lbr: Discard erroneous branch entries The Revision Guide for AMD Family 19h Model 10-1Fh processors declares Erratum 1452 which states that non-branch entries may erroneously be recorded in the Last Branch Record (LBR) stack with the valid and spec bits set. Such entries can be recognized by inspecting bit 61 of the corresponding LastBranchStackToIp register. This bit is currently reserved but if found to be set, the associated branch entry should be discarded. Signed-off-by: Sandipan Das Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Link: https://bugzilla.kernel.org/attachment.cgi?id=305518 Link: https://lore.kernel.org/r/3ad2aa305f7396d41a40e3f054f740d464b16b7f.1706526029.git.sandipan.das@amd.com --- arch/x86/events/amd/lbr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/amd/lbr.c b/arch/x86/events/amd/lbr.c index eb31f850841a..4a1e600314d5 100644 --- a/arch/x86/events/amd/lbr.c +++ b/arch/x86/events/amd/lbr.c @@ -173,9 +173,11 @@ void amd_pmu_lbr_read(void) /* * Check if a branch has been logged; if valid = 0, spec = 0 - * then no branch was recorded + * then no branch was recorded; if reserved = 1 then an + * erroneous branch was recorded (see Erratum 1452) */ - if (!entry.to.split.valid && !entry.to.split.spec) + if ((!entry.to.split.valid && !entry.to.split.spec) || + entry.to.split.reserved) continue; perf_clear_branch_entry_bitfields(br + out); From ad8c91282c95f801c37812d59d2d9eba6899b384 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Mon, 29 Jan 2024 16:36:26 +0530 Subject: [PATCH 797/814] perf/x86/amd/core: Avoid register reset when CPU is dead When bringing a CPU online, some of the PMC and LBR related registers are reset. The same is done when a CPU is taken offline although that is unnecessary. This currently happens in the "cpu_dead" callback which is also incorrect as the callback runs on a control CPU instead of the one that is being taken offline. This also affects hibernation and suspend to RAM on some platforms as reported in the link below. Fixes: 21d59e3e2c40 ("perf/x86/amd/core: Detect PerfMonV2 support") Reported-by: Mario Limonciello Signed-off-by: Sandipan Das Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Link: https://lore.kernel.org/r/550a026764342cf7e5812680e3e2b91fe662b5ac.1706526029.git.sandipan.das@amd.com --- arch/x86/events/amd/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index 69a3b02e50bb..aec16e581f5b 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -604,7 +604,6 @@ static void amd_pmu_cpu_dead(int cpu) kfree(cpuhw->lbr_sel); cpuhw->lbr_sel = NULL; - amd_pmu_cpu_reset(cpu); if (!x86_pmu.amd_nb_constraints) return; From b874d4aae58b92144ec2c8fa5dc0a27c98388fcc Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 12 Mar 2024 15:58:41 -0600 Subject: [PATCH 798/814] block: limit block time caching to in_task() context We should not have any callers of this from non-task context, but Jakub ran [1] into one from blk-iocost. Rather than risk running into others, or future ones, just limit blk_time_get_ns() to when it is called from a task. Any other usage is invalid. [1] https://lore.kernel.org/lkml/CAHk-=wiOaBLqarS2uFhM1YdwOvCX4CZaWkeyNDY1zONpbYw2ig@mail.gmail.com/ Fixes: da4c8c3d0975 ("block: cache current nsec time in struct blk_plug") Reported-by: Jakub Kicinski Signed-off-by: Jens Axboe --- block/blk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk.h b/block/blk.h index a19b7b42e650..5cac4e29ae17 100644 --- a/block/blk.h +++ b/block/blk.h @@ -534,7 +534,7 @@ static inline u64 blk_time_get_ns(void) { struct blk_plug *plug = current->plug; - if (!plug) + if (!plug || !in_task()) return ktime_get_ns(); /* From 256aab46e31683d76d45ccbedc287b4d3f3e322b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 13 Mar 2024 14:42:18 -0700 Subject: [PATCH 799/814] Revert "block/mq-deadline: use correct way to throttling write requests" The code "max(1U, 3 * (1U << shift) / 4)" comes from the Kyber I/O scheduler. The Kyber I/O scheduler maintains one internal queue per hwq and hence derives its async_depth from the number of hwq tags. Using this approach for the mq-deadline scheduler is wrong since the mq-deadline scheduler maintains one internal queue for all hwqs combined. Hence this revert. Cc: stable@vger.kernel.org Cc: Damien Le Moal Cc: Harshit Mogalapalli Cc: Zhiguo Niu Fixes: d47f9717e5cf ("block/mq-deadline: use correct way to throttling write requests") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240313214218.1736147-1-bvanassche@acm.org Signed-off-by: Jens Axboe --- block/mq-deadline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/block/mq-deadline.c b/block/mq-deadline.c index f958e79277b8..02a916ba62ee 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -646,9 +646,8 @@ static void dd_depth_updated(struct blk_mq_hw_ctx *hctx) struct request_queue *q = hctx->queue; struct deadline_data *dd = q->elevator->elevator_data; struct blk_mq_tags *tags = hctx->sched_tags; - unsigned int shift = tags->bitmap_tags.sb.shift; - dd->async_depth = max(1U, 3 * (1U << shift) / 4); + dd->async_depth = max(1UL, 3 * q->nr_requests / 4); sbitmap_queue_min_shallow_depth(&tags->bitmap_tags, dd->async_depth); } From 9448e55d032d99af8e23487f51a542d51b2f1a48 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Feb 2024 14:27:11 +0000 Subject: [PATCH 800/814] of: Add cleanup.h based auto release via __free(device_node) markings The recent addition of scope based cleanup support to the kernel provides a convenient tool to reduce the chances of leaking reference counts where of_node_put() should have been called in an error path. This enables struct device_node *child __free(device_node) = NULL; for_each_child_of_node(np, child) { if (test) return test; } with no need for a manual call of of_node_put(). A following patch will reduce the scope of the child variable to the for loop, to avoid an issues with ordering of autocleanup, and make it obvious when this assigned a non NULL value. In this simple example the gains are small but there are some very complex error handling cases buried in these loops that will be greatly simplified by enabling early returns with out the need for this manual of_node_put() call. Note that there are coccinelle checks in scripts/coccinelle/iterators/for_each_child.cocci to detect a failure to call of_node_put(). This new approach does not cause false positives. Longer term we may want to add scripting to check this new approach is done correctly with no double of_node_put() calls being introduced due to the auto cleanup. It may also be useful to script finding places this new approach is useful. Signed-off-by: Jonathan Cameron Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240225142714.286440-2-jic23@kernel.org Signed-off-by: Rob Herring --- include/linux/of.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/of.h b/include/linux/of.h index d5e7acdc8c8e..2992e24cd72b 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -13,6 +13,7 @@ */ #include #include +#include #include #include #include @@ -134,6 +135,7 @@ static inline struct device_node *of_node_get(struct device_node *node) } static inline void of_node_put(struct device_node *node) { } #endif /* !CONFIG_OF_DYNAMIC */ +DEFINE_FREE(device_node, struct device_node *, if (_T) of_node_put(_T)) /* Pointer for first entry in chain of all nodes. */ extern struct device_node *of_root; From 34af4554fb0ce164e2c4876683619eb1e23848d4 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Feb 2024 14:27:12 +0000 Subject: [PATCH 801/814] of: Introduce for_each_*_child_of_node_scoped() to automate of_node_put() handling To avoid issues with out of order cleanup, or ambiguity about when the auto freed data is first instantiated, do it within the for loop definition. The disadvantage is that the struct device_node *child variable creation is not immediately obvious where this is used. However, in many cases, if there is another definition of struct device_node *child; the compiler / static analysers will notify us that it is unused, or uninitialized. Note that, in the vast majority of cases, the _available_ form should be used and as code is converted to these scoped handers, we should confirm that any cases that do not check for available have a good reason not to. Signed-off-by: Jonathan Cameron Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240225142714.286440-3-jic23@kernel.org Signed-off-by: Rob Herring --- include/linux/of.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/of.h b/include/linux/of.h index 2992e24cd72b..4677e50d52b7 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -1420,10 +1420,23 @@ static inline int of_property_read_s32(const struct device_node *np, #define for_each_child_of_node(parent, child) \ for (child = of_get_next_child(parent, NULL); child != NULL; \ child = of_get_next_child(parent, child)) + +#define for_each_child_of_node_scoped(parent, child) \ + for (struct device_node *child __free(device_node) = \ + of_get_next_child(parent, NULL); \ + child != NULL; \ + child = of_get_next_child(parent, child)) + #define for_each_available_child_of_node(parent, child) \ for (child = of_get_next_available_child(parent, NULL); child != NULL; \ child = of_get_next_available_child(parent, child)) +#define for_each_available_child_of_node_scoped(parent, child) \ + for (struct device_node *child __free(device_node) = \ + of_get_next_available_child(parent, NULL); \ + child != NULL; \ + child = of_get_next_available_child(parent, child)) + #define for_each_of_cpu_node(cpu) \ for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \ cpu = of_get_next_cpu_node(cpu)) From 2056b282ad191589e4ceb5a8fdab639b9549edc6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Feb 2024 14:27:13 +0000 Subject: [PATCH 802/814] of: unittest: Use for_each_child_of_node_scoped() A simple example of the utility of this autocleanup approach to handling of_node_put(). In this particular case some of the nodes needed for the test are not available and the _available_ version would cause them to be skipped resulting in a test failure. Signed-off-by: Jonathan Cameron Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240225142714.286440-4-jic23@kernel.org Signed-off-by: Rob Herring --- drivers/of/unittest.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 4c67de37bf26..0913d916e790 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -233,27 +233,22 @@ static void __init of_unittest_dynamic(void) static int __init of_unittest_check_node_linkage(struct device_node *np) { - struct device_node *child; int count = 0, rc; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (child->parent != np) { pr_err("Child node %pOFn links to wrong parent %pOFn\n", child, np); - rc = -EINVAL; - goto put_child; + return -EINVAL; } rc = of_unittest_check_node_linkage(child); if (rc < 0) - goto put_child; + return rc; count += rc; } return count + 1; -put_child: - of_node_put(child); - return rc; } static void __init of_unittest_check_tree_linkage(void) From bf5e3a30f777b6e763f6a46c10e1250c20237e97 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Mar 2024 19:16:23 -0700 Subject: [PATCH 803/814] Revert "blk-lib: check for kill signal" This reverts commit 8a08c5fd89b447a7de7eb293a7a274c46b932ba2. It turns out while this is a perfectly valid and long overdue thing to do for user initiated discards / zeroing from the ioctl handler, it actually breaks file system use of the discard helper by interrupting in places the file system doesn't expect, and by leaving the bio chain in a state that the file system callers of (at least) __blkdev_issue_discard do not expect. Revert the change for now, we'll redo it for the next merge window after refactoring the code to better split the file system vs ioctl callers and cleaning up a few other loose ends. Reported-by: Chandan Babu R Signed-off-by: Christoph Hellwig Acked-by: Keith Busch Link: https://lore.kernel.org/r/20240314021623.1908895-1-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-lib.c | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index dc8e35d0a51d..a6954eafb8c8 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -35,26 +35,6 @@ static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector) return round_down(UINT_MAX, discard_granularity) >> SECTOR_SHIFT; } -static void await_bio_endio(struct bio *bio) -{ - complete(bio->bi_private); - bio_put(bio); -} - -/* - * await_bio_chain - ends @bio and waits for every chained bio to complete - */ -static void await_bio_chain(struct bio *bio) -{ - DECLARE_COMPLETION_ONSTACK_MAP(done, - bio->bi_bdev->bd_disk->lockdep_map); - - bio->bi_private = &done; - bio->bi_end_io = await_bio_endio; - bio_endio(bio); - blk_wait_io(&done); -} - int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct bio **biop) { @@ -97,10 +77,6 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, * is disabled. */ cond_resched(); - if (fatal_signal_pending(current)) { - await_bio_chain(bio); - return -EINTR; - } } *biop = bio; @@ -167,10 +143,6 @@ static int __blkdev_issue_write_zeroes(struct block_device *bdev, nr_sects -= len; sector += len; cond_resched(); - if (fatal_signal_pending(current)) { - await_bio_chain(bio); - return -EINTR; - } } *biop = bio; @@ -215,10 +187,6 @@ static int __blkdev_issue_zero_pages(struct block_device *bdev, break; } cond_resched(); - if (fatal_signal_pending(current)) { - await_bio_chain(bio); - return -EINTR; - } } *biop = bio; @@ -309,7 +277,7 @@ retry: bio_put(bio); } blk_finish_plug(&plug); - if (ret && ret != -EINTR && try_write_zeroes) { + if (ret && try_write_zeroes) { if (!(flags & BLKDEV_ZERO_NOFALLBACK)) { try_write_zeroes = false; goto retry; @@ -361,12 +329,6 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector, sector += len; nr_sects -= len; cond_resched(); - if (fatal_signal_pending(current)) { - await_bio_chain(bio); - ret = -EINTR; - bio = NULL; - break; - } } if (bio) { ret = submit_bio_wait(bio); From 4c4ab8ae416350ce817339f239bdaaf351212f15 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 14 Mar 2024 10:56:15 +0800 Subject: [PATCH 804/814] block: fix mismatched kerneldoc function name No functional modification involved. block/blk-settings.c:281: warning: expecting prototype for queue_limits_commit_set(). Prototype was for queue_limits_set() instead. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8539 Signed-off-by: Jiapeng Chong Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20240314025615.71269-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Jens Axboe --- block/blk-settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index e160d56e8eda..3c7d8d638ab5 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -267,7 +267,7 @@ int queue_limits_commit_update(struct request_queue *q, EXPORT_SYMBOL_GPL(queue_limits_commit_update); /** - * queue_limits_commit_set - apply queue limits to queue + * queue_limits_set - apply queue limits to queue * @q: queue to update * @lim: limits to apply * From edc1243437e75ea019ba264d38b2cd793ae83ed0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 14 Mar 2024 17:34:26 -0700 Subject: [PATCH 805/814] Documentation/ABI/testing/debugfs-cxl: Fix "Unexpected indentation" Stephen reported that an htmldocs build hit: Documentation/ABI/testing/debugfs-cxl:38: ERROR: Unexpected indentation. It turns out that line was fine but the tool was unhappy about some line breaks in the table of values to error types. It turns out that: make V=1 SPHINXDIRS="admin-guide" htmldocs ...can not be used to get more info about what is behind a documentation build error. It was only pure luck that reflowing the text resulted in an error message that seemed a imply a problem later on with line breaks around the table. Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files") Cc: Jonathan Corbet Reported-by: Stephen Rothwell Closes: http://lore.kernel.org/r/20240314141313.7ba04aff@canb.auug.org.au Cc: Ben Cheatham Signed-off-by: Dan Williams --- Documentation/ABI/testing/debugfs-cxl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl index 4c0f62f881ca..c61f9b813973 100644 --- a/Documentation/ABI/testing/debugfs-cxl +++ b/Documentation/ABI/testing/debugfs-cxl @@ -40,8 +40,12 @@ KernelVersion: v6.9 Contact: linux-cxl@vger.kernel.org Description: (RO) Prints the CXL protocol error types made available by - the platform in the format "0x ". + the platform in the format: + + 0x + The possible error types are (as of ACPI v6.5): + 0x1000 CXL.cache Protocol Correctable 0x2000 CXL.cache Protocol Uncorrectable non-fatal 0x4000 CXL.cache Protocol Uncorrectable fatal From 4781179012d9380005649b0fe07f77dcaa2610e3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 15 Mar 2024 06:52:55 -0400 Subject: [PATCH 806/814] selftests: kvm: remove meaningless assignments in Makefiles $(shell ...) expands to the output of the command. It expands to the empty string when the command does not print anything to stdout. Hence, $(shell mkdir ...) is sufficient and does not need any variable assignment in front of it. Commit c2bd08ba20a5 ("treewide: remove meaningless assignments in Makefiles", 2024-02-23) did this to all of tools/ but ignored in-flight changes to tools/testing/selftests/kvm/Makefile, so reapply the change. Cc: Masahiro Yamada Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 19f5710bb456..741c7dc16afc 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -277,7 +277,7 @@ TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBKVM_OBJS)) TEST_DEP_FILES += $(patsubst %.o, %.d, $(SPLIT_TEST_GEN_OBJ)) -include $(TEST_DEP_FILES) -x := $(shell mkdir -p $(sort $(OUTPUT)/$(ARCH_DIR) $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)))) +$(shell mkdir -p $(sort $(OUTPUT)/$(ARCH_DIR) $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)))) $(filter-out $(SPLIT_TEST_GEN_PROGS), $(TEST_GEN_PROGS)) \ $(TEST_GEN_PROGS_EXTENDED): %: %.o @@ -309,7 +309,7 @@ $(LIBKVM_S_OBJ): $(OUTPUT)/%.o: %.S $(GEN_HDRS) $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@ -x := $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS)))) +$(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS)))) $(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS) $(TEST_GEN_PROGS): $(LIBKVM_OBJS) $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS) From 7e98fe49f8896cc60c2a88c60bc535aa3e0e2564 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 14 Mar 2024 15:59:53 +0100 Subject: [PATCH 807/814] dt-bindings: soc: imx: fsl,imx-anatop: add imx6q regulators imx6q has additional regulators compared to imx6ul. Add them to the list of allowed patterns. Signed-off-by: Alexander Stein Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240314145953.2957313-1-alexander.stein@ew.tq-group.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml index 5a59e3470510..c4ae4f28422b 100644 --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml @@ -43,7 +43,7 @@ properties: $ref: /schemas/thermal/imx-thermal.yaml patternProperties: - "regulator-((3p0)|(vddcore)|(vddsoc))$": + "regulator-((1p1)|(2p5)|(3p0)|(vddcore)|(vddpu)|(vddsoc))$": type: object unevaluatedProperties: false $ref: /schemas/regulator/anatop-regulator.yaml From b3810c5a2cc4a6665f7a65bed5393c75ce3f3aa2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 15 Mar 2024 16:26:16 +0100 Subject: [PATCH 808/814] x86/efistub: Clear decompressor BSS in native EFI entrypoint The EFI stub on x86 no longer invokes the decompressor as a subsequent boot stage, but calls into the decompression code directly while running in the context of the EFI boot services. This means that when using the native EFI entrypoint (as opposed to the EFI handover protocol, which clears BSS explicitly), the firmware PE image loader is being relied upon to ensure that BSS is zeroed before the EFI stub is entered from the firmware. As Radek's report proves, this is a bad idea. Not all loaders do this correctly, which means some global variables that should be statically initialized to 0x0 may have junk in them. So clear BSS explicitly when entering via efi_pe_entry(). Note that zeroing BSS from C code is not generally safe, but in this case, the following assignment and dereference of a global pointer variable ensures that the memset() cannot be deferred or reordered. Cc: # v6.1+ Reported-by: Radek Podgorny Closes: https://lore.kernel.org/all/a99a831a-8ad5-4cb0-bff9-be637311f771@podgorny.cz Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/x86-stub.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index 35413c8dfc25..2096ae09438e 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -21,6 +21,8 @@ #include "efistub.h" #include "x86-stub.h" +extern char _bss[], _ebss[]; + const efi_system_table_t *efi_system_table; const efi_dxe_services_table_t *efi_dxe_table; static efi_loaded_image_t *image = NULL; @@ -474,6 +476,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, efi_status_t status; char *cmdline_ptr; + memset(_bss, 0, _ebss - _bss); + efi_system_table = sys_table_arg; /* Check if we were booted by the EFI firmware */ @@ -967,8 +971,6 @@ fail: void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, struct boot_params *boot_params) { - extern char _bss[], _ebss[]; - memset(_bss, 0, _ebss - _bss); efi_stub_entry(handle, sys_table_arg, boot_params); } From 0883f1d89d7827efea6c11c1d821a2166c0eda35 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 12 Mar 2024 19:30:01 +0100 Subject: [PATCH 809/814] dt-bindings: input: samsung,s3c6410-keypad: convert to DT Schema Convert Samsung SoC Keypad bindings to DT schema with changes: 1. Rename "linux,keypad-no-autorepeat" property to "linux,input-no-autorepeat", because the latter was implemented in the Linux driver. 2. Add clocks and clock-names, already used by DTS and the Linux driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240312183001.714626-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- .../input/samsung,s3c6410-keypad.yaml | 121 ++++++++++++++++++ .../bindings/input/samsung-keypad.txt | 77 ----------- .../bindings/power/wakeup-source.txt | 2 +- 3 files changed, 122 insertions(+), 78 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml delete mode 100644 Documentation/devicetree/bindings/input/samsung-keypad.txt diff --git a/Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml b/Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml new file mode 100644 index 000000000000..a53569aa0ee7 --- /dev/null +++ b/Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/samsung,s3c6410-keypad.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung SoC series Keypad Controller + +description: + Samsung SoC Keypad controller is used to interface a SoC with a matrix-type + keypad device. The keypad controller supports multiple row and column lines. + A key can be placed at each intersection of a unique row and a unique column. + The keypad controller can sense a key-press and key-release and report the + event using a interrupt to the cpu. + +maintainers: + - Krzysztof Kozlowski + +properties: + compatible: + enum: + - samsung,s3c6410-keypad + - samsung,s5pv210-keypad + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: keypad + + interrupts: + maxItems: 1 + + wakeup-source: true + + linux,input-no-autorepeat: + type: boolean + description: + Do no enable autorepeat feature. + + linux,input-wakeup: + type: boolean + deprecated: true + + samsung,keypad-num-columns: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of column lines connected to the keypad controller. + + samsung,keypad-num-rows: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of row lines connected to the keypad controller. + +patternProperties: + '^key-[0-9a-z]+$': + type: object + $ref: input.yaml# + additionalProperties: false + description: + Each key connected to the keypad controller is represented as a child + node to the keypad controller device node. + + properties: + keypad,column: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The column number to which the key is connected. + + keypad,row: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The row number to which the key is connected. + + linux,code: true + + required: + - keypad,column + - keypad,row + - linux,code + +required: + - compatible + - reg + - interrupts + - samsung,keypad-num-columns + - samsung,keypad-num-rows + +additionalProperties: false + +examples: + - | + #include + #include + + keypad@100a0000 { + compatible = "samsung,s5pv210-keypad"; + reg = <0x100a0000 0x100>; + interrupts = ; + clocks = <&clock CLK_KEYIF>; + clock-names = "keypad"; + + samsung,keypad-num-rows = <2>; + samsung,keypad-num-columns = <8>; + linux,input-no-autorepeat; + wakeup-source; + + key-1 { + keypad,row = <0>; + keypad,column = <3>; + linux,code = <2>; + }; + + key-2 { + keypad,row = <0>; + keypad,column = <4>; + linux,code = <3>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt deleted file mode 100644 index 4c5c0a82586d..000000000000 --- a/Documentation/devicetree/bindings/input/samsung-keypad.txt +++ /dev/null @@ -1,77 +0,0 @@ -* Samsung's Keypad Controller device tree bindings - -Samsung's Keypad controller is used to interface a SoC with a matrix-type -keypad device. The keypad controller supports multiple row and column lines. -A key can be placed at each intersection of a unique row and a unique column. -The keypad controller can sense a key-press and key-release and report the -event using a interrupt to the cpu. - -Required SoC Specific Properties: -- compatible: should be one of the following - - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad - controller. - - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad - controller. - -- reg: physical base address of the controller and length of memory mapped - region. - -- interrupts: The interrupt number to the cpu. - -Required Board Specific Properties: -- samsung,keypad-num-rows: Number of row lines connected to the keypad - controller. - -- samsung,keypad-num-columns: Number of column lines connected to the - keypad controller. - -- Keys represented as child nodes: Each key connected to the keypad - controller is represented as a child node to the keypad controller - device node and should include the following properties. - - keypad,row: the row number to which the key is connected. - - keypad,column: the column number to which the key is connected. - - linux,code: the key-code to be reported when the key is pressed - and released. - -- pinctrl-0: Should specify pin control groups used for this controller. -- pinctrl-names: Should contain only one value - "default". - -Optional Properties: -- wakeup-source: use any event on keypad as wakeup event. - (Legacy property supported: "linux,input-wakeup") - -Optional Properties specific to linux: -- linux,keypad-no-autorepeat: do no enable autorepeat feature. - - -Example: - keypad@100a0000 { - compatible = "samsung,s5pv210-keypad"; - reg = <0x100A0000 0x100>; - interrupts = <173>; - samsung,keypad-num-rows = <2>; - samsung,keypad-num-columns = <8>; - linux,input-no-autorepeat; - wakeup-source; - - pinctrl-names = "default"; - pinctrl-0 = <&keypad_rows &keypad_columns>; - - key_1 { - keypad,row = <0>; - keypad,column = <3>; - linux,code = <2>; - }; - - key_2 { - keypad,row = <0>; - keypad,column = <4>; - linux,code = <3>; - }; - - key_3 { - keypad,row = <0>; - keypad,column = <5>; - linux,code = <4>; - }; - }; diff --git a/Documentation/devicetree/bindings/power/wakeup-source.txt b/Documentation/devicetree/bindings/power/wakeup-source.txt index 697333a56d5e..6baa200548df 100644 --- a/Documentation/devicetree/bindings/power/wakeup-source.txt +++ b/Documentation/devicetree/bindings/power/wakeup-source.txt @@ -23,7 +23,7 @@ List of legacy properties and respective binding document Documentation/devicetree/bindings/mfd/tc3589x.txt Documentation/devicetree/bindings/input/touchscreen/ads7846.txt 4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt -5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt +5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml 6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt Examples From 81c32343d04f8ca974681d5fb5d939d2e1f58851 Mon Sep 17 00:00:00 2001 From: Matt Scialabba Date: Fri, 15 Mar 2024 11:56:19 -0700 Subject: [PATCH 810/814] Input: xpad - add support for Snakebyte GAMEPADs Add Snakebyte GAMEPAD BASE X and Snakebyte GAMEPAD RGB X to the list of supported devices. Signed-off-by: Matt Scialabba Link: https://lore.kernel.org/r/efbfb428-06b0-48f9-8701-db291c2a9d65@app.fastmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 153c561c6e0e..1697ff90fe10 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -357,6 +357,8 @@ static const struct xpad_device { { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, + { 0x294b, 0x3303, "Snakebyte GAMEPAD BASE X", 0, XTYPE_XBOXONE }, + { 0x294b, 0x3404, "Snakebyte GAMEPAD RGB X", 0, XTYPE_XBOXONE }, { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, @@ -499,6 +501,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA controllers */ XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ + XPAD_XBOXONE_VENDOR(0x294b), /* Snakebyte */ XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ From 82affc97affbdfe83c807ad17147a1220031fd90 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Sat, 16 Mar 2024 00:24:57 +0000 Subject: [PATCH 811/814] Revert "KVM: arm64: Snapshot all non-zero RES0/RES1 sysreg fields for later checking" This reverts commits 99101dda29e3186b1356b0dc4dbb835c02c71ac9 and b80b701d5a67d07f4df4a21e09cb31f6bc1feeca. Linus reports that the sysreg reserved bit checks in KVM have led to build failures, arising from commit fdd867fe9b32 ("arm64/sysreg: Add register fields for ID_AA64DFR1_EL1") giving meaning to fields that were previously RES0. Of course, this is a genuine issue, since KVM's sysreg emulation depends heavily on the definition of reserved fields. But at this point the build breakage is far more offensive, and the right course of action is to revert and retry later. All of these build-time assertions were on by default before commit 99101dda29e3 ("KVM: arm64: Make build-time check of RES0/RES1 bits optional"), so deliberately revert it all atomically to avoid introducing further breakage of bisection. Link: https://lore.kernel.org/all/CAHk-=whCvkhc8BbFOUf1ddOsgSGgEjwoKv77=HEY1UiVCydGqw@mail.gmail.com/ Acked-by: Marc Zyngier Signed-off-by: Oliver Upton Signed-off-by: Linus Torvalds --- arch/arm64/kvm/Kconfig | 11 --- arch/arm64/kvm/check-res-bits.h | 125 -------------------------------- arch/arm64/kvm/sys_regs.c | 3 - 3 files changed, 139 deletions(-) delete mode 100644 arch/arm64/kvm/check-res-bits.h diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 937f15b7d8c3..58f09370d17e 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -65,15 +65,4 @@ config PROTECTED_NVHE_STACKTRACE If unsure, or not using protected nVHE (pKVM), say N. -config KVM_ARM64_RES_BITS_PARANOIA - bool "Build-time check of RES0/RES1 bits" - depends on KVM - default n - help - Say Y here to validate that KVM's knowledge of most system - registers' RES0/RES1 bits matches when the rest of the kernel - defines. Expect the build to fail badly if you enable this. - - Just say N. - endif # VIRTUALIZATION diff --git a/arch/arm64/kvm/check-res-bits.h b/arch/arm64/kvm/check-res-bits.h deleted file mode 100644 index 2d98e60efc3c..000000000000 --- a/arch/arm64/kvm/check-res-bits.h +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2024 - Google LLC - * Author: Marc Zyngier - */ - -#include - -/* - * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - * - * If any of these BUILD_BUG_ON() fails, that's because some bits that - * were reserved have gained some other meaning, and KVM needs to know - * about those. - * - * In such case, do *NOT* blindly change the assertion so that it - * passes, but also teach the rest of the code about the actual - * change. - * - * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - */ -static inline void check_res_bits(void) -{ -#ifdef CONFIG_KVM_ARM64_RES_BITS_PARANOIA - - BUILD_BUG_ON(OSDTRRX_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(MDCCINT_EL1_RES0 != (GENMASK_ULL(63, 31) | GENMASK_ULL(28, 0))); - BUILD_BUG_ON(MDSCR_EL1_RES0 != (GENMASK_ULL(63, 36) | GENMASK_ULL(28, 28) | GENMASK_ULL(25, 24) | GENMASK_ULL(20, 20) | GENMASK_ULL(18, 16) | GENMASK_ULL(11, 7) | GENMASK_ULL(5, 1))); - BUILD_BUG_ON(OSDTRTX_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(OSECCR_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(OSLAR_EL1_RES0 != (GENMASK_ULL(63, 1))); - BUILD_BUG_ON(ID_PFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_PFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_DFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_AFR0_EL1_RES0 != (GENMASK_ULL(63, 16))); - BUILD_BUG_ON(ID_MMFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_MMFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_MMFR2_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_MMFR3_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_ISAR0_EL1_RES0 != (GENMASK_ULL(63, 28))); - BUILD_BUG_ON(ID_ISAR1_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_ISAR2_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_ISAR3_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_ISAR4_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_ISAR5_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(23, 20))); - BUILD_BUG_ON(ID_ISAR6_EL1_RES0 != (GENMASK_ULL(63, 28))); - BUILD_BUG_ON(ID_MMFR4_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(MVFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(MVFR1_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(MVFR2_EL1_RES0 != (GENMASK_ULL(63, 8))); - BUILD_BUG_ON(ID_PFR2_EL1_RES0 != (GENMASK_ULL(63, 12))); - BUILD_BUG_ON(ID_DFR1_EL1_RES0 != (GENMASK_ULL(63, 8))); - BUILD_BUG_ON(ID_MMFR5_EL1_RES0 != (GENMASK_ULL(63, 8))); - BUILD_BUG_ON(ID_AA64PFR1_EL1_RES0 != (GENMASK_ULL(23, 20))); - BUILD_BUG_ON(ID_AA64PFR2_EL1_RES0 != (GENMASK_ULL(63, 36) | GENMASK_ULL(31, 12))); - BUILD_BUG_ON(ID_AA64ZFR0_EL1_RES0 != (GENMASK_ULL(63, 60) | GENMASK_ULL(51, 48) | GENMASK_ULL(39, 36) | GENMASK_ULL(31, 28) | GENMASK_ULL(15, 8))); - BUILD_BUG_ON(ID_AA64SMFR0_EL1_RES0 != (GENMASK_ULL(62, 61) | GENMASK_ULL(51, 49) | GENMASK_ULL(31, 31) | GENMASK_ULL(27, 0))); - BUILD_BUG_ON(ID_AA64FPFR0_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 2))); - BUILD_BUG_ON(ID_AA64DFR0_EL1_RES0 != (GENMASK_ULL(27, 24) | GENMASK_ULL(19, 16))); - BUILD_BUG_ON(ID_AA64DFR1_EL1_RES0 != (GENMASK_ULL(63, 0))); - BUILD_BUG_ON(ID_AA64AFR0_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(ID_AA64AFR1_EL1_RES0 != (GENMASK_ULL(63, 0))); - BUILD_BUG_ON(ID_AA64ISAR0_EL1_RES0 != (GENMASK_ULL(3, 0))); - BUILD_BUG_ON(ID_AA64ISAR2_EL1_RES0 != (GENMASK_ULL(47, 44))); - BUILD_BUG_ON(ID_AA64ISAR3_EL1_RES0 != (GENMASK_ULL(63, 16))); - BUILD_BUG_ON(ID_AA64MMFR0_EL1_RES0 != (GENMASK_ULL(55, 48))); - BUILD_BUG_ON(ID_AA64MMFR2_EL1_RES0 != (GENMASK_ULL(47, 44))); - BUILD_BUG_ON(ID_AA64MMFR3_EL1_RES0 != (GENMASK_ULL(51, 48))); - BUILD_BUG_ON(ID_AA64MMFR4_EL1_RES0 != (GENMASK_ULL(63, 40) | GENMASK_ULL(35, 28) | GENMASK_ULL(3, 0))); - BUILD_BUG_ON(SCTLR_EL1_RES0 != (GENMASK_ULL(17, 17))); - BUILD_BUG_ON(CPACR_ELx_RES0 != (GENMASK_ULL(63, 30) | GENMASK_ULL(27, 26) | GENMASK_ULL(23, 22) | GENMASK_ULL(19, 18) | GENMASK_ULL(15, 0))); - BUILD_BUG_ON(SMPRI_EL1_RES0 != (GENMASK_ULL(63, 4))); - BUILD_BUG_ON(ZCR_ELx_RES0 != (GENMASK_ULL(63, 9))); - BUILD_BUG_ON(SMCR_ELx_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(29, 9))); - BUILD_BUG_ON(GCSCR_ELx_RES0 != (GENMASK_ULL(63, 10) | GENMASK_ULL(7, 7) | GENMASK_ULL(4, 1))); - BUILD_BUG_ON(GCSPR_ELx_RES0 != (GENMASK_ULL(2, 0))); - BUILD_BUG_ON(GCSCRE0_EL1_RES0 != (GENMASK_ULL(63, 11) | GENMASK_ULL(7, 6) | GENMASK_ULL(4, 1))); - BUILD_BUG_ON(ALLINT_RES0 != (GENMASK_ULL(63, 14) | GENMASK_ULL(12, 0))); - BUILD_BUG_ON(PMSCR_EL1_RES0 != (GENMASK_ULL(63, 8) | GENMASK_ULL(2, 2))); - BUILD_BUG_ON(PMSICR_EL1_RES0 != (GENMASK_ULL(55, 32))); - BUILD_BUG_ON(PMSIRR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(7, 1))); - BUILD_BUG_ON(PMSFCR_EL1_RES0 != (GENMASK_ULL(63, 19) | GENMASK_ULL(15, 4))); - BUILD_BUG_ON(PMSLATFR_EL1_RES0 != (GENMASK_ULL(63, 16))); - BUILD_BUG_ON(PMSIDR_EL1_RES0 != (GENMASK_ULL(63, 25) | GENMASK_ULL(7, 7))); - BUILD_BUG_ON(PMBLIMITR_EL1_RES0 != (GENMASK_ULL(11, 6) | GENMASK_ULL(4, 3))); - BUILD_BUG_ON(PMBSR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(25, 20))); - BUILD_BUG_ON(PMBIDR_EL1_RES0 != (GENMASK_ULL(63, 12) | GENMASK_ULL(7, 6))); - BUILD_BUG_ON(CONTEXTIDR_ELx_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(CCSIDR_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(CLIDR_EL1_RES0 != (GENMASK_ULL(63, 47))); - BUILD_BUG_ON(CCSIDR2_EL1_RES0 != (GENMASK_ULL(63, 24))); - BUILD_BUG_ON(GMID_EL1_RES0 != (GENMASK_ULL(63, 4))); - BUILD_BUG_ON(SMIDR_EL1_RES0 != (GENMASK_ULL(63, 32) | GENMASK_ULL(14, 12))); - BUILD_BUG_ON(CSSELR_EL1_RES0 != (GENMASK_ULL(63, 5))); - BUILD_BUG_ON(CTR_EL0_RES0 != (GENMASK_ULL(63, 38) | GENMASK_ULL(30, 30) | GENMASK_ULL(13, 4))); - BUILD_BUG_ON(CTR_EL0_RES1 != (GENMASK_ULL(31, 31))); - BUILD_BUG_ON(DCZID_EL0_RES0 != (GENMASK_ULL(63, 5))); - BUILD_BUG_ON(SVCR_RES0 != (GENMASK_ULL(63, 2))); - BUILD_BUG_ON(FPMR_RES0 != (GENMASK_ULL(63, 38) | GENMASK_ULL(23, 23) | GENMASK_ULL(13, 9))); - BUILD_BUG_ON(HFGxTR_EL2_RES0 != (GENMASK_ULL(51, 51))); - BUILD_BUG_ON(HFGITR_EL2_RES0 != (GENMASK_ULL(63, 63) | GENMASK_ULL(61, 61))); - BUILD_BUG_ON(HDFGRTR_EL2_RES0 != (GENMASK_ULL(49, 49) | GENMASK_ULL(42, 42) | GENMASK_ULL(39, 38) | GENMASK_ULL(21, 20) | GENMASK_ULL(8, 8))); - BUILD_BUG_ON(HDFGWTR_EL2_RES0 != (GENMASK_ULL(63, 63) | GENMASK_ULL(59, 58) | GENMASK_ULL(51, 51) | GENMASK_ULL(47, 47) | GENMASK_ULL(43, 43) | GENMASK_ULL(40, 38) | GENMASK_ULL(34, 34) | GENMASK_ULL(30, 30) | GENMASK_ULL(22, 22) | GENMASK_ULL(9, 9) | GENMASK_ULL(6, 6))); - BUILD_BUG_ON(HAFGRTR_EL2_RES0 != (GENMASK_ULL(63, 50) | GENMASK_ULL(16, 5))); - BUILD_BUG_ON(HCRX_EL2_RES0 != (GENMASK_ULL(63, 25) | GENMASK_ULL(13, 12))); - BUILD_BUG_ON(DACR32_EL2_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(PMSCR_EL2_RES0 != (GENMASK_ULL(63, 8) | GENMASK_ULL(2, 2))); - BUILD_BUG_ON(TCR2_EL1x_RES0 != (GENMASK_ULL(63, 16) | GENMASK_ULL(13, 12) | GENMASK_ULL(9, 6))); - BUILD_BUG_ON(TCR2_EL2_RES0 != (GENMASK_ULL(63, 16))); - BUILD_BUG_ON(LORSA_EL1_RES0 != (GENMASK_ULL(63, 52) | GENMASK_ULL(15, 1))); - BUILD_BUG_ON(LOREA_EL1_RES0 != (GENMASK_ULL(63, 52) | GENMASK_ULL(15, 0))); - BUILD_BUG_ON(LORN_EL1_RES0 != (GENMASK_ULL(63, 8))); - BUILD_BUG_ON(LORC_EL1_RES0 != (GENMASK_ULL(63, 10) | GENMASK_ULL(1, 1))); - BUILD_BUG_ON(LORID_EL1_RES0 != (GENMASK_ULL(63, 24) | GENMASK_ULL(15, 8))); - BUILD_BUG_ON(ISR_EL1_RES0 != (GENMASK_ULL(63, 11) | GENMASK_ULL(5, 0))); - BUILD_BUG_ON(ICC_NMIAR1_EL1_RES0 != (GENMASK_ULL(63, 24))); - BUILD_BUG_ON(TRBLIMITR_EL1_RES0 != (GENMASK_ULL(11, 7))); - BUILD_BUG_ON(TRBBASER_EL1_RES0 != (GENMASK_ULL(11, 0))); - BUILD_BUG_ON(TRBSR_EL1_RES0 != (GENMASK_ULL(63, 56) | GENMASK_ULL(25, 24) | GENMASK_ULL(19, 19) | GENMASK_ULL(16, 16))); - BUILD_BUG_ON(TRBMAR_EL1_RES0 != (GENMASK_ULL(63, 12))); - BUILD_BUG_ON(TRBTRG_EL1_RES0 != (GENMASK_ULL(63, 32))); - BUILD_BUG_ON(TRBIDR_EL1_RES0 != (GENMASK_ULL(63, 12) | GENMASK_ULL(7, 6))); - -#endif -} diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 8e60aa4a8dfb..c9f4f387155f 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -32,7 +32,6 @@ #include -#include "check-res-bits.h" #include "sys_regs.h" #include "trace.h" @@ -4110,8 +4109,6 @@ int __init kvm_sys_reg_table_init(void) unsigned int i; int ret = 0; - check_res_bits(); - /* Make sure tables are unique and in order. */ valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false); valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), true); From 5c84b051bd4e777cf37aaff983277e58c99618d5 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Fri, 15 Mar 2024 22:42:27 +0100 Subject: [PATCH 812/814] x86/CPU/AMD: Update the Zenbleed microcode revisions Update them to the correct revision numbers. Fixes: 522b1d69219d ("x86/cpu/amd: Add a Zenbleed fix") Signed-off-by: Borislav Petkov (AMD) Cc: Signed-off-by: Linus Torvalds --- arch/x86/kernel/cpu/amd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 3282a747b645..6d8677e80ddb 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -864,11 +864,11 @@ static bool cpu_has_zenbleed_microcode(void) u32 good_rev = 0; switch (boot_cpu_data.x86_model) { - case 0x30 ... 0x3f: good_rev = 0x0830107a; break; - case 0x60 ... 0x67: good_rev = 0x0860010b; break; - case 0x68 ... 0x6f: good_rev = 0x08608105; break; - case 0x70 ... 0x7f: good_rev = 0x08701032; break; - case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; + case 0x30 ... 0x3f: good_rev = 0x0830107b; break; + case 0x60 ... 0x67: good_rev = 0x0860010c; break; + case 0x68 ... 0x6f: good_rev = 0x08608107; break; + case 0x70 ... 0x7f: good_rev = 0x08701033; break; + case 0xa0 ... 0xaf: good_rev = 0x08a00009; break; default: return false; From 719fcafe07c12646691bd62d7f8d94d657fa0766 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 11 Mar 2024 11:11:53 -0400 Subject: [PATCH 813/814] nfs: fix panic when nfs4_ff_layout_prepare_ds() fails We've been seeing the following panic in production BUG: kernel NULL pointer dereference, address: 0000000000000065 PGD 2f485f067 P4D 2f485f067 PUD 2cc5d8067 PMD 0 RIP: 0010:ff_layout_cancel_io+0x3a/0x90 [nfs_layout_flexfiles] Call Trace: ? __die+0x78/0xc0 ? page_fault_oops+0x286/0x380 ? __rpc_execute+0x2c3/0x470 [sunrpc] ? rpc_new_task+0x42/0x1c0 [sunrpc] ? exc_page_fault+0x5d/0x110 ? asm_exc_page_fault+0x22/0x30 ? ff_layout_free_layoutreturn+0x110/0x110 [nfs_layout_flexfiles] ? ff_layout_cancel_io+0x3a/0x90 [nfs_layout_flexfiles] ? ff_layout_cancel_io+0x6f/0x90 [nfs_layout_flexfiles] pnfs_mark_matching_lsegs_return+0x1b0/0x360 [nfsv4] pnfs_error_mark_layout_for_return+0x9e/0x110 [nfsv4] ? ff_layout_send_layouterror+0x50/0x160 [nfs_layout_flexfiles] nfs4_ff_layout_prepare_ds+0x11f/0x290 [nfs_layout_flexfiles] ff_layout_pg_init_write+0xf0/0x1f0 [nfs_layout_flexfiles] __nfs_pageio_add_request+0x154/0x6c0 [nfs] nfs_pageio_add_request+0x26b/0x380 [nfs] nfs_do_writepage+0x111/0x1e0 [nfs] nfs_writepages_callback+0xf/0x30 [nfs] write_cache_pages+0x17f/0x380 ? nfs_pageio_init_write+0x50/0x50 [nfs] ? nfs_writepages+0x6d/0x210 [nfs] ? nfs_writepages+0x6d/0x210 [nfs] nfs_writepages+0x125/0x210 [nfs] do_writepages+0x67/0x220 ? generic_perform_write+0x14b/0x210 filemap_fdatawrite_wbc+0x5b/0x80 file_write_and_wait_range+0x6d/0xc0 nfs_file_fsync+0x81/0x170 [nfs] ? nfs_file_mmap+0x60/0x60 [nfs] __x64_sys_fsync+0x53/0x90 do_syscall_64+0x3d/0x90 entry_SYSCALL_64_after_hwframe+0x46/0xb0 Inspecting the core with drgn I was able to pull this >>> prog.crashed_thread().stack_trace()[0] #0 at 0xffffffffa079657a (ff_layout_cancel_io+0x3a/0x84) in ff_layout_cancel_io at fs/nfs/flexfilelayout/flexfilelayout.c:2021:27 >>> prog.crashed_thread().stack_trace()[0]['idx'] (u32)1 >>> prog.crashed_thread().stack_trace()[0]['flseg'].mirror_array[1].mirror_ds (struct nfs4_ff_layout_ds *)0xffffffffffffffed This is clear from the stack trace, we call nfs4_ff_layout_prepare_ds() which could error out initializing the mirror_ds, and then we go to clean it all up and our check is only for if (!mirror->mirror_ds). This is inconsistent with the rest of the users of mirror_ds, which have if (IS_ERR_OR_NULL(mirror_ds)) to keep from tripping over this exact scenario. Fix this up in ff_layout_cancel_io() to make sure we don't panic when we get an error. I also spot checked all the other instances of checking mirror_ds and we appear to be doing the correct checks everywhere, only unconditionally dereferencing mirror_ds when we know it would be valid. Signed-off-by: Josef Bacik Fixes: b739a5bd9d9f ("NFSv4/flexfiles: Cancel I/O if the layout is recalled or revoked") Reviewed-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index ef817a0475ff..3e724cb7ef01 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -2016,7 +2016,7 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg) for (idx = 0; idx < flseg->mirror_array_cnt; idx++) { mirror = flseg->mirror_array[idx]; mirror_ds = mirror->mirror_ds; - if (!mirror_ds) + if (IS_ERR_OR_NULL(mirror_ds)) continue; ds = mirror->mirror_ds->ds; if (!ds) From 4b6f4c5a67c07417bf29d896c76f513a4be07516 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 15 Mar 2024 02:14:47 +0100 Subject: [PATCH 814/814] timer/migration: Remove buggy early return on deactivation When a CPU enters into idle and deactivates itself from the timer migration hierarchy without any global timer of its own to propagate, the group event of that CPU is set to "ignore" and tmigr_update_events() accordingly performs an early return without considering timers queued by other CPUs. If the hierarchy has a single level, and the CPU is the last one to enter idle, it will ignore others' global timers, as in the following layout: [GRP0:0] migrator = 0 active = 0 nextevt = T0i / \ 0 1 active (T0i) idle (T1) 0) CPU 0 is active thus its event is ignored (the letter 'i') and so are upper levels' events. CPU 1 is idle and has the timer T1 enqueued. [GRP0:0] migrator = NONE active = NONE nextevt = T0i / \ 0 1 idle (T0i) idle (T1) 1) CPU 0 goes idle without global event queued. Therefore KTIME_MAX is pushed as its next expiry and its own event kept as "ignore". As a result tmigr_update_events() ignores T1 and CPU 0 goes to idle with T1 unhandled. This isn't proper to single level hierarchy though. A similar issue, although slightly different, may arise on multi-level: [GRP1:0] migrator = GRP0:0 active = GRP0:0 nextevt = T0:0i, T0:1 / \ [GRP0:0] [GRP0:1] migrator = 0 migrator = NONE active = 0 active = NONE nextevt = T0i nextevt = T2 / \ / \ 0 (T0i) 1 (T1) 2 (T2) 3 active idle idle idle 0) CPU 0 is active thus its event is ignored (the letter 'i') and so are upper levels' events. CPU 1 is idle and has the timer T1 enqueued. CPU 2 also has a timer. The expiry order is T0 (ignored) < T1 < T2 [GRP1:0] migrator = GRP0:0 active = GRP0:0 nextevt = T0:0i, T0:1 / \ [GRP0:0] [GRP0:1] migrator = NONE migrator = NONE active = NONE active = NONE nextevt = T0i nextevt = T2 / \ / \ 0 (T0i) 1 (T1) 2 (T2) 3 idle idle idle idle 1) CPU 0 goes idle without global event queued. Therefore KTIME_MAX is pushed as its next expiry and its own event kept as "ignore". As a result tmigr_update_events() ignores T1. The change only propagated up to 1st level so far. [GRP1:0] migrator = NONE active = NONE nextevt = T0:1 / \ [GRP0:0] [GRP0:1] migrator = NONE migrator = NONE active = NONE active = NONE nextevt = T0i nextevt = T2 / \ / \ 0 (T0i) 1 (T1) 2 (T2) 3 idle idle idle idle 2) The change now propagates up to the top. tmigr_update_events() finds that the child event is ignored and thus removes it. The top level next event is now T2 which is returned to CPU 0 as its next effective expiry to take account for as the global idle migrator. However T1 has been ignored along the way, leaving it unhandled. Fix those issues with removing the buggy related early return. Ignored child events must not prevent from evaluating the other events within the same group. Reported-by: Boqun Feng Reported-by: Florian Fainelli Reported-by: Thomas Gleixner Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Tested-by: Florian Fainelli Link: https://lore.kernel.org/r/ZfOhB9ZByTZcBy4u@lothringen --- kernel/time/timer_migration.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index 8f49b6b96dfd..611cd904f035 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -751,26 +751,6 @@ bool tmigr_update_events(struct tmigr_group *group, struct tmigr_group *child, first_childevt = evt = data->evt; - /* - * Walking the hierarchy is required in any case when a - * remote expiry was done before. This ensures to not lose - * already queued events in non active groups (see section - * "Required event and timerqueue update after a remote - * expiry" in the documentation at the top). - * - * The two call sites which are executed without a remote expiry - * before, are not prevented from propagating changes through - * the hierarchy by the return: - * - When entering this path by tmigr_new_timer(), @evt->ignore - * is never set. - * - tmigr_inactive_up() takes care of the propagation by - * itself and ignores the return value. But an immediate - * return is required because nothing has to be done in this - * level as the event could be ignored. - */ - if (evt->ignore && !remote) - return true; - raw_spin_lock(&group->lock); childstate.state = 0;