From 692751879ea876dec81357e6f1f8ca0ced131ceb Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 7 Jan 2020 08:53:40 +0100 Subject: [PATCH 001/809] clk, clk-si5341: Support multiple input ports The Si5341 and Si5340 have multiple input clock options. So far, the driver only supported the XTAL input, this adds support for the three external clock inputs as well. If the clock chip isn't programmed at boot, the driver will default to the XTAL input as before. If there is no "xtal" clock input available, it will pick the first connected input (e.g. "in0") as the input clock for the PLL. One can use clock-assigned-parents to select a particular clock as input. Signed-off-by: Mike Looijmans Link: https://lkml.kernel.org/r/20200107075340.14528-1-mike.looijmans@topic.nl Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5341.c | 212 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 196 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 6e780c2a9e6b..3c228b018116 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -16,6 +16,8 @@ #include #include +#define SI5341_NUM_INPUTS 4 + #define SI5341_MAX_NUM_OUTPUTS 10 #define SI5340_MAX_NUM_OUTPUTS 4 @@ -56,8 +58,8 @@ struct clk_si5341 { struct i2c_client *i2c_client; struct clk_si5341_synth synth[SI5341_NUM_SYNTH]; struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS]; - struct clk *pxtal; - const char *pxtal_name; + struct clk *input_clk[SI5341_NUM_INPUTS]; + const char *input_clk_name[SI5341_NUM_INPUTS]; const u16 *reg_output_offset; const u16 *reg_rdiv_offset; u64 freq_vco; /* 13500–14256 MHz */ @@ -78,10 +80,25 @@ struct clk_si5341_output_config { #define SI5341_DEVICE_REV 0x0005 #define SI5341_STATUS 0x000C #define SI5341_SOFT_RST 0x001C +#define SI5341_IN_SEL 0x0021 +#define SI5341_XAXB_CFG 0x090E +#define SI5341_IN_EN 0x0949 +#define SI5341_INX_TO_PFD_EN 0x094A + +/* Input selection */ +#define SI5341_IN_SEL_MASK 0x06 +#define SI5341_IN_SEL_SHIFT 1 +#define SI5341_IN_SEL_REGCTRL 0x01 +#define SI5341_INX_TO_PFD_SHIFT 4 + +/* XTAL config bits */ +#define SI5341_XAXB_CFG_EXTCLK_EN BIT(0) +#define SI5341_XAXB_CFG_PDNB BIT(1) /* Input dividers (48-bit) */ #define SI5341_IN_PDIV(x) (0x0208 + ((x) * 10)) #define SI5341_IN_PSET(x) (0x020E + ((x) * 10)) +#define SI5341_PX_UPD 0x0230 /* PLL configuration */ #define SI5341_PLL_M_NUM 0x0235 @@ -120,6 +137,10 @@ struct si5341_reg_default { u8 value; }; +static const char * const si5341_input_clock_names[] = { + "in0", "in1", "in2", "xtal" +}; + /* Output configuration registers 0..9 are not quite logically organized */ static const u16 si5341_reg_output_offset[] = { 0x0108, @@ -390,7 +411,112 @@ static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw, return (unsigned long)res; } +static int si5341_clk_get_selected_input(struct clk_si5341 *data) +{ + int err; + u32 val; + + err = regmap_read(data->regmap, SI5341_IN_SEL, &val); + if (err < 0) + return err; + + return (val & SI5341_IN_SEL_MASK) >> SI5341_IN_SEL_SHIFT; +} + +static u8 si5341_clk_get_parent(struct clk_hw *hw) +{ + struct clk_si5341 *data = to_clk_si5341(hw); + int res = si5341_clk_get_selected_input(data); + + if (res < 0) + return 0; /* Apparently we cannot report errors */ + + return res; +} + +static int si5341_clk_reparent(struct clk_si5341 *data, u8 index) +{ + int err; + u8 val; + + val = (index << SI5341_IN_SEL_SHIFT) & SI5341_IN_SEL_MASK; + /* Enable register-based input selection */ + val |= SI5341_IN_SEL_REGCTRL; + + err = regmap_update_bits(data->regmap, + SI5341_IN_SEL, SI5341_IN_SEL_REGCTRL | SI5341_IN_SEL_MASK, val); + if (err < 0) + return err; + + if (index < 3) { + /* Enable input buffer for selected input */ + err = regmap_update_bits(data->regmap, + SI5341_IN_EN, 0x07, BIT(index)); + if (err < 0) + return err; + + /* Enables the input to phase detector */ + err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN, + 0x7 << SI5341_INX_TO_PFD_SHIFT, + BIT(index + SI5341_INX_TO_PFD_SHIFT)); + if (err < 0) + return err; + + /* Power down XTAL oscillator and buffer */ + err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG, + SI5341_XAXB_CFG_PDNB, 0); + if (err < 0) + return err; + + /* + * Set the P divider to "1". There's no explanation in the + * datasheet of these registers, but the clockbuilder software + * programs a "1" when the input is being used. + */ + err = regmap_write(data->regmap, SI5341_IN_PDIV(index), 1); + if (err < 0) + return err; + + err = regmap_write(data->regmap, SI5341_IN_PSET(index), 1); + if (err < 0) + return err; + + /* Set update PDIV bit */ + err = regmap_write(data->regmap, SI5341_PX_UPD, BIT(index)); + if (err < 0) + return err; + } else { + /* Disable all input buffers */ + err = regmap_update_bits(data->regmap, SI5341_IN_EN, 0x07, 0); + if (err < 0) + return err; + + /* Disable input to phase detector */ + err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN, + 0x7 << SI5341_INX_TO_PFD_SHIFT, 0); + if (err < 0) + return err; + + /* Power up XTAL oscillator and buffer */ + err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG, + SI5341_XAXB_CFG_PDNB, SI5341_XAXB_CFG_PDNB); + if (err < 0) + return err; + } + + return 0; +} + +static int si5341_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_si5341 *data = to_clk_si5341(hw); + + return si5341_clk_reparent(data, index); +} + static const struct clk_ops si5341_clk_ops = { + .set_parent = si5341_clk_set_parent, + .get_parent = si5341_clk_get_parent, .recalc_rate = si5341_clk_recalc_rate, }; @@ -985,7 +1111,8 @@ static const struct regmap_range si5341_regmap_volatile_range[] = { regmap_reg_range(0x000C, 0x0012), /* Status */ regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */ regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */ - /* Update bits for synth config */ + /* Update bits for P divider and synth config */ + regmap_reg_range(SI5341_PX_UPD, SI5341_PX_UPD), regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)), regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)), regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)), @@ -1122,6 +1249,7 @@ static int si5341_initialize_pll(struct clk_si5341 *data) struct device_node *np = data->i2c_client->dev.of_node; u32 m_num = 0; u32 m_den = 0; + int sel; if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) { dev_err(&data->i2c_client->dev, @@ -1135,7 +1263,11 @@ static int si5341_initialize_pll(struct clk_si5341 *data) if (!m_num || !m_den) { dev_err(&data->i2c_client->dev, "PLL configuration invalid, assume 14GHz\n"); - m_den = clk_get_rate(data->pxtal) / 10; + sel = si5341_clk_get_selected_input(data); + if (sel < 0) + return sel; + + m_den = clk_get_rate(data->input_clk[sel]) / 10; m_num = 1400000000; } @@ -1143,11 +1275,52 @@ static int si5341_initialize_pll(struct clk_si5341 *data) SI5341_PLL_M_NUM, m_num, m_den); } +static int si5341_clk_select_active_input(struct clk_si5341 *data) +{ + int res; + int err; + int i; + + res = si5341_clk_get_selected_input(data); + if (res < 0) + return res; + + /* If the current register setting is invalid, pick the first input */ + if (!data->input_clk[res]) { + dev_dbg(&data->i2c_client->dev, + "Input %d not connected, rerouting\n", res); + res = -ENODEV; + for (i = 0; i < SI5341_NUM_INPUTS; ++i) { + if (data->input_clk[i]) { + res = i; + break; + } + } + if (res < 0) { + dev_err(&data->i2c_client->dev, + "No clock input available\n"); + return res; + } + } + + /* Make sure the selected clock is also enabled and routed */ + err = si5341_clk_reparent(data, res); + if (err < 0) + return err; + + err = clk_prepare_enable(data->input_clk[res]); + if (err < 0) + return err; + + return res; +} + static int si5341_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct clk_si5341 *data; struct clk_init_data init; + struct clk *input; const char *root_clock_name; const char *synth_clock_names[SI5341_NUM_SYNTH]; int err; @@ -1161,12 +1334,16 @@ static int si5341_probe(struct i2c_client *client, data->i2c_client = client; - data->pxtal = devm_clk_get(&client->dev, "xtal"); - if (IS_ERR(data->pxtal)) { - if (PTR_ERR(data->pxtal) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - dev_err(&client->dev, "Missing xtal clock input\n"); + for (i = 0; i < SI5341_NUM_INPUTS; ++i) { + input = devm_clk_get(&client->dev, si5341_input_clock_names[i]); + if (IS_ERR(input)) { + if (PTR_ERR(input) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->input_clk_name[i] = si5341_input_clock_names[i]; + } else { + data->input_clk[i] = input; + data->input_clk_name[i] = __clk_get_name(input); + } } err = si5341_dt_parse_dt(client, config); @@ -1188,9 +1365,6 @@ static int si5341_probe(struct i2c_client *client, if (err < 0) return err; - /* "Activate" the xtal (usually a fixed clock) */ - clk_prepare_enable(data->pxtal); - if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) { initialization_required = true; } else { @@ -1223,7 +1397,14 @@ static int si5341_probe(struct i2c_client *client, ARRAY_SIZE(si5341_reg_defaults)); if (err < 0) return err; + } + /* Input must be up and running at this point */ + err = si5341_clk_select_active_input(data); + if (err < 0) + return err; + + if (initialization_required) { /* PLL configuration is required */ err = si5341_initialize_pll(data); if (err < 0) @@ -1231,9 +1412,8 @@ static int si5341_probe(struct i2c_client *client, } /* Register the PLL */ - data->pxtal_name = __clk_get_name(data->pxtal); - init.parent_names = &data->pxtal_name; - init.num_parents = 1; /* For now, only XTAL input supported */ + init.parent_names = data->input_clk_name; + init.num_parents = SI5341_NUM_INPUTS; init.ops = &si5341_clk_ops; init.flags = 0; data->hw.init = &init; From a630fe34ddc09ec9b82df4867a8680d0929fe926 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 Jan 2020 22:08:45 +0100 Subject: [PATCH 002/809] gpio: pxa: Avoid a warning when gpio0 and gpio1 IRQS are not there Not all platforms use those. Let's use platform_get_irq_byname_optional() instead platform_get_irq_byname() so that we avoid a useless warning: [ 1.359455] pxa-gpio d4019000.gpio: IRQ gpio0 not found [ 1.359583] pxa-gpio d4019000.gpio: IRQ gpio1 not found Signed-off-by: Lubomir Rintel Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pxa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9888b62f37af..567742d962ae 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -652,8 +652,8 @@ static int pxa_gpio_probe(struct platform_device *pdev) if (!pchip->irqdomain) return -ENOMEM; - irq0 = platform_get_irq_byname(pdev, "gpio0"); - irq1 = platform_get_irq_byname(pdev, "gpio1"); + irq0 = platform_get_irq_byname_optional(pdev, "gpio0"); + irq1 = platform_get_irq_byname_optional(pdev, "gpio1"); irq_mux = platform_get_irq_byname(pdev, "gpio_mux"); if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0) || (irq_mux <= 0)) From 47d7d116661993499d626f7ec6f7679e83d59f15 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 31 Jan 2020 20:29:17 +0800 Subject: [PATCH 003/809] gpio: wcd934x: Don't change gpio direction in wcd_gpio_set The .set callback should just set output value. Signed-off-by: Axel Lin Reviewed-by: Srinivas Kandagatla Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-wcd934x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c index 74913f2e5697..9d4ec8941b9b 100644 --- a/drivers/gpio/gpio-wcd934x.c +++ b/drivers/gpio/gpio-wcd934x.c @@ -66,7 +66,10 @@ static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) { - wcd_gpio_direction_output(chip, pin, val); + struct wcd_gpio_data *data = gpiochip_get_data(chip); + + regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET, + WCD_PIN_MASK(pin), val ? WCD_PIN_MASK(pin) : 0); } static int wcd_gpio_probe(struct platform_device *pdev) From 47203198ed3df0f6896d07613182c05cb94110a5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 31 Jan 2020 20:29:18 +0800 Subject: [PATCH 004/809] gpio: wcd934x: Fix logic of wcd_gpio_get The check with register value and mask should be & rather than &&. While at it, also use "unsigned int" for value variable because regmap_read() takes unsigned int *val argument. Signed-off-by: Axel Lin Reviewed-by: Srinivas Kandagatla Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-wcd934x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c index 9d4ec8941b9b..1cbce5990855 100644 --- a/drivers/gpio/gpio-wcd934x.c +++ b/drivers/gpio/gpio-wcd934x.c @@ -57,11 +57,11 @@ static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) { struct wcd_gpio_data *data = gpiochip_get_data(chip); - int value; + unsigned int value; regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value); - return !!(value && WCD_PIN_MASK(pin)); + return !!(value & WCD_PIN_MASK(pin)); } static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) From 046e14afb3561523efd0047c35c20793ae5f8848 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2020 15:43:36 +0200 Subject: [PATCH 005/809] gpio: Avoid kernel.h inclusion where it's possible Inclusion of kernel.h increases the mess with the header dependencies. Avoid kernel.h inclusion where it's possible. Besides that, clean up a bit other inclusions inside GPIO subsystem headers. It includes: - removal pin control bits (forward declaration and header) from linux/gpio.h - removal of.h from asm-generic/gpio.h - use of explicit headers in gpio/consumer.h - add FIXME note with regard to gpio.h inclusion in of_gpio,h Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200205134336.20197-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- include/asm-generic/gpio.h | 4 ++-- include/linux/gpio.h | 2 -- include/linux/gpio/consumer.h | 5 ++++- include/linux/of_gpio.h | 9 ++++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 19eadac415c4..aea9aee1f3e9 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -2,10 +2,8 @@ #ifndef _ASM_GENERIC_GPIO_H #define _ASM_GENERIC_GPIO_H -#include #include #include -#include #ifdef CONFIG_GPIOLIB @@ -140,6 +138,8 @@ static inline void gpio_unexport(unsigned gpio) #else /* !CONFIG_GPIOLIB */ +#include + static inline bool gpio_is_valid(int number) { /* only non-negative numbers are valid */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 2157717c2136..008ad3ee56b7 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -102,11 +102,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio); #include #include #include -#include struct device; struct gpio_chip; -struct pinctrl_dev; static inline bool gpio_is_valid(int number) { diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index bf2d017dd7b7..0a72fccf60ff 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -2,9 +2,10 @@ #ifndef __LINUX_GPIO_CONSUMER_H #define __LINUX_GPIO_CONSUMER_H +#include #include +#include #include -#include struct device; @@ -189,6 +190,8 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, #else /* CONFIG_GPIOLIB */ +#include + static inline int gpiod_count(struct device *dev, const char *con_id) { return 0; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 16967390a3fe..f821095218b0 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -11,9 +11,8 @@ #define __LINUX_OF_GPIO_H #include -#include -#include -#include +#include +#include /* FIXME: Shouldn't be here */ #include struct device_node; @@ -34,6 +33,8 @@ enum of_gpio_flags { #ifdef CONFIG_OF_GPIO +#include + /* * OF GPIO chip for memory mapped banks */ @@ -63,6 +64,8 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); #else /* CONFIG_OF_GPIO */ +#include + /* Drivers may not strictly depend on the GPIO support, so let them link. */ static inline int of_get_named_gpio_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags) From 6e26901a00c04436e9e7a323772b71348aeab651 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2020 14:31:37 +0100 Subject: [PATCH 006/809] clk: renesas: rcar-gen3: Add CCREE clocks Add the CryptoCell module clocks and their parents for the CryptoCell instances in the various Renesas R-Car Gen3 SoCs that do not have support for them yet in their clock drivers (M3-W/W+, M3-N, E3, D3). The R-Car H3 clock driver already supports these clocks. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200124133137.15921-1-geert+renesas@glider.be --- drivers/clk/renesas/r8a7796-cpg-mssr.c | 2 ++ drivers/clk/renesas/r8a77965-cpg-mssr.c | 4 +++- drivers/clk/renesas/r8a77990-cpg-mssr.c | 2 ++ drivers/clk/renesas/r8a77995-cpg-mssr.c | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index e8420d3ada94..1155d6636848 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -105,6 +105,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x26c), DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cr", R8A7796_CLK_CR, CLK_PLL1_DIV4, 2, 1), DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A7796_CLK_CPEX, CLK_EXTAL, 2, 1), @@ -132,6 +133,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { DEF_MOD("sys-dmac2", 217, R8A7796_CLK_S3D1), DEF_MOD("sys-dmac1", 218, R8A7796_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A7796_CLK_S0D3), + DEF_MOD("sceg-pub", 229, R8A7796_CLK_CR), DEF_MOD("cmt3", 300, R8A7796_CLK_R), DEF_MOD("cmt2", 301, R8A7796_CLK_R), DEF_MOD("cmt1", 302, R8A7796_CLK_R), diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index b3af4da2ca74..9530480880f1 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -99,7 +99,8 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { DEF_GEN3_SD("sd2", R8A77965_CLK_SD2, CLK_SDSRC, 0x268), DEF_GEN3_SD("sd3", R8A77965_CLK_SD3, CLK_SDSRC, 0x26c), - DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cr", R8A77965_CLK_CR, CLK_PLL1_DIV4, 2, 1), DEF_FIXED("cp", R8A77965_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A77965_CLK_CPEX, CLK_EXTAL, 2, 1), @@ -127,6 +128,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("sys-dmac2", 217, R8A77965_CLK_S3D1), DEF_MOD("sys-dmac1", 218, R8A77965_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A77965_CLK_S0D3), + DEF_MOD("sceg-pub", 229, R8A77965_CLK_CR), DEF_MOD("cmt3", 300, R8A77965_CLK_R), DEF_MOD("cmt2", 301, R8A77965_CLK_R), diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c index ceabf55c21c2..8eda2e3e2480 100644 --- a/drivers/clk/renesas/r8a77990-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c @@ -105,6 +105,7 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = { DEF_GEN3_SD("sd3", R8A77990_CLK_SD3, CLK_SDSRC, 0x026c), DEF_FIXED("cl", R8A77990_CLK_CL, CLK_PLL1, 48, 1), + DEF_FIXED("cr", R8A77990_CLK_CR, CLK_PLL1D2, 2, 1), DEF_FIXED("cp", R8A77990_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A77990_CLK_CPEX, CLK_EXTAL, 4, 1), @@ -135,6 +136,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { DEF_MOD("sys-dmac2", 217, R8A77990_CLK_S3D1), DEF_MOD("sys-dmac1", 218, R8A77990_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A77990_CLK_S3D1), + DEF_MOD("sceg-pub", 229, R8A77990_CLK_CR), DEF_MOD("cmt3", 300, R8A77990_CLK_R), DEF_MOD("cmt2", 301, R8A77990_CLK_R), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index 962bb337f2e7..056ebf3e70e2 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -91,6 +91,7 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = { DEF_FIXED("s3d4", R8A77995_CLK_S3D4, CLK_S3, 4, 1), DEF_FIXED("cl", R8A77995_CLK_CL, CLK_PLL1, 48, 1), + DEF_FIXED("cr", R8A77995_CLK_CR, CLK_PLL1D2, 2, 1), DEF_FIXED("cp", R8A77995_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A77995_CLK_CPEX, CLK_EXTAL, 4, 1), @@ -122,6 +123,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("sys-dmac2", 217, R8A77995_CLK_S3D1), DEF_MOD("sys-dmac1", 218, R8A77995_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A77995_CLK_S3D1), + DEF_MOD("sceg-pub", 229, R8A77995_CLK_CR), DEF_MOD("cmt3", 300, R8A77995_CLK_R), DEF_MOD("cmt2", 301, R8A77995_CLK_R), DEF_MOD("cmt1", 302, R8A77995_CLK_R), From 9e6f3b44dc75666bd1861f49aea0f8dfa8c67499 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 3 Feb 2020 08:28:59 +0100 Subject: [PATCH 007/809] clk: renesas: r8a7795: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the R-Car H3 (R8A7795) CPG/MSSR driver. Inspired by commit 94e3935b5756 ("clk: renesas: r8a77980: Add RPC clocks"). Signed-off-by: Dirk Behme Link: https://lore.kernel.org/r/20200203072901.31548-1-dirk.behme@de.bosch.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index fbc8c75f4314..ff5b3020cb03 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -44,6 +44,7 @@ enum clk_ids { CLK_S3, CLK_SDSRC, CLK_SSPSRC, + CLK_RPCSRC, CLK_RINT, /* Module Clocks */ @@ -70,6 +71,12 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_BASE("rpc", R8A7795_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A7795_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A7795_CLK_RPC), DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), @@ -242,6 +249,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2), DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4), DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A7795_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A7795_CLK_S0D6), DEF_MOD("i2c5", 919, R8A7795_CLK_S0D6), DEF_MOD("i2c-dvfs", 926, R8A7795_CLK_CP), From 715286f51d13f125de6dbc13f2d707a7893bf95d Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 3 Feb 2020 08:29:00 +0100 Subject: [PATCH 008/809] clk: renesas: r8a7796: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the R-Car M3-W/M3-W+ (R8A7796) CPG/MSSR driver. Inspired by commit 94e3935b5756 ("clk: renesas: r8a77980: Add RPC clocks"). Signed-off-by: Dirk Behme Link: https://lore.kernel.org/r/20200203072901.31548-2-dirk.behme@de.bosch.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7796-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 1155d6636848..e8d466dbc7f9 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -46,6 +46,7 @@ enum clk_ids { CLK_S3, CLK_SDSRC, CLK_SSPSRC, + CLK_RPCSRC, CLK_RINT, /* Module Clocks */ @@ -72,6 +73,12 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_BASE("rpc", R8A7796_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A7796_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A7796_CLK_RPC), DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), @@ -217,6 +224,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { DEF_MOD("can-fd", 914, R8A7796_CLK_S3D2), DEF_MOD("can-if1", 915, R8A7796_CLK_S3D4), DEF_MOD("can-if0", 916, R8A7796_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A7796_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6), DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6), DEF_MOD("i2c-dvfs", 926, R8A7796_CLK_CP), From 808eab15f39be1ed9502244d2aa4f35209f9d0d5 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 3 Feb 2020 08:29:01 +0100 Subject: [PATCH 009/809] clk: renesas: r8a77965: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the R-Car M3-N (R8A77965) CPG/MSSR driver. Inspired by commit 94e3935b5756 ("clk: renesas: r8a77980: Add RPC clocks"). Signed-off-by: Dirk Behme Link: https://lore.kernel.org/r/20200203072901.31548-3-dirk.behme@de.bosch.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a77965-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index 9530480880f1..7a05a2fc1cc6 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -43,6 +43,7 @@ enum clk_ids { CLK_S3, CLK_SDSRC, CLK_SSPSRC, + CLK_RPCSRC, CLK_RINT, /* Module Clocks */ @@ -68,6 +69,12 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_BASE("rpc", R8A77965_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A77965_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A77965_CLK_RPC), DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), @@ -217,6 +224,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("can-fd", 914, R8A77965_CLK_S3D2), DEF_MOD("can-if1", 915, R8A77965_CLK_S3D4), DEF_MOD("can-if0", 916, R8A77965_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A77965_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6), DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6), DEF_MOD("i2c-dvfs", 926, R8A77965_CLK_CP), From 1de8493069b8f510e586242c1b4329cd3c9b6fb9 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 10 Feb 2020 18:06:53 +0100 Subject: [PATCH 010/809] clk: sunxi-ng: a64: Export MBUS clock MBUS clock will be referenced in MBUS controller node. Export it. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-a64.h | 4 ---- include/dt-bindings/clock/sun50i-a64-ccu.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h index 116e6f826d04..54d1f96f4b68 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h @@ -55,10 +55,6 @@ /* All the DRAM gates are exported */ -/* Some more module clocks are exported */ - -#define CLK_MBUS 112 - /* And the DSI and GPU module clock is exported */ #define CLK_NUMBER (CLK_GPU + 1) diff --git a/include/dt-bindings/clock/sun50i-a64-ccu.h b/include/dt-bindings/clock/sun50i-a64-ccu.h index e512a1c9b0fc..318eb15c414c 100644 --- a/include/dt-bindings/clock/sun50i-a64-ccu.h +++ b/include/dt-bindings/clock/sun50i-a64-ccu.h @@ -131,7 +131,7 @@ #define CLK_AVS 109 #define CLK_HDMI 110 #define CLK_HDMI_DDC 111 - +#define CLK_MBUS 112 #define CLK_DSI_DPHY 113 #define CLK_GPU 114 From 3f2e4c11e136e2cffd60dbc840b59ff65f017328 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 17 Dec 2019 18:48:55 +0100 Subject: [PATCH 011/809] kfifo: provide noirqsave variants of spinlocked in and out helpers Provide variants of spinlocked kfifo_in() and kfifo_out() routines which don't disable interrupts. Signed-off-by: Bartosz Golaszewski Acked-by: Stefani Seibold --- include/linux/kfifo.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index fc4b0b10210f..123c200ed7cb 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -517,6 +517,26 @@ __kfifo_uint_must_check_helper( \ __ret; \ }) +/** + * kfifo_in_spinlocked_noirqsave - put data into fifo using a spinlock for + * locking, don't disable interrupts + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * @lock: pointer to the spinlock to use for locking + * + * This is a variant of kfifo_in_spinlocked() but uses spin_lock/unlock() + * for locking and doesn't disable interrupts. + */ +#define kfifo_in_spinlocked_noirqsave(fifo, buf, n, lock) \ +({ \ + unsigned int __ret; \ + spin_lock(lock); \ + __ret = kfifo_in(fifo, buf, n); \ + spin_unlock(lock); \ + __ret; \ +}) + /* alias for kfifo_in_spinlocked, will be removed in a future release */ #define kfifo_in_locked(fifo, buf, n, lock) \ kfifo_in_spinlocked(fifo, buf, n, lock) @@ -569,6 +589,28 @@ __kfifo_uint_must_check_helper( \ }) \ ) +/** + * kfifo_out_spinlocked_noirqsave - get data from the fifo using a spinlock + * for locking, don't disable interrupts + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * @lock: pointer to the spinlock to use for locking + * + * This is a variant of kfifo_out_spinlocked() which uses spin_lock/unlock() + * for locking and doesn't disable interrupts. + */ +#define kfifo_out_spinlocked_noirqsave(fifo, buf, n, lock) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned int __ret; \ + spin_lock(lock); \ + __ret = kfifo_out(fifo, buf, n); \ + spin_unlock(lock); \ + __ret; \ +}) \ +) + /* alias for kfifo_out_spinlocked, will be removed in a future release */ #define kfifo_out_locked(fifo, buf, n, lock) \ kfifo_out_spinlocked(fifo, buf, n, lock) From 5195a89e8583bba43ec13871a7226763e401b44e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 17 Dec 2019 11:30:59 +0100 Subject: [PATCH 012/809] kfifo: provide kfifo_is_empty_spinlocked() Provide two spinlocked versions of kfifo_is_empty() to be used with spinlocked variants of kfifo_in() and kfifo_out(). Signed-off-by: Bartosz Golaszewski Acked-by: Stefani Seibold --- include/linux/kfifo.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 123c200ed7cb..86249476b57f 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -246,6 +246,37 @@ __kfifo_int_must_check_helper(int val) __tmpq->kfifo.in == __tmpq->kfifo.out; \ }) +/** + * kfifo_is_empty_spinlocked - returns true if the fifo is empty using + * a spinlock for locking + * @fifo: address of the fifo to be used + * @lock: spinlock to be used for locking + */ +#define kfifo_is_empty_spinlocked(fifo, lock) \ +({ \ + unsigned long __flags; \ + bool __ret; \ + spin_lock_irqsave(lock, __flags); \ + __ret = kfifo_is_empty(fifo); \ + spin_unlock_irqrestore(lock, __flags); \ + __ret; \ +}) + +/** + * kfifo_is_empty_spinlocked_noirqsave - returns true if the fifo is empty + * using a spinlock for locking, doesn't disable interrupts + * @fifo: address of the fifo to be used + * @lock: spinlock to be used for locking + */ +#define kfifo_is_empty_spinlocked_noirqsave(fifo, lock) \ +({ \ + bool __ret; \ + spin_lock(lock); \ + __ret = kfifo_is_empty(fifo); \ + spin_unlock(lock); \ + __ret; \ +}) + /** * kfifo_is_full - returns true if the fifo is full * @fifo: address of the fifo to be used From dea9c80ee6726986d90260f135c83545427cbc4e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 27 Nov 2019 12:19:21 +0100 Subject: [PATCH 013/809] gpiolib: rework the locking mechanism for lineevent kfifo The read_lock mutex is supposed to prevent collisions between reading and writing to the line event kfifo but it's actually only taken when the events are being read from it. Drop the mutex entirely and reuse the spinlock made available to us in the waitqueue struct. Take the lock whenever the fifo is modified or inspected. Drop the call to kfifo_to_user() and instead first extract the new element from kfifo when the lock is taken and only then pass it on to the user after the spinlock is released. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib.c | 66 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 753283486037..43d98309e725 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -787,8 +787,6 @@ out_free_lh: * @irq: the interrupt that trigger in response to events on this GPIO * @wait: wait queue that handles blocking reads of events * @events: KFIFO for the GPIO events - * @read_lock: mutex lock to protect reads from colliding with adding - * new events to the FIFO * @timestamp: cache for the timestamp storing it between hardirq * and IRQ thread, used to bring the timestamp close to the actual * event @@ -801,7 +799,6 @@ struct lineevent_state { int irq; wait_queue_head_t wait; DECLARE_KFIFO(events, struct gpioevent_data, 16); - struct mutex read_lock; u64 timestamp; }; @@ -817,7 +814,7 @@ static __poll_t lineevent_poll(struct file *filep, poll_wait(filep, &le->wait, wait); - if (!kfifo_is_empty(&le->events)) + if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock)) events = EPOLLIN | EPOLLRDNORM; return events; @@ -830,43 +827,52 @@ static ssize_t lineevent_read(struct file *filep, loff_t *f_ps) { struct lineevent_state *le = filep->private_data; - unsigned int copied; + struct gpioevent_data event; + ssize_t bytes_read = 0; int ret; - if (count < sizeof(struct gpioevent_data)) + if (count < sizeof(event)) return -EINVAL; do { + spin_lock(&le->wait.lock); if (kfifo_is_empty(&le->events)) { - if (filep->f_flags & O_NONBLOCK) - return -EAGAIN; + if (bytes_read) { + spin_unlock(&le->wait.lock); + return bytes_read; + } - ret = wait_event_interruptible(le->wait, + if (filep->f_flags & O_NONBLOCK) { + spin_unlock(&le->wait.lock); + return -EAGAIN; + } + + ret = wait_event_interruptible_locked(le->wait, !kfifo_is_empty(&le->events)); - if (ret) + if (ret) { + spin_unlock(&le->wait.lock); return ret; + } } - if (mutex_lock_interruptible(&le->read_lock)) - return -ERESTARTSYS; - ret = kfifo_to_user(&le->events, buf, count, &copied); - mutex_unlock(&le->read_lock); + ret = kfifo_out(&le->events, &event, 1); + spin_unlock(&le->wait.lock); + if (ret != 1) { + /* + * This should never happen - we were holding the lock + * from the moment we learned the fifo is no longer + * empty until now. + */ + ret = -EIO; + break; + } - if (ret) - return ret; + if (copy_to_user(buf + bytes_read, &event, sizeof(event))) + return -EFAULT; + bytes_read += sizeof(event); + } while (count >= bytes_read + sizeof(event)); - /* - * If we couldn't read anything from the fifo (a different - * thread might have been faster) we either return -EAGAIN if - * the file descriptor is non-blocking, otherwise we go back to - * sleep and wait for more data to arrive. - */ - if (copied == 0 && (filep->f_flags & O_NONBLOCK)) - return -EAGAIN; - - } while (copied == 0); - - return copied; + return bytes_read; } static int lineevent_release(struct inode *inode, struct file *filep) @@ -968,7 +974,8 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) return IRQ_NONE; } - ret = kfifo_put(&le->events, ge); + ret = kfifo_in_spinlocked_noirqsave(&le->events, &ge, + 1, &le->wait.lock); if (ret) wake_up_poll(&le->wait, EPOLLIN); @@ -1083,7 +1090,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) INIT_KFIFO(le->events); init_waitqueue_head(&le->wait); - mutex_init(&le->read_lock); /* Request a thread to read the events */ ret = request_threaded_irq(le->irq, From 248ae1752e91438cb7cfc8432b88bc34410e8e4e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 29 Nov 2019 11:22:18 +0100 Subject: [PATCH 014/809] gpiolib: emit a debug message when adding events to a full kfifo Currently if the line-event kfifo is full, we just silently drop any new events. Add a ratelimited debug message so that we at least have some trace in the kernel log of event overflow. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 43d98309e725..36afe0b2b150 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -978,6 +978,8 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) 1, &le->wait.lock); if (ret) wake_up_poll(&le->wait, EPOLLIN); + else + pr_debug_ratelimited("event FIFO is full - event dropped\n"); return IRQ_HANDLED; } From d2ac25798208fb85f866056cd7d8030eb919da99 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 3 Dec 2019 14:08:44 +0100 Subject: [PATCH 015/809] gpiolib: provide a dedicated function for setting lineinfo We'll soon be filling out the gpioline_info structure in multiple places. Add a separate function that given a gpio_desc sets all relevant fields. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib.c | 98 ++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 36afe0b2b150..443321f9cf63 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1147,6 +1147,60 @@ out_free_le: return ret; } +static void gpio_desc_to_lineinfo(struct gpio_desc *desc, + struct gpioline_info *info) +{ + struct gpio_chip *chip = desc->gdev->chip; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + if (desc->name) { + strncpy(info->name, desc->name, sizeof(info->name)); + info->name[sizeof(info->name) - 1] = '\0'; + } else { + info->name[0] = '\0'; + } + + if (desc->label) { + strncpy(info->consumer, desc->label, sizeof(info->consumer)); + info->consumer[sizeof(info->consumer) - 1] = '\0'; + } else { + info->consumer[0] = '\0'; + } + + /* + * Userspace only need to know that the kernel is using this GPIO so + * it can't use it. + */ + info->flags = 0; + if (test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_IS_HOGGED, &desc->flags) || + test_bit(FLAG_USED_AS_IRQ, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags) || + test_bit(FLAG_SYSFS, &desc->flags) || + !pinctrl_gpio_can_use_line(chip->base + info->line_offset)) + info->flags |= GPIOLINE_FLAG_KERNEL; + if (test_bit(FLAG_IS_OUT, &desc->flags)) + info->flags |= GPIOLINE_FLAG_IS_OUT; + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + info->flags |= GPIOLINE_FLAG_ACTIVE_LOW; + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN | + GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE | + GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + info->flags |= GPIOLINE_FLAG_BIAS_DISABLE; + if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; + if (test_bit(FLAG_PULL_UP, &desc->flags)) + info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP; + + spin_unlock_irqrestore(&gpio_lock, flags); +} + /* * gpio_ioctl() - ioctl handler for the GPIO chardev */ @@ -1187,49 +1241,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); - if (desc->name) { - strncpy(lineinfo.name, desc->name, - sizeof(lineinfo.name)); - lineinfo.name[sizeof(lineinfo.name)-1] = '\0'; - } else { - lineinfo.name[0] = '\0'; - } - if (desc->label) { - strncpy(lineinfo.consumer, desc->label, - sizeof(lineinfo.consumer)); - lineinfo.consumer[sizeof(lineinfo.consumer)-1] = '\0'; - } else { - lineinfo.consumer[0] = '\0'; - } - - /* - * Userspace only need to know that the kernel is using - * this GPIO so it can't use it. - */ - lineinfo.flags = 0; - if (test_bit(FLAG_REQUESTED, &desc->flags) || - test_bit(FLAG_IS_HOGGED, &desc->flags) || - test_bit(FLAG_USED_AS_IRQ, &desc->flags) || - test_bit(FLAG_EXPORT, &desc->flags) || - test_bit(FLAG_SYSFS, &desc->flags) || - !pinctrl_gpio_can_use_line(chip->base + lineinfo.line_offset)) - lineinfo.flags |= GPIOLINE_FLAG_KERNEL; - if (test_bit(FLAG_IS_OUT, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_IS_OUT; - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW; - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - lineinfo.flags |= (GPIOLINE_FLAG_OPEN_DRAIN | - GPIOLINE_FLAG_IS_OUT); - if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | - GPIOLINE_FLAG_IS_OUT); - if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE; - if (test_bit(FLAG_PULL_DOWN, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; - if (test_bit(FLAG_PULL_UP, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP; + gpio_desc_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; From 51c1064e82e77b39a49889287ca50709303e2f26 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 22 Nov 2019 15:19:21 +0100 Subject: [PATCH 016/809] gpiolib: add new ioctl() for monitoring changes in line info Currently there is no way for user-space to be informed about changes in status of GPIO lines e.g. when someone else requests the line or its config changes. We can only periodically re-read the line-info. This is fine for simple one-off user-space tools, but any daemon that provides a centralized access to GPIO chips would benefit hugely from an event driven line info synchronization. This patch adds a new ioctl() that allows user-space processes to reuse the file descriptor associated with the character device for watching any changes in line properties. Every such event contains the updated line information. Currently the events are generated on three types of status changes: when a line is requested, when it's released and when its config is changed. The first two are self-explanatory. For the third one: this will only happen when another user-space process calls the new SET_CONFIG ioctl() as any changes that can happen from within the kernel (i.e. set_transitory() or set_debounce()) are of no interest to user-space. Signed-off-by: Bartosz Golaszewski Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 188 ++++++++++++++++++++++++++++++++++++-- drivers/gpio/gpiolib.h | 1 + include/uapi/linux/gpio.h | 30 ++++++ 3 files changed, 210 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 443321f9cf63..f73077f26eff 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -546,6 +546,9 @@ static long linehandle_set_config(struct linehandle_state *lh, if (ret) return ret; } + + atomic_notifier_call_chain(&desc->gdev->notifier, + GPIOLINE_CHANGED_CONFIG, desc); } return 0; } @@ -1201,14 +1204,25 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, spin_unlock_irqrestore(&gpio_lock, flags); } +struct gpio_chardev_data { + struct gpio_device *gdev; + wait_queue_head_t wait; + DECLARE_KFIFO(events, struct gpioline_info_changed, 32); + struct notifier_block lineinfo_changed_nb; + unsigned long *watched_lines; +}; + /* * gpio_ioctl() - ioctl handler for the GPIO chardev */ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct gpio_device *gdev = filp->private_data; + struct gpio_chardev_data *priv = filp->private_data; + struct gpio_device *gdev = priv->gdev; struct gpio_chip *chip = gdev->chip; void __user *ip = (void __user *)arg; + struct gpio_desc *desc; + __u32 offset; /* We fail any subsequent ioctl():s when the chip is gone */ if (!chip) @@ -1230,9 +1244,9 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) return -EFAULT; return 0; - } else if (cmd == GPIO_GET_LINEINFO_IOCTL) { + } else if (cmd == GPIO_GET_LINEINFO_IOCTL || + cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { struct gpioline_info lineinfo; - struct gpio_desc *desc; if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; @@ -1245,11 +1259,25 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; + + if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) + set_bit(desc_to_gpio(desc), priv->watched_lines); + return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { return linehandle_create(gdev, ip); } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { return lineevent_create(gdev, ip); + } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) { + if (copy_from_user(&offset, ip, sizeof(offset))) + return -EFAULT; + + desc = gpiochip_get_desc(chip, offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + clear_bit(desc_to_gpio(desc), &desc->flags); + return 0; } return -EINVAL; } @@ -1262,6 +1290,101 @@ static long gpio_ioctl_compat(struct file *filp, unsigned int cmd, } #endif +static struct gpio_chardev_data * +to_gpio_chardev_data(struct notifier_block *nb) +{ + return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb); +} + +static int lineinfo_changed_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct gpio_chardev_data *priv = to_gpio_chardev_data(nb); + struct gpioline_info_changed chg; + struct gpio_desc *desc = data; + int ret; + + if (!test_bit(desc_to_gpio(desc), priv->watched_lines)) + return NOTIFY_DONE; + + memset(&chg, 0, sizeof(chg)); + chg.info.line_offset = gpio_chip_hwgpio(desc); + chg.event_type = action; + chg.timestamp = ktime_get_ns(); + gpio_desc_to_lineinfo(desc, &chg.info); + + ret = kfifo_in_spinlocked(&priv->events, &chg, 1, &priv->wait.lock); + if (ret) + wake_up_poll(&priv->wait, EPOLLIN); + else + pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n"); + + return NOTIFY_OK; +} + +static __poll_t lineinfo_watch_poll(struct file *filep, + struct poll_table_struct *pollt) +{ + struct gpio_chardev_data *priv = filep->private_data; + __poll_t events = 0; + + poll_wait(filep, &priv->wait, pollt); + + if (!kfifo_is_empty_spinlocked_noirqsave(&priv->events, + &priv->wait.lock)) + events = EPOLLIN | EPOLLRDNORM; + + return events; +} + +static ssize_t lineinfo_watch_read(struct file *filep, char __user *buf, + size_t count, loff_t *off) +{ + struct gpio_chardev_data *priv = filep->private_data; + struct gpioline_info_changed event; + ssize_t bytes_read = 0; + int ret; + + if (count < sizeof(event)) + return -EINVAL; + + do { + spin_lock(&priv->wait.lock); + if (kfifo_is_empty(&priv->events)) { + if (bytes_read) { + spin_unlock(&priv->wait.lock); + return bytes_read; + } + + if (filep->f_flags & O_NONBLOCK) { + spin_unlock(&priv->wait.lock); + return -EAGAIN; + } + + ret = wait_event_interruptible_locked(priv->wait, + !kfifo_is_empty(&priv->events)); + if (ret) { + spin_unlock(&priv->wait.lock); + return ret; + } + } + + ret = kfifo_out(&priv->events, &event, 1); + spin_unlock(&priv->wait.lock); + if (ret != 1) { + ret = -EIO; + break; + /* We should never get here. See lineevent_read(). */ + } + + if (copy_to_user(buf + bytes_read, &event, sizeof(event))) + return -EFAULT; + bytes_read += sizeof(event); + } while (count >= bytes_read + sizeof(event)); + + return bytes_read; +} + /** * gpio_chrdev_open() - open the chardev for ioctl operations * @inode: inode for this chardev @@ -1272,14 +1395,48 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) { struct gpio_device *gdev = container_of(inode->i_cdev, struct gpio_device, chrdev); + struct gpio_chardev_data *priv; + int ret = -ENOMEM; /* Fail on open if the backing gpiochip is gone */ if (!gdev->chip) return -ENODEV; - get_device(&gdev->dev); - filp->private_data = gdev; - return nonseekable_open(inode, filp); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL); + if (!priv->watched_lines) + goto out_free_priv; + + init_waitqueue_head(&priv->wait); + INIT_KFIFO(priv->events); + priv->gdev = gdev; + + priv->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify; + ret = atomic_notifier_chain_register(&gdev->notifier, + &priv->lineinfo_changed_nb); + if (ret) + goto out_free_bitmap; + + get_device(&gdev->dev); + filp->private_data = priv; + + ret = nonseekable_open(inode, filp); + if (ret) + goto out_unregister_notifier; + + return ret; + +out_unregister_notifier: + atomic_notifier_chain_unregister(&gdev->notifier, + &priv->lineinfo_changed_nb); +out_free_bitmap: + bitmap_free(priv->watched_lines); +out_free_priv: + kfree(priv); + return ret; } /** @@ -1290,17 +1447,23 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) */ static int gpio_chrdev_release(struct inode *inode, struct file *filp) { - struct gpio_device *gdev = container_of(inode->i_cdev, - struct gpio_device, chrdev); + struct gpio_chardev_data *priv = filp->private_data; + struct gpio_device *gdev = priv->gdev; + bitmap_free(priv->watched_lines); + atomic_notifier_chain_unregister(&gdev->notifier, + &priv->lineinfo_changed_nb); put_device(&gdev->dev); + kfree(priv); + return 0; } - static const struct file_operations gpio_fileops = { .release = gpio_chrdev_release, .open = gpio_chrdev_open, + .poll = lineinfo_watch_poll, + .read = lineinfo_watch_read, .owner = THIS_MODULE, .llseek = no_llseek, .unlocked_ioctl = gpio_ioctl, @@ -1511,6 +1674,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, spin_unlock_irqrestore(&gpio_lock, flags); + ATOMIC_INIT_NOTIFIER_HEAD(&gdev->notifier); + #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif @@ -2843,6 +3008,8 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) } done: spin_unlock_irqrestore(&gpio_lock, flags); + atomic_notifier_call_chain(&desc->gdev->notifier, + GPIOLINE_CHANGED_REQUESTED, desc); return ret; } @@ -2940,6 +3107,9 @@ static bool gpiod_free_commit(struct gpio_desc *desc) } spin_unlock_irqrestore(&gpio_lock, flags); + atomic_notifier_call_chain(&desc->gdev->notifier, + GPIOLINE_CHANGED_RELEASED, desc); + return ret; } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 3e0aab2945d8..5ab90746b519 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -56,6 +56,7 @@ struct gpio_device { const char *label; void *data; struct list_head list; + struct atomic_notifier_head notifier; #ifdef CONFIG_PINCTRL /* diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 799cf823d493..dca320764e4d 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -59,6 +59,34 @@ struct gpioline_info { /* Maximum number of requested handles */ #define GPIOHANDLES_MAX 64 +/* Possible line status change events */ +enum { + GPIOLINE_CHANGED_REQUESTED = 1, + GPIOLINE_CHANGED_RELEASED, + GPIOLINE_CHANGED_CONFIG, +}; + +/** + * struct gpioline_info_changed - Information about a change in status + * of a GPIO line + * @info: updated line information + * @timestamp: estimate of time of status change occurrence, in nanoseconds + * and GPIOLINE_CHANGED_CONFIG + * @event_type: one of GPIOLINE_CHANGED_REQUESTED, GPIOLINE_CHANGED_RELEASED + * + * Note: struct gpioline_info embedded here has 32-bit alignment on its own, + * but it works fine with 64-bit alignment too. With its 72 byte size, we can + * guarantee there are no implicit holes between it and subsequent members. + * The 20-byte padding at the end makes sure we don't add any implicit padding + * at the end of the structure on 64-bit architectures. + */ +struct gpioline_info_changed { + struct gpioline_info info; + __u64 timestamp; + __u32 event_type; + __u32 padding[5]; /* for future use */ +}; + /* Linerequest flags */ #define GPIOHANDLE_REQUEST_INPUT (1UL << 0) #define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1) @@ -176,6 +204,8 @@ struct gpioevent_data { #define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info) #define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info) +#define GPIO_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x0b, struct gpioline_info) +#define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0c, __u32) #define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request) #define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request) From 33f0c47b8fb4724792b16351a32b24902a5d3b07 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 27 Nov 2019 10:17:54 +0100 Subject: [PATCH 017/809] tools: gpio: implement gpio-watch Add a simple program that allows to test the new LINECHANGED_FD ioctl(). Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko --- tools/gpio/.gitignore | 1 + tools/gpio/Build | 1 + tools/gpio/Makefile | 11 ++++- tools/gpio/gpio-watch.c | 99 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 tools/gpio/gpio-watch.c diff --git a/tools/gpio/.gitignore b/tools/gpio/.gitignore index a94c0e83b209..eab36c6d7751 100644 --- a/tools/gpio/.gitignore +++ b/tools/gpio/.gitignore @@ -1,4 +1,5 @@ gpio-event-mon gpio-hammer +gpio-watch lsgpio include/linux/gpio.h diff --git a/tools/gpio/Build b/tools/gpio/Build index 4141f35837db..67c7b7f6a717 100644 --- a/tools/gpio/Build +++ b/tools/gpio/Build @@ -2,3 +2,4 @@ gpio-utils-y += gpio-utils.o lsgpio-y += lsgpio.o gpio-utils.o gpio-hammer-y += gpio-hammer.o gpio-utils.o gpio-event-mon-y += gpio-event-mon.o gpio-utils.o +gpio-watch-y += gpio-watch.o diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 6080de58861f..842287e42c83 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -18,7 +18,7 @@ MAKEFLAGS += -r override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon +ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon gpio-watch ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) all: $(ALL_PROGRAMS) @@ -66,6 +66,15 @@ $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o $(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ +# +# gpio-watch +# +GPIO_WATCH_IN := $(OUTPUT)gpio-watch-in.o +$(GPIO_WATCH_IN): prepare FORCE + $(Q)$(MAKE) $(build)=gpio-watch +$(OUTPUT)gpio-watch: $(GPIO_WATCH_IN) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + clean: rm -f $(ALL_PROGRAMS) rm -f $(OUTPUT)include/linux/gpio.h diff --git a/tools/gpio/gpio-watch.c b/tools/gpio/gpio-watch.c new file mode 100644 index 000000000000..5cea24fddfa7 --- /dev/null +++ b/tools/gpio/gpio-watch.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * gpio-watch - monitor unrequested lines for property changes using the + * character device + * + * Copyright (C) 2019 BayLibre SAS + * Author: Bartosz Golaszewski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + struct gpioline_info_changed chg; + struct gpioline_info req; + struct pollfd pfd; + int fd, i, j, ret; + char *event, *end; + ssize_t rd; + + if (argc < 3) + goto err_usage; + + fd = open(argv[1], O_RDWR | O_CLOEXEC); + if (fd < 0) { + perror("unable to open gpiochip"); + return EXIT_FAILURE; + } + + for (i = 0, j = 2; i < argc - 2; i++, j++) { + memset(&req, 0, sizeof(req)); + + req.line_offset = strtoul(argv[j], &end, 0); + if (*end != '\0') + goto err_usage; + + ret = ioctl(fd, GPIO_GET_LINEINFO_WATCH_IOCTL, &req); + if (ret) { + perror("unable to set up line watch"); + return EXIT_FAILURE; + } + } + + pfd.fd = fd; + pfd.events = POLLIN | POLLPRI; + + for (;;) { + ret = poll(&pfd, 1, 5000); + if (ret < 0) { + perror("error polling the linechanged fd"); + return EXIT_FAILURE; + } else if (ret > 0) { + memset(&chg, 0, sizeof(chg)); + rd = read(pfd.fd, &chg, sizeof(chg)); + if (rd < 0 || rd != sizeof(chg)) { + if (rd != sizeof(chg)) + errno = EIO; + + perror("error reading line change event"); + return EXIT_FAILURE; + } + + switch (chg.event_type) { + case GPIOLINE_CHANGED_REQUESTED: + event = "requested"; + break; + case GPIOLINE_CHANGED_RELEASED: + event = "released"; + break; + case GPIOLINE_CHANGED_CONFIG: + event = "config changed"; + break; + default: + fprintf(stderr, + "invalid event type received from the kernel\n"); + return EXIT_FAILURE; + } + + printf("line %u: %s at %llu\n", + chg.info.line_offset, event, chg.timestamp); + } + } + + return 0; + +err_usage: + printf("%s: ...\n", argv[0]); + return EXIT_FAILURE; +} From 38a49742de113746dfb954afe7b1b65a098a69a8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Feb 2020 09:48:36 +0100 Subject: [PATCH 018/809] rtc: sh: Restore devm_ioremap() alignment The alignment of the continuation of the devm_ioremap() call in sh_rtc_probe() was broken. Join the lines, as all parameters can fit on a single line. Fixes: 4bdc0d676a643140 ("remove ioremap_nocache and devm_ioremap_nocache") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200212084836.9511-1-geert+renesas@glider.be Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index feb1f8e52c00..9167b48014a1 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -504,8 +504,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) if (unlikely(!rtc->res)) return -EBUSY; - rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, - rtc->regsize); + rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, rtc->regsize); if (unlikely(!rtc->regbase)) return -EINVAL; From 4594d082dbe6385c2df6b838817ccd214c16b358 Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Wed, 12 Feb 2020 15:54:39 +0530 Subject: [PATCH 019/809] rtc: zynqmp: Clear alarm interrupt status before interrupt enable Fix multiple occurring interrupts for alarm interrupt. RTC module doesn't clear the alarm interrupt status bit immediately after the interrupt is triggered.This is due to the sticky nature of the alarm interrupt status register. The alarm interrupt status register can be cleared only after the second counter outruns the set alarm value. To fix multiple spurious interrupts, disable alarm interrupt in the handler and clear the status bit before enabling the alarm interrupt. Fixes: 11143c19eb57 ("rtc: add xilinx zynqmp rtc driver") Signed-off-by: Srinivas Neeli Acked-by: Michal Simek Link: https://lore.kernel.org/r/1581503079-387-1-git-send-email-srinivas.neeli@xilinx.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-zynqmp.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index 5786866c09e9..4b1077e2f826 100644 --- a/drivers/rtc/rtc-zynqmp.c +++ b/drivers/rtc/rtc-zynqmp.c @@ -38,6 +38,8 @@ #define RTC_CALIB_DEF 0x198233 #define RTC_CALIB_MASK 0x1FFFFF +#define RTC_ALRM_MASK BIT(1) +#define RTC_MSEC 1000 struct xlnx_rtc_dev { struct rtc_device *rtc; @@ -123,11 +125,28 @@ static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled) { struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned int status; + ulong timeout; + + timeout = jiffies + msecs_to_jiffies(RTC_MSEC); + + if (enabled) { + while (1) { + status = readl(xrtcdev->reg_base + RTC_INT_STS); + if (!((status & RTC_ALRM_MASK) == RTC_ALRM_MASK)) + break; + + if (time_after_eq(jiffies, timeout)) { + dev_err(dev, "Time out occur, while clearing alarm status bit\n"); + return -ETIMEDOUT; + } + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS); + } - if (enabled) writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN); - else + } else { writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); + } return 0; } @@ -183,8 +202,8 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) return IRQ_NONE; - /* Clear RTC_INT_ALRM interrupt only */ - writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS); + /* Disable RTC_INT_ALRM interrupt only */ + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); if (status & RTC_INT_ALRM) rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); From 2b48dcb7a821fc38e0be3e171bd02e058196ccf1 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:30 +0100 Subject: [PATCH 020/809] clk: sunxi-ng: sun8i-de2: Split out H5 definitions H5 has less clocks and resets than A64. Currently that's not obvious because A64 is missing rotation core related clocks and reset. Split out H5 definition. A64 structures will be fixed in subsequent commit. Note that this patch depends on commit 19368d99746e ("clk: sunxi-ng: add support for Allwinner H3 DE2 CCU") for the H3 clock list. Fixes: 763c5bd045b1 ("clk: sunxi-ng: add support for DE2 CCU") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index d9668493c3f9..2478ae314d0f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -192,6 +192,12 @@ static struct ccu_reset_map sun50i_a64_de2_resets[] = { [RST_WB] = { 0x08, BIT(2) }, }; +static struct ccu_reset_map sun50i_h5_de2_resets[] = { + [RST_MIXER0] = { 0x08, BIT(0) }, + [RST_MIXER1] = { 0x08, BIT(1) }, + [RST_WB] = { 0x08, BIT(2) }, +}; + static struct ccu_reset_map sun50i_h6_de3_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, [RST_MIXER1] = { 0x08, BIT(1) }, @@ -229,6 +235,16 @@ static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun50i_a64_de2_resets), }; +static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = { + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), + + .hw_clks = &sun8i_h3_de2_hw_clks, + + .resets = sun50i_h5_de2_resets, + .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets), +}; + static const struct sunxi_ccu_desc sun50i_h6_de3_clk_desc = { .ccu_clks = sun50i_h6_de3_clks, .num_ccu_clks = ARRAY_SIZE(sun50i_h6_de3_clks), @@ -347,7 +363,7 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { }, { .compatible = "allwinner,sun50i-h5-de2-clk", - .data = &sun50i_a64_de2_clk_desc, + .data = &sun50i_h5_de2_clk_desc, }, { .compatible = "allwinner,sun50i-h6-de3-clk", From b4bbce660a3694811b5500c40b9cd69513b50d38 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:31 +0100 Subject: [PATCH 021/809] clk: sunxi-ng: sun8i-de2: Add rotation core clocks and reset for A64 A64 has rotation core which needs clocks and reset. Because there is no appropriate structures available, make a separate, A64 specific structures. Fixes: cf4881c12935 ("clk: sunxi-ng: fix the A64/H5 clock description of DE2 CCU") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 45 ++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 2478ae314d0f..c6220be8e205 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -108,6 +108,24 @@ static struct ccu_common *sun8i_v3s_de2_clks[] = { &wb_div_clk.common, }; +static struct ccu_common *sun50i_a64_de2_clks[] = { + &mixer0_clk.common, + &mixer1_clk.common, + &wb_clk.common, + + &bus_mixer0_clk.common, + &bus_mixer1_clk.common, + &bus_wb_clk.common, + + &mixer0_div_clk.common, + &mixer1_div_clk.common, + &wb_div_clk.common, + + &bus_rot_clk.common, + &rot_clk.common, + &rot_div_clk.common, +}; + static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { .hws = { [CLK_MIXER0] = &mixer0_clk.common.hw, @@ -156,6 +174,26 @@ static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = { .num = CLK_NUMBER_WITHOUT_ROT, }; +static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = { + .hws = { + [CLK_MIXER0] = &mixer0_clk.common.hw, + [CLK_MIXER1] = &mixer1_clk.common.hw, + [CLK_WB] = &wb_clk.common.hw, + [CLK_ROT] = &rot_clk.common.hw, + + [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, + [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, + [CLK_BUS_WB] = &bus_wb_clk.common.hw, + [CLK_BUS_ROT] = &bus_rot_clk.common.hw, + + [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, + [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, + [CLK_WB_DIV] = &wb_div_clk.common.hw, + [CLK_ROT_DIV] = &rot_div_clk.common.hw, + }, + .num = CLK_NUMBER_WITH_ROT, +}; + static struct clk_hw_onecell_data sun50i_h6_de3_hw_clks = { .hws = { [CLK_MIXER0] = &mixer0_clk.common.hw, @@ -190,6 +228,7 @@ static struct ccu_reset_map sun50i_a64_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, [RST_MIXER1] = { 0x08, BIT(1) }, [RST_WB] = { 0x08, BIT(2) }, + [RST_ROT] = { 0x08, BIT(3) }, }; static struct ccu_reset_map sun50i_h5_de2_resets[] = { @@ -226,10 +265,10 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { }; static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { - .ccu_clks = sun8i_h3_de2_clks, - .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), + .ccu_clks = sun50i_a64_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a64_de2_clks), - .hw_clks = &sun8i_h3_de2_hw_clks, + .hw_clks = &sun50i_a64_de2_hw_clks, .resets = sun50i_a64_de2_resets, .num_resets = ARRAY_SIZE(sun50i_a64_de2_resets), From 75250eb75c828eebda77e23f44de0f037546ea9a Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:32 +0100 Subject: [PATCH 022/809] clk: sunxi-ng: sun8i-de2: H6 doesn't have rotate core DE3 documentation regarding presence of rotate core in H6 is a bit confusing. Register descriptions mention bits for enabling rotate core clocks and reset, but general overview doesn't list it as feature of H6 display engine, BSP kernel doesn't support it and there is no interrupt listed for it. Manual poking registers also didn't reveal presence of rotate core. Let's assume there isn't any rotate core on H6 present and remove related clocks. With that done, structures are same as those for H5, so just reuse H5 structure. Fixes: 56808da9f97f ("clk: sunxi-ng: Add support for H6 DE3 clocks") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 57 +--------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index c6220be8e205..87a30d072ae9 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -51,24 +51,6 @@ static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4, static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); -static struct ccu_common *sun50i_h6_de3_clks[] = { - &mixer0_clk.common, - &mixer1_clk.common, - &wb_clk.common, - - &bus_mixer0_clk.common, - &bus_mixer1_clk.common, - &bus_wb_clk.common, - - &mixer0_div_clk.common, - &mixer1_div_clk.common, - &wb_div_clk.common, - - &bus_rot_clk.common, - &rot_clk.common, - &rot_div_clk.common, -}; - static struct ccu_common *sun8i_a83t_de2_clks[] = { &mixer0_clk.common, &mixer1_clk.common, @@ -194,26 +176,6 @@ static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = { .num = CLK_NUMBER_WITH_ROT, }; -static struct clk_hw_onecell_data sun50i_h6_de3_hw_clks = { - .hws = { - [CLK_MIXER0] = &mixer0_clk.common.hw, - [CLK_MIXER1] = &mixer1_clk.common.hw, - [CLK_WB] = &wb_clk.common.hw, - [CLK_ROT] = &rot_clk.common.hw, - - [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, - [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, - [CLK_BUS_WB] = &bus_wb_clk.common.hw, - [CLK_BUS_ROT] = &bus_rot_clk.common.hw, - - [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, - [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, - [CLK_WB_DIV] = &wb_div_clk.common.hw, - [CLK_ROT_DIV] = &rot_div_clk.common.hw, - }, - .num = CLK_NUMBER_WITH_ROT, -}; - static struct ccu_reset_map sun8i_a83t_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, /* @@ -237,13 +199,6 @@ static struct ccu_reset_map sun50i_h5_de2_resets[] = { [RST_WB] = { 0x08, BIT(2) }, }; -static struct ccu_reset_map sun50i_h6_de3_resets[] = { - [RST_MIXER0] = { 0x08, BIT(0) }, - [RST_MIXER1] = { 0x08, BIT(1) }, - [RST_WB] = { 0x08, BIT(2) }, - [RST_ROT] = { 0x08, BIT(3) }, -}; - static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = { .ccu_clks = sun8i_a83t_de2_clks, .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_de2_clks), @@ -284,16 +239,6 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets), }; -static const struct sunxi_ccu_desc sun50i_h6_de3_clk_desc = { - .ccu_clks = sun50i_h6_de3_clks, - .num_ccu_clks = ARRAY_SIZE(sun50i_h6_de3_clks), - - .hw_clks = &sun50i_h6_de3_hw_clks, - - .resets = sun50i_h6_de3_resets, - .num_resets = ARRAY_SIZE(sun50i_h6_de3_resets), -}; - static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = { .ccu_clks = sun8i_v3s_de2_clks, .num_ccu_clks = ARRAY_SIZE(sun8i_v3s_de2_clks), @@ -406,7 +351,7 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { }, { .compatible = "allwinner,sun50i-h6-de3-clk", - .data = &sun50i_h6_de3_clk_desc, + .data = &sun50i_h5_de2_clk_desc, }, { } }; From 8f9b11a33ad6976e17e7279a170864a1fc613803 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:33 +0100 Subject: [PATCH 023/809] clk: sunxi-ng: sun8i-de2: Don't reuse A83T resets Currently, V3s and H3 reuse A83T reset structure. However, A83T contains additional core for rotation, which is not present in V3s and H3. Make new reset structure for H3 and let V3s reuse it. A83T reset structure will be amended in subsequent commit. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 87a30d072ae9..bbbe1ed7aba1 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -179,9 +179,18 @@ static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = { static struct ccu_reset_map sun8i_a83t_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, /* - * For A83T, H3 and R40, mixer1 reset line is shared with wb, so - * only RST_WB is exported here. - * For V3s there's just no mixer1, so it also shares this struct. + * Mixer1 reset line is shared with wb, so only RST_WB is + * exported here. + */ + [RST_WB] = { 0x08, BIT(2) }, +}; + +static struct ccu_reset_map sun8i_h3_de2_resets[] = { + [RST_MIXER0] = { 0x08, BIT(0) }, + /* + * Mixer1 reset line is shared with wb, so only RST_WB is + * exported here. + * V3s doesn't have mixer1, so it also shares this struct. */ [RST_WB] = { 0x08, BIT(2) }, }; @@ -215,8 +224,8 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { .hw_clks = &sun8i_h3_de2_hw_clks, - .resets = sun8i_a83t_de2_resets, - .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), + .resets = sun8i_h3_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_h3_de2_resets), }; static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { @@ -245,8 +254,8 @@ static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = { .hw_clks = &sun8i_v3s_de2_hw_clks, - .resets = sun8i_a83t_de2_resets, - .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), + .resets = sun8i_h3_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_h3_de2_resets), }; static int sunxi_de2_clk_probe(struct platform_device *pdev) From b0bfba905cf81d540acaac7a4b23459f7df1bb24 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:34 +0100 Subject: [PATCH 024/809] clk: sunxi-ng: sun8i-de2: Add rotation core clocks and reset for A83T A83T structures don't have clocks and reset for rotation core. Add them. Fixes: 763c5bd045b1 ("clk: sunxi-ng: add support for DE2 CCU") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index bbbe1ed7aba1..9656553c01f3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -50,6 +50,8 @@ static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4, CLK_SET_RATE_PARENT); static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(rot_div_a83_clk, "rot-div", "pll-de", 0x0c, 0x0c, 4, + CLK_SET_RATE_PARENT); static struct ccu_common *sun8i_a83t_de2_clks[] = { &mixer0_clk.common, @@ -63,6 +65,10 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = { &mixer0_div_a83_clk.common, &mixer1_div_a83_clk.common, &wb_div_a83_clk.common, + + &bus_rot_clk.common, + &rot_clk.common, + &rot_div_a83_clk.common, }; static struct ccu_common *sun8i_h3_de2_clks[] = { @@ -113,16 +119,19 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { [CLK_MIXER0] = &mixer0_clk.common.hw, [CLK_MIXER1] = &mixer1_clk.common.hw, [CLK_WB] = &wb_clk.common.hw, + [CLK_ROT] = &rot_clk.common.hw, [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, [CLK_BUS_WB] = &bus_wb_clk.common.hw, + [CLK_BUS_ROT] = &bus_rot_clk.common.hw, [CLK_MIXER0_DIV] = &mixer0_div_a83_clk.common.hw, [CLK_MIXER1_DIV] = &mixer1_div_a83_clk.common.hw, [CLK_WB_DIV] = &wb_div_a83_clk.common.hw, + [CLK_ROT_DIV] = &rot_div_a83_clk.common.hw, }, - .num = CLK_NUMBER_WITHOUT_ROT, + .num = CLK_NUMBER_WITH_ROT, }; static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = { @@ -183,6 +192,7 @@ static struct ccu_reset_map sun8i_a83t_de2_resets[] = { * exported here. */ [RST_WB] = { 0x08, BIT(2) }, + [RST_ROT] = { 0x08, BIT(3) }, }; static struct ccu_reset_map sun8i_h3_de2_resets[] = { From 11d0c436ffed1dba397e9adec9eaebfe7eef2d10 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:35 +0100 Subject: [PATCH 025/809] clk: sunxi-ng: sun8i-de2: Add R40 specific quirks R40 is actually very similar to A64, but it doesn't have mixer1 reset. This means it's clocks and resets combination is unique and R40 specific quirks are needed. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 9656553c01f3..5a278c391f1d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -238,6 +238,16 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_h3_de2_resets), }; +static const struct sunxi_ccu_desc sun8i_r40_de2_clk_desc = { + .ccu_clks = sun50i_a64_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a64_de2_clks), + + .hw_clks = &sun50i_a64_de2_hw_clks, + + .resets = sun8i_a83t_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), +}; + static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { .ccu_clks = sun50i_a64_de2_clks, .num_ccu_clks = ARRAY_SIZE(sun50i_a64_de2_clks), @@ -356,6 +366,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { .compatible = "allwinner,sun8i-h3-de2-clk", .data = &sun8i_h3_de2_clk_desc, }, + { + .compatible = "allwinner,sun8i-r40-de2-clk", + .data = &sun8i_r40_de2_clk_desc, + }, { .compatible = "allwinner,sun8i-v3s-de2-clk", .data = &sun8i_v3s_de2_clk_desc, From b998b75f8603c37c8a43a3d849cd2c4929adf402 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 11 Feb 2020 19:59:36 +0100 Subject: [PATCH 026/809] clk: sunxi-ng: sun8i-de2: Sort structures V3s quirks are not in right place. Move it. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 5a278c391f1d..524f33275bc7 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -248,6 +248,16 @@ static const struct sunxi_ccu_desc sun8i_r40_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), }; +static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = { + .ccu_clks = sun8i_v3s_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_v3s_de2_clks), + + .hw_clks = &sun8i_v3s_de2_hw_clks, + + .resets = sun8i_a83t_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), +}; + static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { .ccu_clks = sun50i_a64_de2_clks, .num_ccu_clks = ARRAY_SIZE(sun50i_a64_de2_clks), @@ -268,16 +278,6 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets), }; -static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = { - .ccu_clks = sun8i_v3s_de2_clks, - .num_ccu_clks = ARRAY_SIZE(sun8i_v3s_de2_clks), - - .hw_clks = &sun8i_v3s_de2_hw_clks, - - .resets = sun8i_h3_de2_resets, - .num_resets = ARRAY_SIZE(sun8i_h3_de2_resets), -}; - static int sunxi_de2_clk_probe(struct platform_device *pdev) { struct resource *res; From 04ac0ad7e8edc7f1a7b3e219db245060fcaf59a4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 10 Feb 2020 09:31:05 +0530 Subject: [PATCH 027/809] dt-bindings: clk: qcom: Add support for GPU GX GDSCR In the cases where the GPU SW requires to use the GX GDSCR add support for the same. Signed-off-by: Taniya Das Link: https://lkml.kernel.org/r/1581307266-26989-1-git-send-email-tdas@codeaurora.org Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/qcom,gpucc-sc7180.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/qcom,gpucc-sc7180.h b/include/dt-bindings/clock/qcom,gpucc-sc7180.h index 0e4643b08b49..65e706d7d9c6 100644 --- a/include/dt-bindings/clock/qcom,gpucc-sc7180.h +++ b/include/dt-bindings/clock/qcom,gpucc-sc7180.h @@ -15,7 +15,8 @@ #define GPU_CC_CXO_CLK 6 #define GPU_CC_GMU_CLK_SRC 7 -/* CAM_CC GDSCRs */ +/* GPU_CC GDSCRs */ #define CX_GDSC 0 +#define GX_GDSC 1 #endif From 1a6151128c847c473da1c7e7022ef78d3e2d6689 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 10 Feb 2020 09:31:06 +0530 Subject: [PATCH 028/809] clk: qcom: gpucc: Add support for GX GDSC for SC7180 Most of the time the CPU should not be touching the GX domain on the GPU except for a very special use case when the CPU needs to force the GX headswitch off. Add the GX domain for that use case. As part of this add a dummy enable function for the GX gdsc to simulate success so that the pm_runtime reference counting is correct. This matches what was done in sdm845 in commit 85a3d920d30a ("clk: qcom: Add a dummy enable function for GX gdsc"). Signed-off-by: Taniya Das Reviewed-by: Douglas Anderson Link: https://lkml.kernel.org/r/1581307266-26989-2-git-send-email-tdas@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gpucc-sc7180.c | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c index a96c0b945de2..7b656b6aeced 100644 --- a/drivers/clk/qcom/gpucc-sc7180.c +++ b/drivers/clk/qcom/gpucc-sc7180.c @@ -170,8 +170,45 @@ static struct gdsc cx_gdsc = { .flags = VOTABLE, }; +/* + * On SC7180 the GPU GX domain is *almost* entirely controlled by the GMU + * running in the CX domain so the CPU doesn't need to know anything about the + * GX domain EXCEPT.... + * + * Hardware constraints dictate that the GX be powered down before the CX. If + * the GMU crashes it could leave the GX on. In order to successfully bring back + * the device the CPU needs to disable the GX headswitch. There being no sane + * way to reach in and touch that register from deep inside the GPU driver we + * need to set up the infrastructure to be able to ensure that the GPU can + * ensure that the GX is off during this super special case. We do this by + * defining a GX gdsc with a dummy enable function and a "default" disable + * function. + * + * This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU + * driver. During power up, nothing will happen from the CPU (and the GMU will + * power up normally but during power down this will ensure that the GX domain + * is *really* off - this gives us a semi standard way of doing what we need. + */ +static int gx_gdsc_enable(struct generic_pm_domain *domain) +{ + /* Do nothing but give genpd the impression that we were successful */ + return 0; +} + +static struct gdsc gx_gdsc = { + .gdscr = 0x100c, + .clamp_io_ctrl = 0x1508, + .pd = { + .name = "gx_gdsc", + .power_on = gx_gdsc_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO, +}; + static struct gdsc *gpu_cc_sc7180_gdscs[] = { [CX_GDSC] = &cx_gdsc, + [GX_GDSC] = &gx_gdsc, }; static struct clk_regmap *gpu_cc_sc7180_clocks[] = { From f78f29079327a2f0052096f65a06f66838e82b70 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 4 Feb 2020 22:54:21 -0800 Subject: [PATCH 029/809] clk: qcom: alpha-pll: Make error prints more informative I recently ran across this printk error message spewing in my logs Call set rate on the PLL with rounded rates! and I had no idea what clk that was or what rate was failing to round properly. Make the printk more informative by telling us what went wrong and also add the name of the clk that's failing to change rate. Furthermore, update the other printks in this file with the clk name each time so we know what clk we're talking about. Cc: Taniya Das Cc: Venkata Narendra Kumar Gutta Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200205065421.9426-1-swboyd@chromium.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 7c2936da9b14..6d946770a80f 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -544,7 +544,8 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); vco = alpha_pll_find_vco(pll, rate); if (pll->vco_table && !vco) { - pr_err("alpha pll not in a valid vco range\n"); + pr_err("%s: alpha pll not in a valid vco range\n", + clk_hw_get_name(hw)); return -EINVAL; } @@ -722,7 +723,7 @@ static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate, */ if (clk_alpha_pll_is_enabled(hw)) { if (cur_alpha != a) { - pr_err("clock needs to be gated %s\n", + pr_err("%s: clock needs to be gated\n", clk_hw_get_name(hw)); return -EBUSY; } @@ -1170,7 +1171,7 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, alpha_width = pll_alpha_width(pll); u64 a; - unsigned long rrate; + unsigned long rrate, max = rate + FABIA_PLL_RATE_MARGIN; rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); @@ -1178,8 +1179,9 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, * Due to limited number of bits for fractional rate programming, the * rounded up rate could be marginally higher than the requested rate. */ - if (rrate > (rate + FABIA_PLL_RATE_MARGIN) || rrate < rate) { - pr_err("Call set rate on the PLL with rounded rates!\n"); + if (rrate > max || rrate < rate) { + pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n", + clk_hw_get_name(hw), rrate, rate, max); return -EINVAL; } @@ -1196,6 +1198,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw) struct clk_hw *parent_hw; unsigned long cal_freq, rrate; u32 cal_l, val, alpha_width = pll_alpha_width(pll); + const char *name = clk_hw_get_name(hw); u64 a; int ret; @@ -1210,7 +1213,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw) vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw)); if (!vco) { - pr_err("alpha pll: not in a valid vco range\n"); + pr_err("%s: alpha pll not in a valid vco range\n", name); return -EINVAL; } @@ -1236,7 +1239,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw) /* Bringup the PLL at calibration frequency */ ret = clk_alpha_pll_enable(hw); if (ret) { - pr_err("alpha pll calibration failed\n"); + pr_err("%s: alpha pll calibration failed\n", name); return ret; } From fdd373a4e0c859c64149aaacd082b6f4e58a6489 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 24 Jan 2020 14:32:21 -0800 Subject: [PATCH 030/809] dt-bindings: clock: Add RPMHCC bindings for SM8250 Add bindings and update documentation for clock rpmh driver on SM8250. Acked-by: Rob Herring Reviewed-by: Vinod Koul Reviewed-by: Bjorn Andersson Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Link: https://lkml.kernel.org/r/1579905147-12142-2-git-send-email-vnkgutta@codeaurora.org Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + include/dt-bindings/clock/qcom,rpmh.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index 2cd158f13bab..2b633a4b0bc2 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -20,6 +20,7 @@ properties: - qcom,sc7180-rpmh-clk - qcom,sdm845-rpmh-clk - qcom,sm8150-rpmh-clk + - qcom,sm8250-rpmh-clk clocks: maxItems: 1 diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index edcab3f7b7d3..2e6c54e65455 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. */ #ifndef _DT_BINDINGS_CLK_MSM_RPMH_H @@ -19,5 +19,7 @@ #define RPMH_RF_CLK3 10 #define RPMH_RF_CLK3_A 11 #define RPMH_IPA_CLK 12 +#define RPMH_LN_BB_CLK1 13 +#define RPMH_LN_BB_CLK1_A 14 #endif From 29093b1a5833c24c692abb1370de547d2a60e6be Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 24 Jan 2020 14:32:22 -0800 Subject: [PATCH 031/809] clk: qcom: rpmh: Add support for RPMH clocks on SM8250 Add support for RPMH clocks on SM8250. Reviewed-by: Vinod Koul Reviewed-by: Bjorn Andersson Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Link: https://lkml.kernel.org/r/1579905147-12142-3-git-send-email-vnkgutta@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 98a118c1e244..12bd8715dece 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -404,6 +404,28 @@ static const struct clk_rpmh_desc clk_rpmh_sc7180 = { .num_clks = ARRAY_SIZE(sc7180_rpmh_clocks), }; +DEFINE_CLK_RPMH_VRM(sm8250, ln_bb_clk1, ln_bb_clk1_ao, "lnbclka1", 2); + +static struct clk_hw *sm8250_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, + [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, + [RPMH_LN_BB_CLK1] = &sm8250_ln_bb_clk1.hw, + [RPMH_LN_BB_CLK1_A] = &sm8250_ln_bb_clk1_ao.hw, + [RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw, + [RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw, + [RPMH_LN_BB_CLK3] = &sdm845_ln_bb_clk3.hw, + [RPMH_LN_BB_CLK3_A] = &sdm845_ln_bb_clk3_ao.hw, + [RPMH_RF_CLK1] = &sdm845_rf_clk1.hw, + [RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw, + [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, + [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sm8250 = { + .clks = sm8250_rpmh_clocks, + .num_clks = ARRAY_SIZE(sm8250_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -490,6 +512,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180}, { .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845}, { .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150}, + { .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); From f21cf9c77ee82ef8adfeb2143adfacf21ec1d5cc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 5 Feb 2020 15:27:59 -0800 Subject: [PATCH 032/809] clk: Don't cache errors from clk_ops::get_phase() We don't check for errors from clk_ops::get_phase() before storing away the result into the clk_core::phase member. This can lead to some fairly confusing debugfs information if these ops do return an error. Let's skip the store when this op fails to fix this. While we're here, move the locking outside of clk_core_get_phase() to simplify callers from the debugfs side. Cc: Douglas Anderson Cc: Heiko Stuebner Cc: Jerome Brunet Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200205232802.29184-2-sboyd@kernel.org Acked-by: Jerome Brunet --- drivers/clk/clk.c | 48 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f0f2b599fd7e..82d96d4071b1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2660,12 +2660,14 @@ static int clk_core_get_phase(struct clk_core *core) { int ret; - clk_prepare_lock(); + lockdep_assert_held(&prepare_lock); + if (!core->ops->get_phase) + return 0; + /* Always try to update cached phase if possible */ - if (core->ops->get_phase) - core->phase = core->ops->get_phase(core->hw); - ret = core->phase; - clk_prepare_unlock(); + ret = core->ops->get_phase(core->hw); + if (ret >= 0) + core->phase = ret; return ret; } @@ -2679,10 +2681,16 @@ static int clk_core_get_phase(struct clk_core *core) */ int clk_get_phase(struct clk *clk) { + int ret; + if (!clk) return 0; - return clk_core_get_phase(clk->core); + clk_prepare_lock(); + ret = clk_core_get_phase(clk->core); + clk_prepare_unlock(); + + return ret; } EXPORT_SYMBOL_GPL(clk_get_phase); @@ -2896,13 +2904,21 @@ static struct hlist_head *orphan_list[] = { static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, int level) { - seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n", + int phase; + + seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ", level * 3 + 1, "", 30 - level * 3, c->name, c->enable_count, c->prepare_count, c->protect_count, - clk_core_get_rate(c), clk_core_get_accuracy(c), - clk_core_get_phase(c), - clk_core_get_scaled_duty_cycle(c, 100000)); + clk_core_get_rate(c), clk_core_get_accuracy(c)); + + phase = clk_core_get_phase(c); + if (phase >= 0) + seq_printf(s, "%5d", phase); + else + seq_puts(s, "-----"); + + seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000)); } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -2939,6 +2955,7 @@ DEFINE_SHOW_ATTRIBUTE(clk_summary); static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) { + int phase; unsigned long min_rate, max_rate; clk_core_get_boundaries(c, &min_rate, &max_rate); @@ -2952,7 +2969,9 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"min_rate\": %lu,", min_rate); seq_printf(s, "\"max_rate\": %lu,", max_rate); seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); - seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c)); + phase = clk_core_get_phase(c); + if (phase >= 0) + seq_printf(s, "\"phase\": %d,", phase); seq_printf(s, "\"duty_cycle\": %u", clk_core_get_scaled_duty_cycle(c, 100000)); } @@ -3434,14 +3453,11 @@ static int __clk_core_init(struct clk_core *core) core->accuracy = 0; /* - * Set clk's phase. + * Set clk's phase by clk_core_get_phase() caching the phase. * Since a phase is by definition relative to its parent, just * query the current clock phase, or just assume it's in phase. */ - if (core->ops->get_phase) - core->phase = core->ops->get_phase(core->hw); - else - core->phase = 0; + clk_core_get_phase(core); /* * Set clk's duty cycle. From 768a5d4f63c29d3bed5abb3c187312fcf623fa05 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 5 Feb 2020 15:28:00 -0800 Subject: [PATCH 033/809] clk: Use 'parent' to shorten lines in __clk_core_init() Some lines are getting long in this function. Let's move 'parent' up to the top of the function and use it in many places whenever there is a parent for a clk. This shortens some lines by avoiding core->parent-> indirections. Cc: Douglas Anderson Cc: Heiko Stuebner Cc: Jerome Brunet Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200205232802.29184-3-sboyd@kernel.org Acked-by: Jerome Brunet --- drivers/clk/clk.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 82d96d4071b1..3ddca6084e8e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3342,6 +3342,7 @@ static void clk_core_reparent_orphans_nolock(void) static int __clk_core_init(struct clk_core *core) { int ret; + struct clk_core *parent; unsigned long rate; if (!core) @@ -3413,7 +3414,7 @@ static int __clk_core_init(struct clk_core *core) goto out; } - core->parent = __clk_init_parent(core); + parent = core->parent = __clk_init_parent(core); /* * Populate core->parent if parent has already been clk_core_init'd. If @@ -3425,10 +3426,9 @@ static int __clk_core_init(struct clk_core *core) * clocks and re-parent any that are children of the clock currently * being clk_init'd. */ - if (core->parent) { - hlist_add_head(&core->child_node, - &core->parent->children); - core->orphan = core->parent->orphan; + if (parent) { + hlist_add_head(&core->child_node, &parent->children); + core->orphan = parent->orphan; } else if (!core->num_parents) { hlist_add_head(&core->child_node, &clk_root_list); core->orphan = false; @@ -3446,9 +3446,9 @@ static int __clk_core_init(struct clk_core *core) */ if (core->ops->recalc_accuracy) core->accuracy = core->ops->recalc_accuracy(core->hw, - __clk_get_accuracy(core->parent)); - else if (core->parent) - core->accuracy = core->parent->accuracy; + __clk_get_accuracy(parent)); + else if (parent) + core->accuracy = parent->accuracy; else core->accuracy = 0; @@ -3472,9 +3472,9 @@ static int __clk_core_init(struct clk_core *core) */ if (core->ops->recalc_rate) rate = core->ops->recalc_rate(core->hw, - clk_core_get_rate_nolock(core->parent)); - else if (core->parent) - rate = core->parent->rate; + clk_core_get_rate_nolock(parent)); + else if (parent) + rate = parent->rate; else rate = 0; core->rate = core->req_rate = rate; From 0daa376d832f4ce585f153efee4233b52fa3fe58 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 5 Feb 2020 15:28:01 -0800 Subject: [PATCH 034/809] clk: Move rate and accuracy recalc to mostly consumer APIs There's some confusion about when recalc is done for the rate and accuracy clk consumer APIs in relation to the prepare lock being taken. Oddly enough, we take the lock again in debugfs APIs so that we can call the internal "clk_core" APIs to get these fields with any necessary recalculations. Instead of having this confusion, let's introduce a recalc variant of these two consumer APIs as internal helpers and call them from the consumer APIs and the debugfs code so that we don't take the lock more than once. Cc: Douglas Anderson Cc: Heiko Stuebner Cc: Jerome Brunet Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200205232802.29184-4-sboyd@kernel.org Acked-by: Jerome Brunet --- drivers/clk/clk.c | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 3ddca6084e8e..dc8bdfbd6a0c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -488,7 +488,7 @@ unsigned long clk_hw_get_rate(const struct clk_hw *hw) } EXPORT_SYMBOL_GPL(clk_hw_get_rate); -static unsigned long __clk_get_accuracy(struct clk_core *core) +static unsigned long clk_core_get_accuracy_no_lock(struct clk_core *core) { if (!core) return 0; @@ -1517,18 +1517,12 @@ static void __clk_recalc_accuracies(struct clk_core *core) __clk_recalc_accuracies(child); } -static long clk_core_get_accuracy(struct clk_core *core) +static long clk_core_get_accuracy_recalc(struct clk_core *core) { - unsigned long accuracy; - - clk_prepare_lock(); if (core && (core->flags & CLK_GET_ACCURACY_NOCACHE)) __clk_recalc_accuracies(core); - accuracy = __clk_get_accuracy(core); - clk_prepare_unlock(); - - return accuracy; + return clk_core_get_accuracy_no_lock(core); } /** @@ -1542,10 +1536,16 @@ static long clk_core_get_accuracy(struct clk_core *core) */ long clk_get_accuracy(struct clk *clk) { + long accuracy; + if (!clk) return 0; - return clk_core_get_accuracy(clk->core); + clk_prepare_lock(); + accuracy = clk_core_get_accuracy_recalc(clk->core); + clk_prepare_unlock(); + + return accuracy; } EXPORT_SYMBOL_GPL(clk_get_accuracy); @@ -1599,19 +1599,12 @@ static void __clk_recalc_rates(struct clk_core *core, unsigned long msg) __clk_recalc_rates(child, msg); } -static unsigned long clk_core_get_rate(struct clk_core *core) +static unsigned long clk_core_get_rate_recalc(struct clk_core *core) { - unsigned long rate; - - clk_prepare_lock(); - if (core && (core->flags & CLK_GET_RATE_NOCACHE)) __clk_recalc_rates(core, 0); - rate = clk_core_get_rate_nolock(core); - clk_prepare_unlock(); - - return rate; + return clk_core_get_rate_nolock(core); } /** @@ -1624,10 +1617,16 @@ static unsigned long clk_core_get_rate(struct clk_core *core) */ unsigned long clk_get_rate(struct clk *clk) { + unsigned long rate; + if (!clk) return 0; - return clk_core_get_rate(clk->core); + clk_prepare_lock(); + rate = clk_core_get_rate_recalc(clk->core); + clk_prepare_unlock(); + + return rate; } EXPORT_SYMBOL_GPL(clk_get_rate); @@ -2910,7 +2909,8 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, level * 3 + 1, "", 30 - level * 3, c->name, c->enable_count, c->prepare_count, c->protect_count, - clk_core_get_rate(c), clk_core_get_accuracy(c)); + clk_core_get_rate_recalc(c), + clk_core_get_accuracy_recalc(c)); phase = clk_core_get_phase(c); if (phase >= 0) @@ -2965,10 +2965,10 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"enable_count\": %d,", c->enable_count); seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); seq_printf(s, "\"protect_count\": %d,", c->protect_count); - seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); + seq_printf(s, "\"rate\": %lu,", clk_core_get_rate_recalc(c)); seq_printf(s, "\"min_rate\": %lu,", min_rate); seq_printf(s, "\"max_rate\": %lu,", max_rate); - seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); + seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy_recalc(c)); phase = clk_core_get_phase(c); if (phase >= 0) seq_printf(s, "\"phase\": %d,", phase); @@ -3446,7 +3446,7 @@ static int __clk_core_init(struct clk_core *core) */ if (core->ops->recalc_accuracy) core->accuracy = core->ops->recalc_accuracy(core->hw, - __clk_get_accuracy(parent)); + clk_core_get_accuracy_no_lock(parent)); else if (parent) core->accuracy = parent->accuracy; else From 2760878662a290ac57cff8a5a8d8bda8f4dddc37 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 5 Feb 2020 15:28:02 -0800 Subject: [PATCH 035/809] clk: Bail out when calculating phase fails during clk registration Bail out of clk registration if we fail to get the phase for a clk that has a clk_ops::get_phase() callback. Print a warning too so that driver authors can easily figure out that some clk is unable to read back phase information at boot. Cc: Douglas Anderson Cc: Heiko Stuebner Suggested-by: Jerome Brunet Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200205232802.29184-5-sboyd@kernel.org Acked-by: Jerome Brunet --- drivers/clk/clk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index dc8bdfbd6a0c..ed1797857bae 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3457,7 +3457,12 @@ static int __clk_core_init(struct clk_core *core) * Since a phase is by definition relative to its parent, just * query the current clock phase, or just assume it's in phase. */ - clk_core_get_phase(core); + ret = clk_core_get_phase(core); + if (ret < 0) { + pr_warn("%s: Failed to get phase for clk '%s'\n", __func__, + core->name); + goto out; + } /* * Set clk's duty cycle. From 5bf7f4a249387a6062b9a14c8a77e7ba2fd6a53b Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Fri, 31 Jan 2020 13:58:16 +0200 Subject: [PATCH 036/809] clk: at91: sam9x60: Don't use audio PLL On sam9x60, there is not audio PLL and so I2S and classD have to use one of the best matching parents for their generated clock. Fixes: 01e2113de9a5 ("clk: at91: add sam9x60 pmc driver") Signed-off-by: Codrin Ciubotariu Link: https://lkml.kernel.org/r/20200131115816.12483-1-codrin.ciubotariu@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sam9x60.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 77398aefeb6d..bacb32c15b26 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -124,7 +124,6 @@ static const struct { char *n; u8 id; struct clk_range r; - bool pll; } sam9x60_gck[] = { { .n = "flex0_gclk", .id = 5, }, { .n = "flex1_gclk", .id = 6, }, @@ -144,11 +143,9 @@ static const struct { { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, }, { .n = "flex11_gclk", .id = 32, }, { .n = "flex12_gclk", .id = 33, }, - { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, - .pll = true, }, + { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, }, { .n = "pit64b_gclk", .id = 37, }, - { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, - .pll = true, }, + { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, }, { .n = "tcb1_gclk", .id = 45, }, { .n = "dbgu_gclk", .id = 47, }, }; @@ -290,7 +287,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) sam9x60_gck[i].n, parent_names, 6, sam9x60_gck[i].id, - sam9x60_gck[i].pll, + false, &sam9x60_gck[i].r); if (IS_ERR(hw)) goto err_free; From b0ecf1c6c6e82da4847900fad0272abfd014666d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 17 Jan 2020 13:36:46 +0200 Subject: [PATCH 037/809] clk: at91: usb: continue if clk_hw_round_rate() return zero clk_hw_round_rate() may call round rate function of its parents. In case of SAM9X60 two of USB parrents are PLLA and UPLL. These clocks are controlled by clk-sam9x60-pll.c driver. The round rate function for this driver is sam9x60_pll_round_rate() which call in turn sam9x60_pll_get_best_div_mul(). In case the requested rate is not in the proper range (rate < characteristics->output[0].min && rate > characteristics->output[0].max) the sam9x60_pll_round_rate() will return a negative number to its caller (called by clk_core_round_rate_nolock()). clk_hw_round_rate() will return zero in case a negative number is returned by clk_core_round_rate_nolock(). With this, the USB clock will continue its rate computation even caller of clk_hw_round_rate() returned an error. With this, the USB clock on SAM9X60 may not chose the best parent. I detected this after a suspend/resume cycle on SAM9X60. Signed-off-by: Claudiu Beznea Link: https://lkml.kernel.org/r/1579261009-4573-2-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 22aede42a336..3c0bd7e51b09 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -75,6 +75,9 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, tmp_parent_rate = req->rate * div; tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate); + if (!tmp_parent_rate) + continue; + tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); if (tmp_rate < req->rate) tmp_diff = req->rate - tmp_rate; From 43b203d32b77d1b1b2209e22837f49767020553e Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 17 Jan 2020 13:36:47 +0200 Subject: [PATCH 038/809] clk: at91: sam9x60: fix usb clock parents SAM9X60's USB clock has 3 parents: plla, upll and main_osc. Fixes: 01e2113de9a5 ("clk: at91: add sam9x60 pmc driver") Signed-off-by: Claudiu Beznea Link: https://lkml.kernel.org/r/1579261009-4573-3-git-send-email-claudiu.beznea@microchip.com Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sam9x60.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index bacb32c15b26..cc19e8fb83be 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -234,9 +234,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np) parent_names[0] = "pllack"; parent_names[1] = "upllck"; - parent_names[2] = "mainck"; - parent_names[3] = "mainck"; - hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4); + parent_names[2] = "main_osc"; + hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3); if (IS_ERR(hw)) goto err_free; From d7a83d67a1694c42cc95fc0755d823f7ca3bfcfb Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 17 Jan 2020 13:36:48 +0200 Subject: [PATCH 039/809] clk: at91: usb: use proper usbs_mask Use usbs_mask passed as argument. The usbs_mask is different for SAM9X60. Fixes: 2423eeaead6f8 ("clk: at91: usb: Add sam9x60 support") Signed-off-by: Claudiu Beznea Link: https://lkml.kernel.org/r/1579261009-4573-4-git-send-email-claudiu.beznea@microchip.com Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 3c0bd7e51b09..c0895c993cce 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -214,7 +214,7 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; - usb->usbs_mask = SAM9X5_USBS_MASK; + usb->usbs_mask = usbs_mask; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); From 9962fb0d19958215b5bc6b9279f824b55aabdec2 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 17 Jan 2020 13:36:49 +0200 Subject: [PATCH 040/809] clk: at91: usb: introduce num_parents in driver's structure SAM9X60 USB clock may have up to 3 parents. Save the number of parents in driver's data structure and validate against it when setting parent. Signed-off-by: Claudiu Beznea Link: https://lkml.kernel.org/r/1579261009-4573-5-git-send-email-claudiu.beznea@microchip.com Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index c0895c993cce..31d5c45e30d7 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -25,6 +25,7 @@ struct at91sam9x5_clk_usb { struct clk_hw hw; struct regmap *regmap; u32 usbs_mask; + u8 num_parents; }; #define to_at91sam9x5_clk_usb(hw) \ @@ -110,7 +111,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) { struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); - if (index > 1) + if (index >= usb->num_parents) return -EINVAL; regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index); @@ -215,6 +216,7 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; usb->usbs_mask = usbs_mask; + usb->num_parents = num_parents; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); From 12dc8d3be9d86cccc35dcf32828d3a8e9d48e0d1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Jan 2020 22:05:29 +0100 Subject: [PATCH 041/809] clk: at91: add at91sam9g45 pmc driver Add a driver for the PMC clocks of the at91sam9g45 family. Signed-off-by: Alexandre Belloni Link: https://lkml.kernel.org/r/20200117210529.17490-1-alexandre.belloni@bootlin.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/at91sam9g45.c | 220 +++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 drivers/clk/at91/at91sam9g45.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 3732241352ce..c02c53a0e02e 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c new file mode 100644 index 000000000000..38a7d2d2df0c --- /dev/null +++ b/drivers/clk/at91/at91sam9g45.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 0, .max = 133333333 }, + .divisors = { 1, 2, 4, 3 }, +}; + +static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; + +static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; + +static const struct clk_range plla_outputs[] = { + { .min = 745000000, .max = 800000000 }, + { .min = 695000000, .max = 750000000 }, + { .min = 645000000, .max = 700000000 }, + { .min = 595000000, .max = 650000000 }, + { .min = 545000000, .max = 600000000 }, + { .min = 495000000, .max = 555000000 }, + { .min = 445000000, .max = 500000000 }, + { .min = 400000000, .max = 450000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} at91sam9g45_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +static const struct clk_pcr_layout at91sam9g45_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct pck at91sam9g45_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "pioDE_clk", .id = 5, }, + { .n = "trng_clk", .id = 6, }, + { .n = "usart0_clk", .id = 7, }, + { .n = "usart1_clk", .id = 8, }, + { .n = "usart2_clk", .id = 9, }, + { .n = "usart3_clk", .id = 10, }, + { .n = "mci0_clk", .id = 11, }, + { .n = "twi0_clk", .id = 12, }, + { .n = "twi1_clk", .id = 13, }, + { .n = "spi0_clk", .id = 14, }, + { .n = "spi1_clk", .id = 15, }, + { .n = "ssc0_clk", .id = 16, }, + { .n = "ssc1_clk", .id = 17, }, + { .n = "tcb0_clk", .id = 18, }, + { .n = "pwm_clk", .id = 19, }, + { .n = "adc_clk", .id = 20, }, + { .n = "dma0_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "lcd_clk", .id = 23, }, + { .n = "ac97_clk", .id = 24, }, + { .n = "macb0_clk", .id = 25, }, + { .n = "isi_clk", .id = 26, }, + { .n = "udphs_clk", .id = 27, }, + { .n = "aestdessha_clk", .id = 28, }, + { .n = "mci1_clk", .id = 29, }, + { .n = "vdec_clk", .id = 30, }, +}; + +static void __init at91sam9g45_pmc_setup(struct device_node *np) +{ + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9g45_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91sam9g45_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9g45_systemck), + nck(at91sam9g45_periphck), 0); + if (!at91sam9g45_pmc) + return; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc"); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91rm9200_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "masterck"; + for (i = 0; i < 2; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9g45_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9g45_systemck[i].n, + at91sam9g45_systemck[i].p, + at91sam9g45_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->shws[at91sam9g45_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) { + hw = at91_clk_register_peripheral(regmap, + at91sam9g45_periphck[i].n, + "masterck", + at91sam9g45_periphck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->phws[at91sam9g45_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9g45_pmc); + + return; + +err_free: + pmc_data_free(at91sam9g45_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(at91sam9g45_pmc, "atmel,at91sam9g45-pmc", + at91sam9g45_pmc_setup); From 0969b242f7b8e5de0a1c28f81d8558fd678c066d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 10 Jan 2020 23:30:33 +0100 Subject: [PATCH 042/809] clk: at91: add sama5d3 pmc driver Add a driver for the PMC clocks of the sama5d3. Signed-off-by: Alexandre Belloni Link: https://lkml.kernel.org/r/20200110223033.1261791-1-alexandre.belloni@bootlin.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/sama5d3.c | 240 +++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 drivers/clk/at91/sama5d3.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index c02c53a0e02e..54a94c32d972 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o +obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/sama5d3.c b/drivers/clk/at91/sama5d3.c new file mode 100644 index 000000000000..88506f909c08 --- /dev/null +++ b/drivers/clk/at91/sama5d3.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 0, .max = 166000000 }, + .divisors = { 1, 2, 4, 3 }, +}; + +static u8 plla_out[] = { 0 }; + +static u16 plla_icpll[] = { 0 }; + +static const struct clk_range plla_outputs[] = { + { .min = 400000000, .max = 1000000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 8000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct clk_pcr_layout sama5d3_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(6, 0), + .div_mask = GENMASK(17, 16), +}; + +static const struct { + char *n; + char *p; + u8 id; +} sama5d3_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "lcdck", .p = "masterck", .id = 3 }, + { .n = "smdck", .p = "smdclk", .id = 4 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; +} sama5d3_periphck[] = { + { .n = "dbgu_clk", .id = 2, }, + { .n = "hsmc_clk", .id = 5, }, + { .n = "pioA_clk", .id = 6, }, + { .n = "pioB_clk", .id = 7, }, + { .n = "pioC_clk", .id = 8, }, + { .n = "pioD_clk", .id = 9, }, + { .n = "pioE_clk", .id = 10, }, + { .n = "usart0_clk", .id = 12, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart1_clk", .id = 13, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart2_clk", .id = 14, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart3_clk", .id = 15, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart0_clk", .id = 16, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart1_clk", .id = 17, .r = { .min = 0, .max = 83000000 }, }, + { .n = "twi0_clk", .id = 18, .r = { .min = 0, .max = 41500000 }, }, + { .n = "twi1_clk", .id = 19, .r = { .min = 0, .max = 41500000 }, }, + { .n = "twi2_clk", .id = 20, .r = { .min = 0, .max = 41500000 }, }, + { .n = "mci0_clk", .id = 21, }, + { .n = "mci1_clk", .id = 22, }, + { .n = "mci2_clk", .id = 23, }, + { .n = "spi0_clk", .id = 24, .r = { .min = 0, .max = 166000000 }, }, + { .n = "spi1_clk", .id = 25, .r = { .min = 0, .max = 166000000 }, }, + { .n = "tcb0_clk", .id = 26, .r = { .min = 0, .max = 166000000 }, }, + { .n = "tcb1_clk", .id = 27, .r = { .min = 0, .max = 166000000 }, }, + { .n = "pwm_clk", .id = 28, }, + { .n = "adc_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, }, + { .n = "dma0_clk", .id = 30, }, + { .n = "dma1_clk", .id = 31, }, + { .n = "uhphs_clk", .id = 32, }, + { .n = "udphs_clk", .id = 33, }, + { .n = "macb0_clk", .id = 34, }, + { .n = "macb1_clk", .id = 35, }, + { .n = "lcdc_clk", .id = 36, }, + { .n = "isi_clk", .id = 37, }, + { .n = "ssc0_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, }, + { .n = "ssc1_clk", .id = 39, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can0_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can1_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, }, + { .n = "sha_clk", .id = 42, }, + { .n = "aes_clk", .id = 43, }, + { .n = "tdes_clk", .id = 44, }, + { .n = "trng_clk", .id = 45, }, + { .n = "fuse_clk", .id = 48, }, + { .n = "mpddr_clk", .id = 49, }, +}; + +static void __init sama5d3_pmc_setup(struct device_node *np) +{ + const char *slck_name, *mainxtal_name; + struct pmc_data *sama5d3_pmc; + const char *parent_names[5]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sama5d3_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(sama5d3_systemck), + nck(sama5d3_periphck), 0); + if (!sama5d3_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &sama5d3_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "masterck"; + for (i = 0; i < 3; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sama5d3_systemck); i++) { + hw = at91_clk_register_system(regmap, sama5d3_systemck[i].n, + sama5d3_systemck[i].p, + sama5d3_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->shws[sama5d3_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d3_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d3_pcr_layout, + sama5d3_periphck[i].n, + "masterck", + sama5d3_periphck[i].id, + &sama5d3_periphck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->phws[sama5d3_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d3_pmc); + + return; + +err_free: + pmc_data_free(sama5d3_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(sama5d3_pmc, "atmel,sama5d3-pmc", sama5d3_pmc_setup); From 143e04dab6b4c73c66b1708f6bc3212b9cb71dbb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 16 Jan 2020 18:23:16 +0100 Subject: [PATCH 043/809] clk: at91: add at91sam9n12 pmc driver Add a driver for the PMC clocks of the at91sam9n12 family. Signed-off-by: Alexandre Belloni Link: https://lkml.kernel.org/r/20200116172316.426703-1-alexandre.belloni@bootlin.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/at91sam9n12.c | 238 +++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 drivers/clk/at91/at91sam9n12.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 54a94c32d972..7ab244f346c4 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c new file mode 100644 index 000000000000..8bb39d2ba84b --- /dev/null +++ b/drivers/clk/at91/at91sam9n12.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 0, .max = 133333333 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; + +static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; + +static const struct clk_range plla_outputs[] = { + { .min = 745000000, .max = 800000000 }, + { .min = 695000000, .max = 750000000 }, + { .min = 645000000, .max = 700000000 }, + { .min = 595000000, .max = 650000000 }, + { .min = 545000000, .max = 600000000 }, + { .min = 495000000, .max = 555000000 }, + { .min = 445000000, .max = 500000000 }, + { .min = 400000000, .max = 450000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static u8 pllb_out[] = { 0 }; + +static const struct clk_range pllb_outputs[] = { + { .min = 30000000, .max = 100000000 }, +}; + +static const struct clk_pll_characteristics pllb_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(pllb_outputs), + .output = pllb_outputs, + .out = pllb_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} at91sam9n12_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "lcdck", .p = "masterck", .id = 3 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +static const struct clk_pcr_layout at91sam9n12_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct pck at91sam9n12_periphck[] = { + { .n = "pioAB_clk", .id = 2, }, + { .n = "pioCD_clk", .id = 3, }, + { .n = "fuse_clk", .id = 4, }, + { .n = "usart0_clk", .id = 5, }, + { .n = "usart1_clk", .id = 6, }, + { .n = "usart2_clk", .id = 7, }, + { .n = "usart3_clk", .id = 8, }, + { .n = "twi0_clk", .id = 9, }, + { .n = "twi1_clk", .id = 10, }, + { .n = "mci0_clk", .id = 12, }, + { .n = "spi0_clk", .id = 13, }, + { .n = "spi1_clk", .id = 14, }, + { .n = "uart0_clk", .id = 15, }, + { .n = "uart1_clk", .id = 16, }, + { .n = "tcb_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "lcdc_clk", .id = 25, }, + { .n = "sha_clk", .id = 27, }, + { .n = "ssc0_clk", .id = 28, }, + { .n = "aes_clk", .id = 29, }, + { .n = "trng_clk", .id = 30, }, +}; + +static void __init at91sam9n12_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9n12_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91sam9n12_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9n12_systemck), 31, 0); + if (!at91sam9n12_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1, + &at91rm9200_pll_layout, &pllb_characteristics); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "pllbck"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->chws[PMC_MCK] = hw; + + hw = at91sam9n12_clk_register_usb(regmap, "usbck", "pllbck"); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "pllbck"; + parent_names[4] = "masterck"; + for (i = 0; i < 2; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9n12_systemck[i].n, + at91sam9n12_systemck[i].p, + at91sam9n12_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->shws[at91sam9n12_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9n12_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9n12_pcr_layout, + at91sam9n12_periphck[i].n, + "masterck", + at91sam9n12_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->phws[at91sam9n12_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9n12_pmc); + + return; + +err_free: + pmc_data_free(at91sam9n12_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(at91sam9n12_pmc, "atmel,at91sam9n12-pmc", + at91sam9n12_pmc_setup); From 8d7a577d04e8ce24b1b81ee44ec8cd1dda2a9cd9 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Tue, 21 Jan 2020 17:33:49 -0600 Subject: [PATCH 044/809] clk: samsung: Remove redundant check in samsung_cmu_register_one Consistent with other instances of samsung_clk_init, the check if ctx is NULL is redundant. The function currently does not return NULL. Signed-off-by: Aditya Pakki Link: https://lkml.kernel.org/r/20200121233349.28627-1-pakki001@umn.edu Acked-by: Chanwoo Choi Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index dad31308c071..1949ae7851b2 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -356,10 +356,6 @@ struct samsung_clk_provider * __init samsung_cmu_register_one( } ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids); - if (!ctx) { - panic("%s: unable to allocate ctx\n", __func__); - return ctx; - } if (cmu->pll_clks) samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks, From be545c79b28917caa0cee231f376be2a2e5c9d0e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 6 Dec 2019 14:34:14 +0100 Subject: [PATCH 045/809] clk: Fix continuation of of_clk_detect_critical() The second line of the of_clk_detect_critical() function signature is not indented according to coding style. Signed-off-by: Geert Uytterhoeven Link: https://lkml.kernel.org/r/20191206133414.23925-1-geert+renesas@glider.be Acked-by: Lee Jones Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f0f2b599fd7e..e42145cd996a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4865,8 +4865,8 @@ static int parent_ready(struct device_node *np) * * Return: error code or zero on success */ -int of_clk_detect_critical(struct device_node *np, - int index, unsigned long *flags) +int of_clk_detect_critical(struct device_node *np, int index, + unsigned long *flags) { struct property *prop; const __be32 *cur; From cc26ed7be46c5f5fa45f3df8161ed7ca3c4d318c Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 14 Jan 2020 10:07:25 -0600 Subject: [PATCH 046/809] clk: stratix10: use do_div() for 64-bit calculation do_div() macro to perform u64 division and guards against overflow if the result is too large for the unsigned long return type. Signed-off-by: Dinh Nguyen Link: https://lkml.kernel.org/r/20200114160726.19771-1-dinguyen@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-pll-s10.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c index 4705eb544f01..8d7b1d0c4664 100644 --- a/drivers/clk/socfpga/clk-pll-s10.c +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -39,7 +39,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, /* read VCO1 reg for numerator and denominator */ reg = readl(socfpgaclk->hw.reg); refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; - vco_freq = (unsigned long long)parent_rate / refdiv; + + vco_freq = parent_rate; + do_div(vco_freq, refdiv); /* Read mdiv and fdiv from the fdbck register */ reg = readl(socfpgaclk->hw.reg + 0x4); From 8c0e783d2c7be2bb75bf233574a3f1ad1e818cb1 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 14 Jan 2020 10:07:26 -0600 Subject: [PATCH 047/809] clk: socfpga: stratix10: simplify parameter passing Just pass the clock pointer structure to the various register functions. Signed-off-by: Dinh Nguyen Link: https://lkml.kernel.org/r/20200114160726.19771-2-dinguyen@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-gate-s10.c | 40 +++++++++++--------------- drivers/clk/socfpga/clk-periph-s10.c | 42 ++++++++++++++-------------- drivers/clk/socfpga/clk-pll-s10.c | 13 +++++---- drivers/clk/socfpga/clk-s10.c | 29 +++---------------- drivers/clk/socfpga/stratix10-clk.h | 25 ++++++----------- 5 files changed, 57 insertions(+), 92 deletions(-) diff --git a/drivers/clk/socfpga/clk-gate-s10.c b/drivers/clk/socfpga/clk-gate-s10.c index 54a464fa63e0..8be4722f6064 100644 --- a/drivers/clk/socfpga/clk-gate-s10.c +++ b/drivers/clk/socfpga/clk-gate-s10.c @@ -65,54 +65,49 @@ static const struct clk_ops dbgclk_ops = { .get_parent = socfpga_gate_get_parent, }; -struct clk *s10_register_gate(const char *name, const char *parent_name, - const char * const *parent_names, - u8 num_parents, unsigned long flags, - void __iomem *regbase, unsigned long gate_reg, - unsigned long gate_idx, unsigned long div_reg, - unsigned long div_offset, u8 div_width, - unsigned long bypass_reg, u8 bypass_shift, - u8 fixed_div) +struct clk *s10_register_gate(const struct stratix10_gate_clock *clks, void __iomem *regbase) { struct clk *clk; struct socfpga_gate_clk *socfpga_clk; struct clk_init_data init; + const char * const *parent_names = clks->parent_names; + const char *parent_name = clks->parent_name; socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); if (!socfpga_clk) return NULL; - socfpga_clk->hw.reg = regbase + gate_reg; - socfpga_clk->hw.bit_idx = gate_idx; + socfpga_clk->hw.reg = regbase + clks->gate_reg; + socfpga_clk->hw.bit_idx = clks->gate_idx; gateclk_ops.enable = clk_gate_ops.enable; gateclk_ops.disable = clk_gate_ops.disable; - socfpga_clk->fixed_div = fixed_div; + socfpga_clk->fixed_div = clks->fixed_div; - if (div_reg) - socfpga_clk->div_reg = regbase + div_reg; + if (clks->div_reg) + socfpga_clk->div_reg = regbase + clks->div_reg; else socfpga_clk->div_reg = NULL; - socfpga_clk->width = div_width; - socfpga_clk->shift = div_offset; + socfpga_clk->width = clks->div_width; + socfpga_clk->shift = clks->div_offset; - if (bypass_reg) - socfpga_clk->bypass_reg = regbase + bypass_reg; + if (clks->bypass_reg) + socfpga_clk->bypass_reg = regbase + clks->bypass_reg; else socfpga_clk->bypass_reg = NULL; - socfpga_clk->bypass_shift = bypass_shift; + socfpga_clk->bypass_shift = clks->bypass_shift; - if (streq(name, "cs_pdbg_clk")) + if (streq(clks->name, "cs_pdbg_clk")) init.ops = &dbgclk_ops; else init.ops = &gateclk_ops; - init.name = name; - init.flags = flags; + init.name = clks->name; + init.flags = clks->flags; - init.num_parents = num_parents; + init.num_parents = clks->num_parents; init.parent_names = parent_names ? parent_names : &parent_name; socfpga_clk->hw.hw.init = &init; @@ -121,6 +116,5 @@ struct clk *s10_register_gate(const char *name, const char *parent_name, kfree(socfpga_clk); return NULL; } - return clk; } diff --git a/drivers/clk/socfpga/clk-periph-s10.c b/drivers/clk/socfpga/clk-periph-s10.c index 1a191eeeebba..dd6d4056e9de 100644 --- a/drivers/clk/socfpga/clk-periph-s10.c +++ b/drivers/clk/socfpga/clk-periph-s10.c @@ -73,26 +73,27 @@ static const struct clk_ops peri_cnt_clk_ops = { .get_parent = clk_periclk_get_parent, }; -struct clk *s10_register_periph(const char *name, const char *parent_name, - const char * const *parent_names, - u8 num_parents, unsigned long flags, - void __iomem *reg, unsigned long offset) +struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks, + void __iomem *reg) { struct clk *clk; struct socfpga_periph_clk *periph_clk; struct clk_init_data init; + const char *name = clks->name; + const char *parent_name = clks->parent_name; + const char * const *parent_names = clks->parent_names; periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); if (WARN_ON(!periph_clk)) return NULL; - periph_clk->hw.reg = reg + offset; + periph_clk->hw.reg = reg + clks->offset; init.name = name; init.ops = &peri_c_clk_ops; - init.flags = flags; + init.flags = clks->flags; - init.num_parents = num_parents; + init.num_parents = clks->num_parents; init.parent_names = parent_names ? parent_names : &parent_name; periph_clk->hw.hw.init = &init; @@ -105,38 +106,37 @@ struct clk *s10_register_periph(const char *name, const char *parent_name, return clk; } -struct clk *s10_register_cnt_periph(const char *name, const char *parent_name, - const char * const *parent_names, - u8 num_parents, unsigned long flags, - void __iomem *regbase, unsigned long offset, - u8 fixed_divider, unsigned long bypass_reg, - unsigned long bypass_shift) +struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks, + void __iomem *regbase) { struct clk *clk; struct socfpga_periph_clk *periph_clk; struct clk_init_data init; + const char *name = clks->name; + const char *parent_name = clks->parent_name; + const char * const *parent_names = clks->parent_names; periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); if (WARN_ON(!periph_clk)) return NULL; - if (offset) - periph_clk->hw.reg = regbase + offset; + if (clks->offset) + periph_clk->hw.reg = regbase + clks->offset; else periph_clk->hw.reg = NULL; - if (bypass_reg) - periph_clk->bypass_reg = regbase + bypass_reg; + if (clks->bypass_reg) + periph_clk->bypass_reg = regbase + clks->bypass_reg; else periph_clk->bypass_reg = NULL; - periph_clk->bypass_shift = bypass_shift; - periph_clk->fixed_div = fixed_divider; + periph_clk->bypass_shift = clks->bypass_shift; + periph_clk->fixed_div = clks->fixed_divider; init.name = name; init.ops = &peri_cnt_clk_ops; - init.flags = flags; + init.flags = clks->flags; - init.num_parents = num_parents; + init.num_parents = clks->num_parents; init.parent_names = parent_names ? parent_names : &parent_name; periph_clk->hw.hw.init = &init; diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c index 8d7b1d0c4664..a301bb22f36c 100644 --- a/drivers/clk/socfpga/clk-pll-s10.c +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -110,19 +110,20 @@ static struct clk_ops clk_boot_ops = { .prepare = clk_pll_prepare, }; -struct clk *s10_register_pll(const char *name, const char * const *parent_names, - u8 num_parents, unsigned long flags, - void __iomem *reg, unsigned long offset) +struct clk *s10_register_pll(const struct stratix10_pll_clock *clks, + void __iomem *reg) { struct clk *clk; struct socfpga_pll *pll_clk; struct clk_init_data init; + const char *name = clks->name; + const char * const *parent_names = clks->parent_names; pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); if (WARN_ON(!pll_clk)) return NULL; - pll_clk->hw.reg = reg + offset; + pll_clk->hw.reg = reg + clks->offset; if (streq(name, SOCFPGA_BOOT_CLK)) init.ops = &clk_boot_ops; @@ -130,9 +131,9 @@ struct clk *s10_register_pll(const char *name, const char * const *parent_names, init.ops = &clk_pll_ops; init.name = name; - init.flags = flags; + init.flags = clks->flags; - init.num_parents = num_parents; + init.num_parents = clks->num_parents; init.parent_names = parent_names; pll_clk->hw.hw.init = &init; diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 993f3a73c71e..dea7c6c7d269 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -177,9 +177,7 @@ static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks, int i; for (i = 0; i < nums; i++) { - clk = s10_register_periph(clks[i].name, clks[i].parent_name, - clks[i].parent_names, clks[i].num_parents, - clks[i].flags, base, clks[i].offset); + clk = s10_register_periph(&clks[i], base); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); @@ -198,14 +196,7 @@ static int s10_clk_register_cnt_perip(const struct stratix10_perip_cnt_clock *cl int i; for (i = 0; i < nums; i++) { - clk = s10_register_cnt_periph(clks[i].name, clks[i].parent_name, - clks[i].parent_names, - clks[i].num_parents, - clks[i].flags, base, - clks[i].offset, - clks[i].fixed_divider, - clks[i].bypass_reg, - clks[i].bypass_shift); + clk = s10_register_cnt_periph(&clks[i], base); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); @@ -225,16 +216,7 @@ static int s10_clk_register_gate(const struct stratix10_gate_clock *clks, int i; for (i = 0; i < nums; i++) { - clk = s10_register_gate(clks[i].name, clks[i].parent_name, - clks[i].parent_names, - clks[i].num_parents, - clks[i].flags, base, - clks[i].gate_reg, - clks[i].gate_idx, clks[i].div_reg, - clks[i].div_offset, clks[i].div_width, - clks[i].bypass_reg, - clks[i].bypass_shift, - clks[i].fixed_div); + clk = s10_register_gate(&clks[i], base); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); @@ -254,10 +236,7 @@ static int s10_clk_register_pll(const struct stratix10_pll_clock *clks, int i; for (i = 0; i < nums; i++) { - clk = s10_register_pll(clks[i].name, clks[i].parent_names, - clks[i].num_parents, - clks[i].flags, base, - clks[i].offset); + clk = s10_register_pll(&clks[i], base); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h index e8e121907952..fcabef42249c 100644 --- a/drivers/clk/socfpga/stratix10-clk.h +++ b/drivers/clk/socfpga/stratix10-clk.h @@ -60,21 +60,12 @@ struct stratix10_gate_clock { u8 fixed_div; }; -struct clk *s10_register_pll(const char *, const char *const *, u8, - unsigned long, void __iomem *, unsigned long); - -struct clk *s10_register_periph(const char *, const char *, - const char * const *, u8, unsigned long, - void __iomem *, unsigned long); -struct clk *s10_register_cnt_periph(const char *, const char *, - const char * const *, u8, - unsigned long, void __iomem *, - unsigned long, u8, unsigned long, - unsigned long); -struct clk *s10_register_gate(const char *, const char *, - const char * const *, u8, - unsigned long, void __iomem *, - unsigned long, unsigned long, - unsigned long, unsigned long, u8, - unsigned long, u8, u8); +struct clk *s10_register_pll(const struct stratix10_pll_clock *, + void __iomem *); +struct clk *s10_register_periph(const struct stratix10_perip_c_clock *, + void __iomem *); +struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *, + void __iomem *); +struct clk *s10_register_gate(const struct stratix10_gate_clock *, + void __iomem *); #endif /* __STRATIX10_CLK_H */ From b8fa484376901b812a21549962ffed075b77befd Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 14 Jan 2020 09:26:05 +0800 Subject: [PATCH 048/809] dt-bindings: clock: Convert i.MX8MQ to json-schema Convert the i.MX8MQ clock binding to DT schema format using json-schema Signed-off-by: Anson Huang Reviewed-by: Rob Herring Signed-off-by: Shawn Guo --- .../bindings/clock/imx8mq-clock.txt | 20 ------ .../bindings/clock/imx8mq-clock.yaml | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt deleted file mode 100644 index 52de8263e012..000000000000 --- a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Clock bindings for NXP i.MX8M Quad - -Required properties: -- compatible: Should be "fsl,imx8mq-ccm" -- reg: Address and length of the register set -- #clock-cells: Should be <1> -- clocks: list of clock specifiers, must contain an entry for each required - entry in clock-names -- clock-names: should include the following entries: - - "ckil" - - "osc_25m" - - "osc_27m" - - "clk_ext1" - - "clk_ext2" - - "clk_ext3" - - "clk_ext4" - -The clock consumer should specify the desired clock by having the clock -ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h -for the full list of i.MX8M Quad clock IDs. diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml new file mode 100644 index 000000000000..77790f0fdcd3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/clock/imx8mq-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8M Quad Clock Control Module Binding + +maintainers: + - Anson Huang + +description: | + NXP i.MX8M Quad clock control module is an integrated clock controller, which + generates and supplies to all modules. + +properties: + compatible: + const: fsl,imx8mq-ccm + + reg: + maxItems: 1 + + clocks: + items: + - description: 32k osc + - description: 25m osc + - description: 27m osc + - description: ext1 clock input + - description: ext2 clock input + - description: ext3 clock input + - description: ext4 clock input + + clock-names: + items: + - const: ckil + - const: osc_25m + - const: osc_27m + - const: clk_ext1 + - const: clk_ext2 + - const: clk_ext3 + - const: clk_ext4 + + '#clock-cells': + const: 1 + description: + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h + for the full list of i.MX8M Quad clock IDs. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +examples: + # Clock Control Module node: + - | + clk: clock-controller@30380000 { + compatible = "fsl,imx8mq-ccm"; + reg = <0x30380000 0x10000>; + #clock-cells = <1>; + clocks = <&ckil>, <&osc_25m>, <&osc_27m>, + <&clk_ext1>, <&clk_ext2>, + <&clk_ext3>, <&clk_ext4>; + clock-names = "ckil", "osc_25m", "osc_27m", + "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4"; + }; + +... From 16d848e11836a17702534b65007176d12246d0b3 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 14 Jan 2020 09:26:06 +0800 Subject: [PATCH 049/809] dt-bindings: clock: Convert i.MX8MM to json-schema Convert the i.MX8MM clock binding to DT schema format using json-schema Signed-off-by: Anson Huang Reviewed-by: Rob Herring Signed-off-by: Shawn Guo --- .../bindings/clock/imx8mm-clock.txt | 29 -------- .../bindings/clock/imx8mm-clock.yaml | 68 +++++++++++++++++++ 2 files changed, 68 insertions(+), 29 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/imx8mm-clock.txt create mode 100644 Documentation/devicetree/bindings/clock/imx8mm-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/imx8mm-clock.txt b/Documentation/devicetree/bindings/clock/imx8mm-clock.txt deleted file mode 100644 index 8e4ab9e619a1..000000000000 --- a/Documentation/devicetree/bindings/clock/imx8mm-clock.txt +++ /dev/null @@ -1,29 +0,0 @@ -* Clock bindings for NXP i.MX8M Mini - -Required properties: -- compatible: Should be "fsl,imx8mm-ccm" -- reg: Address and length of the register set -- #clock-cells: Should be <1> -- clocks: list of clock specifiers, must contain an entry for each required - entry in clock-names -- clock-names: should include the following entries: - - "osc_32k" - - "osc_24m" - - "clk_ext1" - - "clk_ext2" - - "clk_ext3" - - "clk_ext4" - -clk: clock-controller@30380000 { - compatible = "fsl,imx8mm-ccm"; - reg = <0x0 0x30380000 0x0 0x10000>; - #clock-cells = <1>; - clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, - <&clk_ext3>, <&clk_ext4>; - clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2", - "clk_ext3", "clk_ext4"; -}; - -The clock consumer should specify the desired clock by having the clock -ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h -for the full list of i.MX8M Mini clock IDs. diff --git a/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml new file mode 100644 index 000000000000..f5be181bd21d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/clock/imx8mm-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8M Mini Clock Control Module Binding + +maintainers: + - Anson Huang + +description: | + NXP i.MX8M Mini clock control module is an integrated clock controller, which + generates and supplies to all modules. + +properties: + compatible: + const: fsl,imx8mm-ccm + + reg: + maxItems: 1 + + clocks: + items: + - description: 32k osc + - description: 24m osc + - description: ext1 clock input + - description: ext2 clock input + - description: ext3 clock input + - description: ext4 clock input + + clock-names: + items: + - const: osc_32k + - const: osc_24m + - const: clk_ext1 + - const: clk_ext2 + - const: clk_ext3 + - const: clk_ext4 + + '#clock-cells': + const: 1 + description: + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h + for the full list of i.MX8M Mini clock IDs. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +examples: + # Clock Control Module node: + - | + clk: clock-controller@30380000 { + compatible = "fsl,imx8mm-ccm"; + reg = <0x30380000 0x10000>; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, + <&clk_ext3>, <&clk_ext4>; + clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4"; + }; + +... From b86a8ad2870e100e2f3ee1ae6c7741e3d771b89d Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 14 Jan 2020 09:26:07 +0800 Subject: [PATCH 050/809] dt-bindings: clock: Refine i.MX8MN clock binding Refine i.MX8MN clock binding by removing useless content and updating the example, it makes all i.MX8M SoCs' clock binding aligned. Signed-off-by: Anson Huang Reviewed-by: Rob Herring Signed-off-by: Shawn Guo --- .../bindings/clock/imx8mn-clock.yaml | 48 +------------------ 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml index cd0b8a341321..49730474c1a7 100644 --- a/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml @@ -40,7 +40,7 @@ properties: '#clock-cells': const: 1 - description: | + description: The clock consumer should specify the desired clock by having the clock ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mn-clock.h for the full list of i.MX8M Nano clock IDs. @@ -57,7 +57,7 @@ examples: - | clk: clock-controller@30380000 { compatible = "fsl,imx8mn-ccm"; - reg = <0x0 0x30380000 0x0 0x10000>; + reg = <0x30380000 0x10000>; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; @@ -65,48 +65,4 @@ examples: "clk_ext2", "clk_ext3", "clk_ext4"; }; - # Required external clocks for Clock Control Module node: - - | - osc_32k: clock-osc-32k { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <32768>; - clock-output-names = "osc_32k"; - }; - - osc_24m: clock-osc-24m { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - clock-output-names = "osc_24m"; - }; - - clk_ext1: clock-ext1 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <133000000>; - clock-output-names = "clk_ext1"; - }; - - clk_ext2: clock-ext2 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <133000000>; - clock-output-names = "clk_ext2"; - }; - - clk_ext3: clock-ext3 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <133000000>; - clock-output-names = "clk_ext3"; - }; - - clk_ext4: clock-ext4 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency= <133000000>; - clock-output-names = "clk_ext4"; - }; - ... From 57795654fb553a78f07a9f92d87fb2582379cd93 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 16 Jan 2020 14:50:49 +0800 Subject: [PATCH 051/809] clk: imx: pll14xx: Add new frequency entries for pll1443x table Add new frequency entries to pll1443x table to meet different display settings requirement. Signed-off-by: Anson Huang Reviewed-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pll14xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 5b0519a81a7a..37e311e1d058 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -55,8 +55,10 @@ static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = { }; static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = { + PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384), PLL_1443X_RATE(650000000U, 325, 3, 2, 0), PLL_1443X_RATE(594000000U, 198, 2, 2, 0), + PLL_1443X_RATE(519750000U, 173, 2, 2, 16384), PLL_1443X_RATE(393216000U, 262, 2, 3, 9437), PLL_1443X_RATE(361267200U, 361, 3, 3, 17511), }; From 73c7ddd8ee15dc5e06ffb2e22bde89c3deff3c45 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 22 Jan 2020 11:04:50 +0100 Subject: [PATCH 052/809] clk: meson: gxbb: add the gxl internal dac gate Add the ACODEC clock gate to the gxl clk controller driver Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 3 +++ drivers/clk/meson/gxbb.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 1f9c056e684c..47916c4f1700 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -2613,6 +2613,7 @@ static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE(gxl_acodec, HHI_GCLK_MPEG0, 28); static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30); static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); @@ -3100,6 +3101,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw, [CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw, [CLKID_HDMI] = &gxbb_hdmi.hw, + [CLKID_ACODEC] = &gxl_acodec.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -3491,6 +3493,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = { &gxl_hdmi_pll_od, &gxl_hdmi_pll_od2, &gxl_hdmi_pll_dco, + &gxl_acodec, }; static const struct meson_eeclkc_data gxbb_clkc_data = { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index b53584fe66cf..1ee8cb7e2f5a 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -188,7 +188,7 @@ #define CLKID_HDMI_SEL 203 #define CLKID_HDMI_DIV 204 -#define NR_CLKS 206 +#define NR_CLKS 207 /* include the CLKIDs that have been made part of the DT binding */ #include From 83b89a75de9bf71203fddca00dc1cd8c9f5e6fd2 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 22 Jan 2020 11:04:51 +0100 Subject: [PATCH 053/809] clk: meson: gxbb: set audio output clock hierarchy The aiu devices peripheral clocks needs the aiu and aiu_glue clocks to operate. Reflect this hierarchy in the gxbb clock tree. Fixes: 738f66d3211d ("clk: gxbb: add AmLogic GXBB clk controller driver") Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 47916c4f1700..5fd6a574f8c3 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -2619,14 +2619,6 @@ static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30); static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3); static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6); -static MESON_GATE(gxbb_iec958, HHI_GCLK_MPEG1, 7); -static MESON_GATE(gxbb_i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_GATE(gxbb_amclk, HHI_GCLK_MPEG1, 9); -static MESON_GATE(gxbb_aififo2, HHI_GCLK_MPEG1, 10); -static MESON_GATE(gxbb_mixer, HHI_GCLK_MPEG1, 11); -static MESON_GATE(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_GATE(gxbb_adc, HHI_GCLK_MPEG1, 13); static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14); static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15); static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16); @@ -2681,6 +2673,16 @@ static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3); static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4); +/* AIU gates */ +static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw); +static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw); + /* Array of all clocks provided by this provider */ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { From 14875e57d8ea9659916cfff524f6a268e882baf7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 19 Jan 2020 10:12:46 +0000 Subject: [PATCH 054/809] clk: imx: imx8mp: add ocotp root clk Add ocotp root clk, then when using nvmem to read fuse, clk could be managed. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index f6c120cca0d4..ee83aa2162d9 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -671,6 +671,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", ccm_base + 0x4180, 0); hws[IMX8MP_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", ccm_base + 0x4190, 0); hws[IMX8MP_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", ccm_base + 0x41a0, 0); + hws[IMX8MP_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", ccm_base + 0x4220, 0); hws[IMX8MP_CLK_PCIE_ROOT] = imx_clk_hw_gate4("pcie_root_clk", "pcie_aux", ccm_base + 0x4250, 0); hws[IMX8MP_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", ccm_base + 0x4280, 0); hws[IMX8MP_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", ccm_base + 0x4290, 0); From 62668b68dc8e7d4c23cdec60f31d9c8dc1384409 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 28 Jan 2020 05:28:36 +0000 Subject: [PATCH 055/809] clk: imx: composite-8m: add imx8m_clk_hw_composite_core There are several clock slices, current composite code only support bus/ip clock slices, it could not support core slice. So introduce a new API imx8m_clk_hw_composite_core to support core slice. To core slice, post divider with 3 bits width and no pre divider. Other fields are same as bus/ip slices. Add a flag IMX_COMPOSITE_CORE for the usecase. Reviewed-by: Abel Vesa Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-composite-8m.c | 18 ++++++++++++++---- drivers/clk/imx/clk.h | 13 +++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 20f7c91c03d2..4869c16376bf 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -15,6 +15,7 @@ #define PCG_PREDIV_MAX 8 #define PCG_DIV_SHIFT 0 +#define PCG_CORE_DIV_WIDTH 3 #define PCG_DIV_WIDTH 6 #define PCG_DIV_MAX 64 @@ -126,6 +127,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = { struct clk_hw *imx8m_clk_hw_composite_flags(const char *name, const char * const *parent_names, int num_parents, void __iomem *reg, + u32 composite_flags, unsigned long flags) { struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw; @@ -133,6 +135,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name, struct clk_divider *div = NULL; struct clk_gate *gate = NULL; struct clk_mux *mux = NULL; + const struct clk_ops *divider_ops; mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) @@ -150,8 +153,16 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name, div_hw = &div->hw; div->reg = reg; - div->shift = PCG_PREDIV_SHIFT; - div->width = PCG_PREDIV_WIDTH; + if (composite_flags & IMX_COMPOSITE_CORE) { + div->shift = PCG_DIV_SHIFT; + div->width = PCG_CORE_DIV_WIDTH; + divider_ops = &clk_divider_ops; + } else { + div->shift = PCG_PREDIV_SHIFT; + div->width = PCG_PREDIV_WIDTH; + divider_ops = &imx8m_clk_composite_divider_ops; + } + div->lock = &imx_ccm_lock; div->flags = CLK_DIVIDER_ROUND_CLOSEST; @@ -166,8 +177,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name, hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, mux_hw, &clk_mux_ops, div_hw, - &imx8m_clk_composite_divider_ops, - gate_hw, &clk_gate_ops, flags); + divider_ops, gate_hw, &clk_gate_ops, flags); if (IS_ERR(hw)) goto fail; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index b05213b91dcf..f074dd8ec42e 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -477,20 +477,29 @@ struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name, struct clk *div, struct clk *mux, struct clk *pll, struct clk *step); +#define IMX_COMPOSITE_CORE BIT(0) + struct clk_hw *imx8m_clk_hw_composite_flags(const char *name, const char * const *parent_names, int num_parents, void __iomem *reg, + u32 composite_flags, unsigned long flags); +#define imx8m_clk_hw_composite_core(name, parent_names, reg) \ + imx8m_clk_hw_composite_flags(name, parent_names, \ + ARRAY_SIZE(parent_names), reg, \ + IMX_COMPOSITE_CORE, \ + CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE) + #define imx8m_clk_composite_flags(name, parent_names, num_parents, reg, \ flags) \ to_clk(imx8m_clk_hw_composite_flags(name, parent_names, \ - num_parents, reg, flags)) + num_parents, reg, 0, flags)) #define __imx8m_clk_hw_composite(name, parent_names, reg, flags) \ imx8m_clk_hw_composite_flags(name, parent_names, \ - ARRAY_SIZE(parent_names), reg, \ + ARRAY_SIZE(parent_names), reg, 0, \ flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE) #define __imx8m_clk_composite(name, parent_names, reg, flags) \ From 7a8d3b90bdfe44d2e90523444ff82f0060d9560e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 28 Jan 2020 05:28:41 +0000 Subject: [PATCH 056/809] clk: imx: imx8mq: use imx8m_clk_hw_composite_core Use imx8m_clk_hw_composite_core to simplify code. Add new definitions, and X_SRC/CG/DIV will be alias to the new definitions for backwards compatibility Reviewed-by: Abel Vesa Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mq.c | 34 +++++++++++++----------- include/dt-bindings/clock/imx8mq-clock.h | 7 ++++- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 4c0edca1a6d0..ac9452cd9a82 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -403,22 +403,26 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) /* CORE */ hws[IMX8MQ_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels)); - hws[IMX8MQ_CLK_M4_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mq_arm_m4_sels, ARRAY_SIZE(imx8mq_arm_m4_sels)); - hws[IMX8MQ_CLK_VPU_SRC] = imx_clk_hw_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels)); - hws[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_hw_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels)); - hws[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_hw_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels, ARRAY_SIZE(imx8mq_gpu_shader_sels)); - hws[IMX8MQ_CLK_A53_CG] = imx_clk_hw_gate3_flags("arm_a53_cg", "arm_a53_src", base + 0x8000, 28, CLK_IS_CRITICAL); - hws[IMX8MQ_CLK_M4_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28); - hws[IMX8MQ_CLK_VPU_CG] = imx_clk_hw_gate3("vpu_cg", "vpu_src", base + 0x8100, 28); - hws[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_hw_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28); - hws[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_hw_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28); - hws[IMX8MQ_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3); - hws[IMX8MQ_CLK_M4_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3); - hws[IMX8MQ_CLK_VPU_DIV] = imx_clk_hw_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3); - hws[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_hw_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3); - hws[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_hw_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3); + + hws[IMX8MQ_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mq_arm_m4_sels, base + 0x8080); + hws[IMX8MQ_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mq_vpu_sels, base + 0x8100); + hws[IMX8MQ_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mq_gpu_core_sels, base + 0x8180); + hws[IMX8MQ_CLK_GPU_SHADER] = imx8m_clk_hw_composite("gpu_shader", imx8mq_gpu_shader_sels, base + 0x8200); + /* For backwards compatibility */ + hws[IMX8MQ_CLK_M4_SRC] = hws[IMX8MQ_CLK_M4_CORE]; + hws[IMX8MQ_CLK_M4_CG] = hws[IMX8MQ_CLK_M4_CORE]; + hws[IMX8MQ_CLK_M4_DIV] = hws[IMX8MQ_CLK_M4_CORE]; + hws[IMX8MQ_CLK_VPU_SRC] = hws[IMX8MQ_CLK_VPU_CORE]; + hws[IMX8MQ_CLK_VPU_CG] = hws[IMX8MQ_CLK_VPU_CORE]; + hws[IMX8MQ_CLK_VPU_DIV] = hws[IMX8MQ_CLK_VPU_CORE]; + hws[IMX8MQ_CLK_GPU_CORE_SRC] = hws[IMX8MQ_CLK_GPU_CORE]; + hws[IMX8MQ_CLK_GPU_CORE_CG] = hws[IMX8MQ_CLK_GPU_CORE]; + hws[IMX8MQ_CLK_GPU_CORE_DIV] = hws[IMX8MQ_CLK_GPU_CORE]; + hws[IMX8MQ_CLK_GPU_SHADER_SRC] = hws[IMX8MQ_CLK_GPU_SHADER]; + hws[IMX8MQ_CLK_GPU_SHADER_CG] = hws[IMX8MQ_CLK_GPU_SHADER]; + hws[IMX8MQ_CLK_GPU_SHADER_DIV] = hws[IMX8MQ_CLK_GPU_SHADER]; /* BUS */ hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800); @@ -567,7 +571,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0); hws[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0); hws[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_hw_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE); - hws[IMX8MQ_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0); + hws[IMX8MQ_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_core", base + 0x4570, 0); hws[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_hw_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE); hws[IMX8MQ_CLK_DISP_ROOT] = imx_clk_hw_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss); hws[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_hw_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss); diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 3bab9b21c8d7..2b88723310bd 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -424,6 +424,11 @@ #define IMX8MQ_SYS2_PLL_500M_CG 283 #define IMX8MQ_SYS2_PLL_1000M_CG 284 -#define IMX8MQ_CLK_END 285 +#define IMX8MQ_CLK_GPU_CORE 285 +#define IMX8MQ_CLK_GPU_SHADER 286 +#define IMX8MQ_CLK_M4_CORE 287 +#define IMX8MQ_CLK_VPU_CORE 288 + +#define IMX8MQ_CLK_END 289 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ From 811e4171d0f5ac6d1172333adf361c74ce2c8ec5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 28 Jan 2020 05:28:46 +0000 Subject: [PATCH 057/809] clk: imx: imx8mm: use imx8m_clk_hw_composite_core Use imx8m_clk_hw_composite_core to simplify code. Add new definitions, and X_SRC/CG/DIV will be alias to the new definitions for backwards compatibility Reviewed-by: Abel Vesa Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 35 ++++++++++++++---------- include/dt-bindings/clock/imx8mm-clock.h | 7 ++++- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 2ed93fc25087..f79a5f5d9ed5 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -414,20 +414,27 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) /* Core Slice */ hws[IMX8MM_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels)); - hws[IMX8MM_CLK_M4_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels)); - hws[IMX8MM_CLK_VPU_SRC] = imx_clk_hw_mux2("vpu_src", base + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels)); - hws[IMX8MM_CLK_GPU3D_SRC] = imx_clk_hw_mux2("gpu3d_src", base + 0x8180, 24, 3, imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels)); - hws[IMX8MM_CLK_GPU2D_SRC] = imx_clk_hw_mux2("gpu2d_src", base + 0x8200, 24, 3, imx8mm_gpu2d_sels, ARRAY_SIZE(imx8mm_gpu2d_sels)); hws[IMX8MM_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28); - hws[IMX8MM_CLK_M4_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28); - hws[IMX8MM_CLK_VPU_CG] = imx_clk_hw_gate3("vpu_cg", "vpu_src", base + 0x8100, 28); - hws[IMX8MM_CLK_GPU3D_CG] = imx_clk_hw_gate3("gpu3d_cg", "gpu3d_src", base + 0x8180, 28); - hws[IMX8MM_CLK_GPU2D_CG] = imx_clk_hw_gate3("gpu2d_cg", "gpu2d_src", base + 0x8200, 28); hws[IMX8MM_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3); - hws[IMX8MM_CLK_M4_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3); - hws[IMX8MM_CLK_VPU_DIV] = imx_clk_hw_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3); - hws[IMX8MM_CLK_GPU3D_DIV] = imx_clk_hw_divider2("gpu3d_div", "gpu3d_cg", base + 0x8180, 0, 3); - hws[IMX8MM_CLK_GPU2D_DIV] = imx_clk_hw_divider2("gpu2d_div", "gpu2d_cg", base + 0x8200, 0, 3); + + hws[IMX8MM_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mm_m4_sels, base + 0x8080); + hws[IMX8MM_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mm_vpu_sels, base + 0x8100); + hws[IMX8MM_CLK_GPU3D_CORE] = imx8m_clk_hw_composite_core("gpu3d_core", imx8mm_gpu3d_sels, base + 0x8180); + hws[IMX8MM_CLK_GPU2D_CORE] = imx8m_clk_hw_composite_core("gpu2d_core", imx8mm_gpu2d_sels, base + 0x8200); + + /* For backwards compatibility */ + hws[IMX8MM_CLK_M4_SRC] = hws[IMX8MM_CLK_M4_CORE]; + hws[IMX8MM_CLK_M4_CG] = hws[IMX8MM_CLK_M4_CORE]; + hws[IMX8MM_CLK_M4_DIV] = hws[IMX8MM_CLK_M4_CORE]; + hws[IMX8MM_CLK_VPU_SRC] = hws[IMX8MM_CLK_VPU_CORE]; + hws[IMX8MM_CLK_VPU_CG] = hws[IMX8MM_CLK_VPU_CORE]; + hws[IMX8MM_CLK_VPU_DIV] = hws[IMX8MM_CLK_VPU_CORE]; + hws[IMX8MM_CLK_GPU3D_SRC] = hws[IMX8MM_CLK_GPU3D_CORE]; + hws[IMX8MM_CLK_GPU3D_CG] = hws[IMX8MM_CLK_GPU3D_CORE]; + hws[IMX8MM_CLK_GPU3D_DIV] = hws[IMX8MM_CLK_GPU3D_CORE]; + hws[IMX8MM_CLK_GPU2D_SRC] = hws[IMX8MM_CLK_GPU2D_CORE]; + hws[IMX8MM_CLK_GPU2D_CG] = hws[IMX8MM_CLK_GPU2D_CORE]; + hws[IMX8MM_CLK_GPU2D_DIV] = hws[IMX8MM_CLK_GPU2D_CORE]; /* BUS */ hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); @@ -564,7 +571,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0); hws[IMX8MM_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0); hws[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0); - hws[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_div", base + 0x44f0, 0); + hws[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core", base + 0x44f0, 0); hws[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0); hws[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0); hws[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0); @@ -586,7 +593,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0); hws[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0); hws[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0); - hws[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_div", base + 0x4660, 0); + hws[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_core", base + 0x4660, 0); hws[IMX8MM_CLK_CSI1_ROOT] = imx_clk_hw_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0); hws[IMX8MM_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8); diff --git a/include/dt-bindings/clock/imx8mm-clock.h b/include/dt-bindings/clock/imx8mm-clock.h index edeece2289f0..038c28d349e8 100644 --- a/include/dt-bindings/clock/imx8mm-clock.h +++ b/include/dt-bindings/clock/imx8mm-clock.h @@ -265,6 +265,11 @@ #define IMX8MM_SYS_PLL2_333M_CG 244 #define IMX8MM_SYS_PLL2_500M_CG 245 -#define IMX8MM_CLK_END 246 +#define IMX8MM_CLK_M4_CORE 246 +#define IMX8MM_CLK_VPU_CORE 247 +#define IMX8MM_CLK_GPU3D_CORE 248 +#define IMX8MM_CLK_GPU2D_CORE 249 + +#define IMX8MM_CLK_END 250 #endif From 33db2ce73e9affe9a25130b166048f5a209d4dc1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 28 Jan 2020 05:28:50 +0000 Subject: [PATCH 058/809] clk: imx: imx8mn: use imx8m_clk_hw_composite_core Use imx8m_clk_hw_composite_core to simplify code. Add new definitions, and X_SRC/CG/DIV will be alias to the new definitions for backwards compatibility Reviewed-by: Abel Vesa Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 19 +++++++++++-------- include/dt-bindings/clock/imx8mn-clock.h | 4 +++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index a181eb2df876..7eea15a81838 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -413,15 +413,18 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) /* CORE */ hws[IMX8MN_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels)); - hws[IMX8MN_CLK_GPU_CORE_SRC] = imx_clk_hw_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mn_gpu_core_sels, ARRAY_SIZE(imx8mn_gpu_core_sels)); - hws[IMX8MN_CLK_GPU_SHADER_SRC] = imx_clk_hw_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mn_gpu_shader_sels, ARRAY_SIZE(imx8mn_gpu_shader_sels)); hws[IMX8MN_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28); - hws[IMX8MN_CLK_GPU_CORE_CG] = imx_clk_hw_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28); - hws[IMX8MN_CLK_GPU_SHADER_CG] = imx_clk_hw_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28); - hws[IMX8MN_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3); - hws[IMX8MN_CLK_GPU_CORE_DIV] = imx_clk_hw_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3); - hws[IMX8MN_CLK_GPU_SHADER_DIV] = imx_clk_hw_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3); + + hws[IMX8MN_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mn_gpu_core_sels, base + 0x8180); + hws[IMX8MN_CLK_GPU_SHADER] = imx8m_clk_hw_composite_core("gpu_shader", imx8mn_gpu_shader_sels, base + 0x8200); + + hws[IMX8MN_CLK_GPU_CORE_SRC] = hws[IMX8MN_CLK_GPU_CORE]; + hws[IMX8MN_CLK_GPU_CORE_CG] = hws[IMX8MN_CLK_GPU_CORE]; + hws[IMX8MN_CLK_GPU_CORE_DIV] = hws[IMX8MN_CLK_GPU_CORE]; + hws[IMX8MN_CLK_GPU_SHADER_SRC] = hws[IMX8MN_CLK_GPU_SHADER]; + hws[IMX8MN_CLK_GPU_SHADER_CG] = hws[IMX8MN_CLK_GPU_SHADER]; + hws[IMX8MN_CLK_GPU_SHADER_DIV] = hws[IMX8MN_CLK_GPU_SHADER]; /* BUS */ hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800); @@ -529,7 +532,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0); hws[IMX8MN_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0); hws[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0); - hws[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_hw_gate4("gpu_core_root_clk", "gpu_core_div", base + 0x44f0, 0); + hws[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_hw_gate4("gpu_core_root_clk", "gpu_core", base + 0x44f0, 0); hws[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0); hws[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0); hws[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0); diff --git a/include/dt-bindings/clock/imx8mn-clock.h b/include/dt-bindings/clock/imx8mn-clock.h index 43883fe65db5..c42a22d3cf7c 100644 --- a/include/dt-bindings/clock/imx8mn-clock.h +++ b/include/dt-bindings/clock/imx8mn-clock.h @@ -229,7 +229,9 @@ #define IMX8MN_SYS_PLL2_500M_CG 210 #define IMX8MN_CLK_SNVS_ROOT 211 +#define IMX8MN_CLK_GPU_CORE 212 +#define IMX8MN_CLK_GPU_SHADER 213 -#define IMX8MN_CLK_END 212 +#define IMX8MN_CLK_END 214 #endif From bcacd6f7c94abb99300e365a6aef93212fc24f15 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 11 Feb 2020 00:08:12 -0300 Subject: [PATCH 059/809] clk: imx8mm: Fix the CLKO1 source select list The CLKO1 clock source select list is the following as per the i.MX8MM Reference Manual (put in increasing order): 000 - 24M_REF_CLK 001 - SYSTEM_PLL1_CLK 010 - None 011 - SYSTEM_PLL1_DIV4 100 - AUDIO_PLL2_CLK 101 - SYSTEM_PLL2_DIV2 110 - VPU_PLL_CLK 111 - SYSTEM_PLL1_DIV10 Fix it accordingly. Fixes: ba5625c3e272 ("clk: imx: Add clock driver support for imx8mm") Signed-off-by: Fabio Estevam Reviewed-by: Abel Vesa Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index f79a5f5d9ed5..523a5b15ae7d 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -283,8 +283,8 @@ static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_8 static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; -static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out", - "vpu_pll", "sys_pll1_80m", }; +static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "dummy", "sys_pll1_200m", + "audio_pll2_out", "sys_pll2_500m", "vpu_pll", "sys_pll1_80m", }; static struct clk_hw_onecell_data *clk_hw_data; static struct clk_hw **hws; From 9c07ae6983d434841bb19bea0a75bd0fd925a75c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Feb 2020 13:49:38 +0800 Subject: [PATCH 060/809] clk: imx8mm: Add CLKO2 support Add CLKO2 support, which is useful for debugging purposes. Signed-off-by: Fabio Estevam Reviewed-by: Abel Vesa Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 3 +++ include/dt-bindings/clock/imx8mm-clock.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 523a5b15ae7d..6dbdc1a1b5eb 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -285,6 +285,8 @@ static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", } static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "dummy", "sys_pll1_200m", "audio_pll2_out", "sys_pll2_500m", "vpu_pll", "sys_pll1_80m", }; +static const char *imx8mm_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m", "sys_pll2_166m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", "osc_32k", }; static struct clk_hw_onecell_data *clk_hw_data; static struct clk_hw **hws; @@ -511,6 +513,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mm_wdog_sels, base + 0xb900); hws[IMX8MM_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mm_wrclk_sels, base + 0xb980); hws[IMX8MM_CLK_CLKO1] = imx8m_clk_hw_composite("clko1", imx8mm_clko1_sels, base + 0xba00); + hws[IMX8MM_CLK_CLKO2] = imx8m_clk_hw_composite("clko2", imx8mm_clko2_sels, base + 0xba80); hws[IMX8MM_CLK_DSI_CORE] = imx8m_clk_hw_composite("dsi_core", imx8mm_dsi_core_sels, base + 0xbb00); hws[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_hw_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, base + 0xbb80); hws[IMX8MM_CLK_DSI_DBI] = imx8m_clk_hw_composite("dsi_dbi", imx8mm_dsi_dbi_sels, base + 0xbc00); diff --git a/include/dt-bindings/clock/imx8mm-clock.h b/include/dt-bindings/clock/imx8mm-clock.h index 038c28d349e8..dbfee6579d6c 100644 --- a/include/dt-bindings/clock/imx8mm-clock.h +++ b/include/dt-bindings/clock/imx8mm-clock.h @@ -270,6 +270,8 @@ #define IMX8MM_CLK_GPU3D_CORE 248 #define IMX8MM_CLK_GPU2D_CORE 249 -#define IMX8MM_CLK_END 250 +#define IMX8MM_CLK_CLKO2 250 + +#define IMX8MM_CLK_END 251 #endif From f95d58981f40b546429e1b06e441c70bcc52786e Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 15:02:23 +0800 Subject: [PATCH 061/809] clk: imx: Include clk-provider.h instead of clk.h for i.MX8M SoCs clock driver The i.MX8M SoCs clock driver are provider, NOT consumer, so clk-provider.h should be used instead of clk.h. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 2 +- drivers/clk/imx/clk-imx8mn.c | 2 +- drivers/clk/imx/clk-imx8mq.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 6dbdc1a1b5eb..0cba5d4bd51e 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 7eea15a81838..6f4547fec368 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index ac9452cd9a82..8b4b2fbe4a65 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include From 79ccef698ac811b3029fd01cbe2114fed3219c8a Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 17:03:00 +0800 Subject: [PATCH 062/809] clk: imx: drop redundant initialization No need to initialize flags as 0, remove the initialization. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-composite-8m.c | 2 +- drivers/clk/imx/clk-fixup-div.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk-gate2.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 4869c16376bf..99773519b5a5 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -92,7 +92,7 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_divider *divider = to_clk_divider(hw); - unsigned long flags = 0; + unsigned long flags; int prediv_value; int div_value; int ret; diff --git a/drivers/clk/imx/clk-fixup-div.c b/drivers/clk/imx/clk-fixup-div.c index 4b17b91504ed..100ca828b052 100644 --- a/drivers/clk/imx/clk-fixup-div.c +++ b/drivers/clk/imx/clk-fixup-div.c @@ -55,7 +55,7 @@ static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); struct clk_divider *div = to_clk_divider(hw); unsigned int divider, value; - unsigned long flags = 0; + unsigned long flags; u32 val; divider = parent_rate / rate; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index b569d919c645..58a67630bb6a 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -42,7 +42,7 @@ static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index) { struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw); struct clk_mux *mux = to_clk_mux(hw); - unsigned long flags = 0; + unsigned long flags; u32 val; spin_lock_irqsave(mux->lock, flags); diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 7d44ce814806..72a7698be791 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -40,7 +40,7 @@ static int clk_gate2_enable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); u32 reg; - unsigned long flags = 0; + unsigned long flags; spin_lock_irqsave(gate->lock, flags); @@ -62,7 +62,7 @@ static void clk_gate2_disable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); u32 reg; - unsigned long flags = 0; + unsigned long flags; spin_lock_irqsave(gate->lock, flags); @@ -101,7 +101,7 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) static void clk_gate2_disable_unused(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - unsigned long flags = 0; + unsigned long flags; u32 reg; spin_lock_irqsave(gate->lock, flags); From 836b2513326ef047e67123ecea389e65addf6c18 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 17:09:43 +0800 Subject: [PATCH 063/809] clk: imx7ulp: Include clk-provider.h instead of clk.h The i.MX7ULP clock driver is provider, NOT consumer, so clk-provider.h should be used instead of clk.h. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx7ulp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c index 0620d6c8c072..3710aa0dee9b 100644 --- a/drivers/clk/imx/clk-imx7ulp.c +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include From 8b1a3c0ba9b1cec6dc91904604130a435d90c53c Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 19:57:33 +0800 Subject: [PATCH 064/809] clk: imx6sl: Add missing of_node_put() After finishing using device node got from of_find_compatible_node(), of_node_put() needs to be called. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx6sl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c index 4bd44d89eaaa..0f647d148abf 100644 --- a/drivers/clk/imx/clk-imx6sl.c +++ b/drivers/clk/imx/clk-imx6sl.c @@ -208,6 +208,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); anatop_base = base; hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); From cb5ae504f2014a66c131920b8eb0ca6b0e6851c6 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 19:57:34 +0800 Subject: [PATCH 065/809] clk: imx8mq: Add missing of_node_put() After finishing using device node got from of_find_compatible_node(), of_node_put() needs to be called. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 8b4b2fbe4a65..1f5ea1eaad65 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -305,6 +305,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop"); base = of_iomap(np, 0); + of_node_put(np); if (WARN_ON(!base)) return -ENOMEM; From 5062d46e2698e720f866c06563419bff09dcacb4 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 19:57:35 +0800 Subject: [PATCH 066/809] clk: imx8mm: Add missing of_node_put() After finishing using device node got from of_find_compatible_node(), of_node_put() needs to be called. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 0cba5d4bd51e..2f2c240a86e2 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -324,6 +324,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); base = of_iomap(np, 0); + of_node_put(np); if (WARN_ON(!base)) return -ENOMEM; From d93171b54cb44e65c1ec5462c17704b51b8afc27 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 19:57:36 +0800 Subject: [PATCH 067/809] clk: imx8mn: Add missing of_node_put() After finishing using device node got from of_find_compatible_node(), of_node_put() needs to be called. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 6f4547fec368..67b826d7184b 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -317,6 +317,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) np = of_find_compatible_node(NULL, NULL, "fsl,imx8mn-anatop"); base = of_iomap(np, 0); + of_node_put(np); if (WARN_ON(!base)) { ret = -ENOMEM; goto unregister_hws; From 680fbce528169eaadf621066a4925794e2addbd7 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2020 19:57:37 +0800 Subject: [PATCH 068/809] clk: imx8mp: Add missing of_node_put() After finishing using device node got from of_find_compatible_node(), of_node_put() needs to be called. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index ee83aa2162d9..a16af4fce044 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -434,6 +434,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop"); anatop_base = of_iomap(np, 0); + of_node_put(np); if (WARN_ON(!anatop_base)) return -ENOMEM; From 0d6f1693f255795d5c747dc444d69c6512586d98 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 4 Dec 2019 09:29:20 +0100 Subject: [PATCH 069/809] s390/cpum_sf: Rework sampling buffer allocation Adjust sampling buffer allocation depending on frequency and correct comments. Investigation on the interrupt handler revealed that almost always one interupt services one SDB, even when running with the maximum frequency of 100000. Very rarely there have been 2 SBD serviced per interrupt. Therefore reduce the number of SBD per CPU. Each SDB is one page in size. The new formula results in freq:4000 n_sdb:32 new:16 freq:10000 n_sdb:80 new:16 freq:20000 n_sdb:159 new:17 freq:40000 n_sdb:318 new:19 freq:50000 n_sdb:397 new:20 freq:62500 n_sdb:497 new:22 freq:83333 n_sdb:662 new:24 freq:100000 n_sdb:794 new:25 Signed-off-by: Thomas Richter Signed-off-by: Vasily Gorbik --- arch/s390/kernel/perf_cpum_sf.c | 40 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index b095b1c78987..cf2020b8db44 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -372,28 +372,33 @@ static void deallocate_buffers(struct cpu_hw_sf *cpuhw) static int allocate_buffers(struct cpu_hw_sf *cpuhw, struct hw_perf_event *hwc) { - unsigned long n_sdb, freq, factor; + unsigned long n_sdb, freq; size_t sample_size; /* Calculate sampling buffers using 4K pages * - * 1. Determine the sample data size which depends on the used - * sampling functions, for example, basic-sampling or - * basic-sampling with diagnostic-sampling. + * 1. The sampling size is 32 bytes for basic sampling. This size + * is the same for all machine types. Diagnostic + * sampling uses auxlilary data buffer setup which provides the + * memory for SDBs using linux common code auxiliary trace + * setup. * - * 2. Use the sampling frequency as input. The sampling buffer is - * designed for almost one second. This can be adjusted through - * the "factor" variable. - * In any case, alloc_sampling_buffer() sets the Alert Request + * 2. Function alloc_sampling_buffer() sets the Alert Request * Control indicator to trigger a measurement-alert to harvest - * sample-data-blocks (sdb). + * sample-data-blocks (SDB). This is done per SDB. This + * measurement alert interrupt fires quick enough to handle + * one SDB, on very high frequency and work loads there might + * be 2 to 3 SBDs available for sample processing. + * Currently there is no need for setup alert request on every + * n-th page. This is counterproductive as one IRQ triggers + * a very high number of samples to be processed at one IRQ. * - * 3. Compute the number of sample-data-blocks and ensure a minimum - * of CPUM_SF_MIN_SDB. Also ensure the upper limit does not - * exceed a "calculated" maximum. The symbolic maximum is - * designed for basic-sampling only and needs to be increased if - * diagnostic-sampling is active. - * See also the remarks for these symbolic constants. + * 3. Use the sampling frequency as input. + * Compute the number of SDBs and ensure a minimum + * of CPUM_SF_MIN_SDB. Depending on frequency add some more + * SDBs to handle a higher sampling rate. + * Use a minimum of CPUM_SF_MIN_SDB and allow for 100 samples + * (one SDB) for every 10000 HZ frequency increment. * * 4. Compute the number of sample-data-block-tables (SDBT) and * ensure a minimum of CPUM_SF_MIN_SDBT (one table can manage up @@ -401,10 +406,7 @@ static int allocate_buffers(struct cpu_hw_sf *cpuhw, struct hw_perf_event *hwc) */ sample_size = sizeof(struct hws_basic_entry); freq = sample_rate_to_freq(&cpuhw->qsi, SAMPL_RATE(hwc)); - factor = 1; - n_sdb = DIV_ROUND_UP(freq, factor * ((PAGE_SIZE-64) / sample_size)); - if (n_sdb < CPUM_SF_MIN_SDB) - n_sdb = CPUM_SF_MIN_SDB; + n_sdb = CPUM_SF_MIN_SDB + DIV_ROUND_UP(freq, 10000); /* If there is already a sampling buffer allocated, it is very likely * that the sampling facility is enabled too. If the event to be From c4f762ff6b7766e0053e39d1d87d599384288048 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 7 Feb 2020 09:05:56 +0100 Subject: [PATCH 070/809] s390/zcrypt: Support for CCA protected key block version 2 There will come a new CCA keyblock version 2 for protected keys delivered back to the OS. The difference is only the amount of available buffer space to be up to 256 bytes for version 2. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 110fe9d0cb91..e6899107c586 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -592,7 +592,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain, u8 pad2[1]; u8 vptype; u8 vp[32]; /* verification pattern */ - } keyblock; + } ckb; } lv3; } __packed * prepparm; @@ -650,15 +650,16 @@ int cca_sec2protkey(u16 cardnr, u16 domain, prepparm = (struct uskrepparm *) prepcblk->rpl_parmb; /* check the returned keyblock */ - if (prepparm->lv3.keyblock.version != 0x01) { - DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x01\n", - __func__, (int) prepparm->lv3.keyblock.version); + if (prepparm->lv3.ckb.version != 0x01 && + prepparm->lv3.ckb.version != 0x02) { + DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n", + __func__, (int) prepparm->lv3.ckb.version); rc = -EIO; goto out; } /* copy the tanslated protected key */ - switch (prepparm->lv3.keyblock.len) { + switch (prepparm->lv3.ckb.len) { case 16+32: /* AES 128 protected key */ if (protkeytype) @@ -676,13 +677,13 @@ int cca_sec2protkey(u16 cardnr, u16 domain, break; default: DEBUG_ERR("%s unknown/unsupported keylen %d\n", - __func__, prepparm->lv3.keyblock.len); + __func__, prepparm->lv3.ckb.len); rc = -EIO; goto out; } - memcpy(protkey, prepparm->lv3.keyblock.key, prepparm->lv3.keyblock.len); + memcpy(protkey, prepparm->lv3.ckb.key, prepparm->lv3.ckb.len); if (protkeylen) - *protkeylen = prepparm->lv3.keyblock.len; + *protkeylen = prepparm->lv3.ckb.len; out: free_cprbmem(mem, PARMBSIZE, 0); @@ -1260,10 +1261,10 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, prepparm = (struct aurepparm *) prepcblk->rpl_parmb; /* check the returned keyblock */ - if (prepparm->vud.ckb.version != 0x01) { - DEBUG_ERR( - "%s reply param keyblock version mismatch 0x%02x != 0x01\n", - __func__, (int) prepparm->vud.ckb.version); + if (prepparm->vud.ckb.version != 0x01 && + prepparm->vud.ckb.version != 0x02) { + DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n", + __func__, (int) prepparm->vud.ckb.version); rc = -EIO; goto out; } From a137e9b620bcf3925a8d72dd7ba723910d0bf976 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Sun, 16 Feb 2020 11:27:45 +0800 Subject: [PATCH 071/809] rtc: snvs: Remove unused include of of_device.h There is nothing in use from of_device.h, remove it. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1581823666-16944-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-snvs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 757f4daa7181..7630089a113c 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include From 64bee9c6cd48179010149313f74f9557345fd0da Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 18 Feb 2020 19:03:24 +0800 Subject: [PATCH 072/809] clk: imx8mp: Include slab.h instead of clkdev.h slab.h is necessary and included indirectly by clkdev.h, actually, there is nothing in use from clkdev.h, so just include slab.h instead of clkdev.h. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index a16af4fce044..3adc8aa46200 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -4,13 +4,13 @@ */ #include -#include #include #include #include #include #include #include +#include #include #include "clk.h" From 2b507025e4b728bb1612855caa6a4abaf5fb0030 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 18 Feb 2020 19:03:25 +0800 Subject: [PATCH 073/809] clk: imx8mm: Remove unused includes There is nothing in use from init.h/of.h, remove them. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 2f2c240a86e2..481d20ae4e0b 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -6,10 +6,8 @@ #include #include #include -#include #include #include -#include #include #include #include From 6b2d0cffee52260bbf20414ce408af3f6f718d52 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 18 Feb 2020 19:03:26 +0800 Subject: [PATCH 074/809] clk: imx8mn: Remove unused includes There is nothing in use from init.h/of.h, remove them. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 67b826d7184b..fb47f86e35e8 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -6,10 +6,8 @@ #include #include #include -#include #include #include -#include #include #include #include From f98df5ed0a670f2c4c1a50d7901acbb862a247c7 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Thu, 30 Jan 2020 17:31:52 +1100 Subject: [PATCH 075/809] powerpc/pseries/vio: Remove stray #ifdef CONFIG_PPC_PSERIES vio.c is in platforms/pseries, which is only built if PPC_PSERIES=y. In other words, this ifdef is pointless. Signed-off-by: Oliver O'Halloran Reviewed-by: Tyrel Datwyler Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200130063153.19915-1-oohall@gmail.com --- arch/powerpc/platforms/pseries/vio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index f682b7babc09..37f1f25ba804 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1628,7 +1628,6 @@ const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) } EXPORT_SYMBOL(vio_get_attribute); -#ifdef CONFIG_PPC_PSERIES /* vio_find_name() - internal because only vio.c knows how we formatted the * kobject name */ @@ -1698,7 +1697,6 @@ int vio_disable_interrupts(struct vio_dev *dev) return rc; } EXPORT_SYMBOL(vio_disable_interrupts); -#endif /* CONFIG_PPC_PSERIES */ static int __init vio_init(void) { From 8cbb00a901037986f4066e2fc0d36a4882475662 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Thu, 30 Jan 2020 17:31:53 +1100 Subject: [PATCH 076/809] powerpc/pseries/Makefile: Remove CONFIG_PPC_PSERIES check The pseries Makefile (arch/powerpc/platforms/pseries/Makefile) is only included by the platform Makefile (arch/powerpc/platform/Makefile) when CONFIG_PPC_PSERIES is selected, so checking for CONFIG_PPC_PSERIES in the pseries Makefile is pointless. Signed-off-by: Oliver O'Halloran Reviewed-by: Tyrel Datwyler Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200130063153.19915-2-oohall@gmail.com --- arch/powerpc/platforms/pseries/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index a3c74a5cf20d..c8a2b0b05ac0 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -29,6 +29,4 @@ obj-$(CONFIG_PPC_SPLPAR) += vphn.o obj-$(CONFIG_PPC_SVM) += svm.o obj-$(CONFIG_FA_DUMP) += rtas-fadump.o -ifdef CONFIG_PPC_PSERIES obj-$(CONFIG_SUSPEND) += suspend.o -endif From 72c4ebbac476b8375e69fd09390e6b64c2891716 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Thu, 30 Jan 2020 09:32:06 +0530 Subject: [PATCH 077/809] powerpc/papr_scm: Mark papr_scm_ndctl() as static Function papr_scm_ndctl() is neither exported from the module nor called directly from outside 'papr.c' hence should be marked 'static'. Signed-off-by: Vaibhav Jain Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200130040206.79998-1-vaibhav@linux.ibm.com --- arch/powerpc/platforms/pseries/papr_scm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 0b4467e378e5..e4606100e286 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -246,8 +246,9 @@ static int papr_scm_meta_set(struct papr_scm_priv *p, return 0; } -int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, - unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) +static int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc, + struct nvdimm *nvdimm, unsigned int cmd, void *buf, + unsigned int buf_len, int *cmd_rc) { struct nd_cmd_get_config_size *get_size_hdr; struct papr_scm_priv *p; From ba32f4b02105e57627912b42e141d65d90074c64 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 29 Jan 2020 19:50:07 +0000 Subject: [PATCH 078/809] powerpc/process: Remove unneccessary #ifdef CONFIG_PPC64 in copy_thread_tls() is_32bit_task() exists on both PPC64 and PPC32, no need of an ifdefery. Signed-off-by: Christophe Leroy Reviewed-by: Michal Suchanek Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/6ecbda05b4119c40222dc8ec284604e1597c9bff.1580327381.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/process.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index fad50db9dcf2..e730b8e522b0 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1634,11 +1634,9 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp, p->thread.regs = childregs; childregs->gpr[3] = 0; /* Result from fork() */ if (clone_flags & CLONE_SETTLS) { -#ifdef CONFIG_PPC64 if (!is_32bit_task()) childregs->gpr[13] = tls; else -#endif childregs->gpr[2] = tls; } From f52153ab383f04a45c38d8a7f55a4249477b20df Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:05 +0530 Subject: [PATCH 079/809] Documentation/ABI: Add ABI documentation for /sys/kernel/fadump_* Add missing ABI documentation for existing FADump sysfs files. Signed-off-by: Sourabh Jain Reviewed-by: Hari Bathini Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-2-sourabhjain@linux.ibm.com --- Documentation/ABI/testing/sysfs-kernel-fadump_enabled | 7 +++++++ Documentation/ABI/testing/sysfs-kernel-fadump_registered | 8 ++++++++ Documentation/ABI/testing/sysfs-kernel-fadump_release_mem | 8 ++++++++ .../ABI/testing/sysfs-kernel-fadump_release_opalcore | 7 +++++++ 4 files changed, 30 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-kernel-fadump_enabled create mode 100644 Documentation/ABI/testing/sysfs-kernel-fadump_registered create mode 100644 Documentation/ABI/testing/sysfs-kernel-fadump_release_mem create mode 100644 Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_enabled b/Documentation/ABI/testing/sysfs-kernel-fadump_enabled new file mode 100644 index 000000000000..f73632b1c006 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fadump_enabled @@ -0,0 +1,7 @@ +What: /sys/kernel/fadump_enabled +Date: Feb 2012 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Primarily used to identify whether the FADump is enabled in + the kernel or not. +User: Kdump service diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_registered b/Documentation/ABI/testing/sysfs-kernel-fadump_registered new file mode 100644 index 000000000000..dcf925e53f0f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fadump_registered @@ -0,0 +1,8 @@ +What: /sys/kernel/fadump_registered +Date: Feb 2012 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read/write + Helps to control the dump collect feature from userspace. + Setting 1 to this file enables the system to collect the + dump and 0 to disable it. +User: Kdump service diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_release_mem b/Documentation/ABI/testing/sysfs-kernel-fadump_release_mem new file mode 100644 index 000000000000..9c20d64ab48d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fadump_release_mem @@ -0,0 +1,8 @@ +What: /sys/kernel/fadump_release_mem +Date: Feb 2012 +Contact: linuxppc-dev@lists.ozlabs.org +Description: write only + This is a special sysfs file and only available when + the system is booted to capture the vmcore using FADump. + It is used to release the memory reserved by FADump to + save the crash dump. diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore b/Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore new file mode 100644 index 000000000000..53313c1d4e7a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore @@ -0,0 +1,7 @@ +What: /sys/kernel/fadump_release_opalcore +Date: Sep 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: write only + The sysfs file is available when the system is booted to + collect the dump on OPAL based machine. It used to release + the memory used to collect the opalcore. From 9255782f70614c89b1a15ec6997c4b72ce9e630a Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:06 +0530 Subject: [PATCH 080/809] sysfs: Wrap __compat_only_sysfs_link_entry_to_kobj function to change the symlink name The __compat_only_sysfs_link_entry_to_kobj function creates a symlink to a kobject but doesn't provide an option to change the symlink file name. This patch adds a wrapper function compat_only_sysfs_link_entry_to_kobj that extends the __compat_only_sysfs_link_entry_to_kobj functionality which allows function caller to customize the symlink name. Signed-off-by: Sourabh Jain [mpe: Fix compile error when CONFIG_SYSFS=n] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-3-sourabhjain@linux.ibm.com --- fs/sysfs/group.c | 28 +++++++++++++++++++++++++--- include/linux/sysfs.h | 12 ++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index c4ab045926b7..1e2a096057bc 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -424,6 +424,25 @@ EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, struct kobject *target_kobj, const char *target_name) +{ + return compat_only_sysfs_link_entry_to_kobj(kobj, target_kobj, + target_name, NULL); +} +EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj); + +/** + * compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing + * to a group or an attribute + * @kobj: The kobject containing the group. + * @target_kobj: The target kobject. + * @target_name: The name of the target group or attribute. + * @symlink_name: The name of the symlink file (target_name will be + * considered if symlink_name is NULL). + */ +int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, + struct kobject *target_kobj, + const char *target_name, + const char *symlink_name) { struct kernfs_node *target; struct kernfs_node *entry; @@ -448,12 +467,15 @@ int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, return -ENOENT; } - link = kernfs_create_link(kobj->sd, target_name, entry); + if (!symlink_name) + symlink_name = target_name; + + link = kernfs_create_link(kobj->sd, symlink_name, entry); if (PTR_ERR(link) == -EEXIST) - sysfs_warn_dup(kobj->sd, target_name); + sysfs_warn_dup(kobj->sd, symlink_name); kernfs_put(entry); kernfs_put(target); return PTR_ERR_OR_ZERO(link); } -EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj); +EXPORT_SYMBOL_GPL(compat_only_sysfs_link_entry_to_kobj); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index fa7ee503fb76..7462315a643b 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -300,6 +300,10 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, struct kobject *target_kobj, const char *target_name); +int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, + struct kobject *target_kobj, + const char *target_name, + const char *symlink_name); void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); @@ -508,6 +512,14 @@ static inline int __compat_only_sysfs_link_entry_to_kobj( return 0; } +static inline int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, + struct kobject *target_kobj, + const char *target_name, + const char *symlink_name) +{ + return 0; +} + static inline void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) { From d418b19f34ed0c751a69810080596f7e749595aa Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:07 +0530 Subject: [PATCH 081/809] powerpc/fadump: Reorganize /sys/kernel/fadump_* sysfs files As the number of FADump sysfs files increases it is hard to manage all of them inside /sys/kernel directory. It's better to have all the FADump related sysfs files in a dedicated directory /sys/kernel/fadump. But in order to maintain backward compatibility a symlink has been added for every sysfs that has moved to new location. As the FADump sysfs files are now part of a dedicated directory there is no need to prefix their name with fadump_, hence sysfs file names are also updated. For example fadump_enabled sysfs file is now referred as enabled. Also consolidate ABI documentation for all the FADump sysfs files in a single file Documentation/ABI/testing/sysfs-kernel-fadump. Signed-off-by: Sourabh Jain Tested-by: Michal Suchanek Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-4-sourabhjain@linux.ibm.com --- Documentation/ABI/testing/sysfs-kernel-fadump | 33 +++++ arch/powerpc/kernel/fadump.c | 119 +++++++++++++----- 2 files changed, 118 insertions(+), 34 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-kernel-fadump diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump b/Documentation/ABI/testing/sysfs-kernel-fadump new file mode 100644 index 000000000000..5d988b919e81 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fadump @@ -0,0 +1,33 @@ +What: /sys/kernel/fadump/* +Date: Dec 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: + The /sys/kernel/fadump/* is a collection of FADump sysfs + file provide information about the configuration status + of Firmware Assisted Dump (FADump). + +What: /sys/kernel/fadump/enabled +Date: Dec 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Primarily used to identify whether the FADump is enabled in + the kernel or not. +User: Kdump service + +What: /sys/kernel/fadump/registered +Date: Dec 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read/write + Helps to control the dump collect feature from userspace. + Setting 1 to this file enables the system to collect the + dump and 0 to disable it. +User: Kdump service + +What: /sys/kernel/fadump/release_mem +Date: Dec 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: write only + This is a special sysfs file and only available when + the system is booted to capture the vmcore using FADump. + It is used to release the memory reserved by FADump to + save the crash dump. diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index ff0114aeba9b..1182ae44ef14 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -36,6 +36,8 @@ static struct fw_dump fw_dump; static void __init fadump_reserve_crash_area(u64 base); +struct kobject *fadump_kobj; + #ifndef CONFIG_PRESERVE_FA_DUMP static DEFINE_MUTEX(fadump_mutex); struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 }; @@ -1323,9 +1325,9 @@ static void fadump_invalidate_release_mem(void) fw_dump.ops->fadump_init_mem_struct(&fw_dump); } -static ssize_t fadump_release_memory_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) +static ssize_t release_mem_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { int input = -1; @@ -1350,23 +1352,33 @@ static ssize_t fadump_release_memory_store(struct kobject *kobj, return count; } -static ssize_t fadump_enabled_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) +/* Release the reserved memory and disable the FADump */ +static void unregister_fadump(void) +{ + fadump_cleanup(); + fadump_release_memory(fw_dump.reserve_dump_area_start, + fw_dump.reserve_dump_area_size); + fw_dump.fadump_enabled = 0; + kobject_put(fadump_kobj); +} + +static ssize_t enabled_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", fw_dump.fadump_enabled); } -static ssize_t fadump_register_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) +static ssize_t registered_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", fw_dump.dump_registered); } -static ssize_t fadump_register_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) +static ssize_t registered_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { int ret = 0; int input = -1; @@ -1418,15 +1430,17 @@ static int fadump_region_show(struct seq_file *m, void *private) return 0; } -static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem, - 0200, NULL, - fadump_release_memory_store); -static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, - 0444, fadump_enabled_show, - NULL); -static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered, - 0644, fadump_register_show, - fadump_register_store); +static struct kobj_attribute release_attr = __ATTR_WO(release_mem); +static struct kobj_attribute enable_attr = __ATTR_RO(enabled); +static struct kobj_attribute register_attr = __ATTR_RW(registered); + +static struct attribute *fadump_attrs[] = { + &enable_attr.attr, + ®ister_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(fadump); DEFINE_SHOW_ATTRIBUTE(fadump_region); @@ -1435,16 +1449,11 @@ static void fadump_init_files(void) struct dentry *debugfs_file; int rc = 0; - rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr); - if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_enabled (%d)\n", rc); - - rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr); - if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_registered (%d)\n", rc); - + fadump_kobj = kobject_create_and_add("fadump", kernel_kobj); + if (!fadump_kobj) { + pr_err("failed to create fadump kobject\n"); + return; + } debugfs_file = debugfs_create_file("fadump_region", 0444, powerpc_debugfs_root, NULL, &fadump_region_fops); @@ -1453,10 +1462,52 @@ static void fadump_init_files(void) " fadump_region\n"); if (fw_dump.dump_active) { - rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); + rc = sysfs_create_file(fadump_kobj, &release_attr.attr); if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_release_mem (%d)\n", rc); + pr_err("unable to create release_mem sysfs file (%d)\n", + rc); + } + + rc = sysfs_create_groups(fadump_kobj, fadump_groups); + if (rc) { + pr_err("sysfs group creation failed (%d), unregistering FADump", + rc); + unregister_fadump(); + return; + } + + /* + * The FADump sysfs are moved from kernel_kobj to fadump_kobj need to + * create symlink at old location to maintain backward compatibility. + * + * - fadump_enabled -> fadump/enabled + * - fadump_registered -> fadump/registered + * - fadump_release_mem -> fadump/release_mem + */ + rc = compat_only_sysfs_link_entry_to_kobj(kernel_kobj, fadump_kobj, + "enabled", "fadump_enabled"); + if (rc) { + pr_err("unable to create fadump_enabled symlink (%d)", rc); + return; + } + + rc = compat_only_sysfs_link_entry_to_kobj(kernel_kobj, fadump_kobj, + "registered", + "fadump_registered"); + if (rc) { + pr_err("unable to create fadump_registered symlink (%d)", rc); + sysfs_remove_link(kernel_kobj, "fadump_enabled"); + return; + } + + if (fw_dump.dump_active) { + rc = compat_only_sysfs_link_entry_to_kobj(kernel_kobj, + fadump_kobj, + "release_mem", + "fadump_release_mem"); + if (rc) + pr_err("unable to create fadump_release_mem symlink (%d)", + rc); } return; } From 8852c07a881b0acfd3d75cf3927adaab815c4ee5 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:08 +0530 Subject: [PATCH 082/809] powerpc/powernv: Move core and fadump_release_opalcore under new kobject The /sys/firmware/opal/core and /sys/kernel/fadump_release_opalcore sysfs files are used to export and release the OPAL memory on PowerNV platform. let's organize them into a new kobject under /sys/firmware/opal/mpipl/ directory. A symlink is added to maintain the backward compatibility for /sys/firmware/opal/core sysfs file. Signed-off-by: Sourabh Jain Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-5-sourabhjain@linux.ibm.com --- .../sysfs-kernel-fadump_release_opalcore | 2 + .../powerpc/firmware-assisted-dump.rst | 15 +++-- arch/powerpc/platforms/powernv/opal-core.c | 55 ++++++++++++++----- 3 files changed, 51 insertions(+), 21 deletions(-) rename Documentation/ABI/{testing => removed}/sysfs-kernel-fadump_release_opalcore (82%) diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore b/Documentation/ABI/removed/sysfs-kernel-fadump_release_opalcore similarity index 82% rename from Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore rename to Documentation/ABI/removed/sysfs-kernel-fadump_release_opalcore index 53313c1d4e7a..a8d46cd0f4e6 100644 --- a/Documentation/ABI/testing/sysfs-kernel-fadump_release_opalcore +++ b/Documentation/ABI/removed/sysfs-kernel-fadump_release_opalcore @@ -1,3 +1,5 @@ +This ABI is moved to /sys/firmware/opal/mpipl/release_core. + What: /sys/kernel/fadump_release_opalcore Date: Sep 2019 Contact: linuxppc-dev@lists.ozlabs.org diff --git a/Documentation/powerpc/firmware-assisted-dump.rst b/Documentation/powerpc/firmware-assisted-dump.rst index 0455a78486d5..345a3405206e 100644 --- a/Documentation/powerpc/firmware-assisted-dump.rst +++ b/Documentation/powerpc/firmware-assisted-dump.rst @@ -112,13 +112,13 @@ to ensure that crash data is preserved to process later. -- On OPAL based machines (PowerNV), if the kernel is build with CONFIG_OPAL_CORE=y, OPAL memory at the time of crash is also - exported as /sys/firmware/opal/core file. This procfs file is + exported as /sys/firmware/opal/mpipl/core file. This procfs file is helpful in debugging OPAL crashes with GDB. The kernel memory used for exporting this procfs file can be released by echo'ing - '1' to /sys/kernel/fadump_release_opalcore node. + '1' to /sys/firmware/opal/mpipl/release_core node. e.g. - # echo 1 > /sys/kernel/fadump_release_opalcore + # echo 1 > /sys/firmware/opal/mpipl/release_core Implementation details: ----------------------- @@ -283,14 +283,17 @@ Here is the list of files under kernel sysfs: enhanced to use this interface to release the memory reserved for dump and continue without 2nd reboot. - /sys/kernel/fadump_release_opalcore +Note: /sys/kernel/fadump_release_opalcore sysfs has moved to + /sys/firmware/opal/mpipl/release_core + + /sys/firmware/opal/mpipl/release_core This file is available only on OPAL based machines when FADump is active during capture kernel. This is used to release the memory - used by the kernel to export /sys/firmware/opal/core file. To + used by the kernel to export /sys/firmware/opal/mpipl/core file. To release this memory, echo '1' to it: - echo 1 > /sys/kernel/fadump_release_opalcore + echo 1 > /sys/firmware/opal/mpipl/release_core Here is the list of files under powerpc debugfs: (Assuming debugfs is mounted on /sys/kernel/debug directory.) diff --git a/arch/powerpc/platforms/powernv/opal-core.c b/arch/powerpc/platforms/powernv/opal-core.c index ed895d82c048..6dba3b62269f 100644 --- a/arch/powerpc/platforms/powernv/opal-core.c +++ b/arch/powerpc/platforms/powernv/opal-core.c @@ -71,6 +71,7 @@ static LIST_HEAD(opalcore_list); static struct opalcore_config *oc_conf; static const struct opal_mpipl_fadump *opalc_metadata; static const struct opal_mpipl_fadump *opalc_cpu_metadata; +struct kobject *mpipl_kobj; /* * Set crashing CPU's signal to SIGUSR1. if the kernel is triggered @@ -428,7 +429,7 @@ static void opalcore_cleanup(void) return; /* Remove OPAL core sysfs file */ - sysfs_remove_bin_file(opal_kobj, &opal_core_attr); + sysfs_remove_bin_file(mpipl_kobj, &opal_core_attr); oc_conf->ptload_phdr = NULL; oc_conf->ptload_cnt = 0; @@ -563,9 +564,9 @@ error_out: of_node_put(np); } -static ssize_t fadump_release_opalcore_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) +static ssize_t release_core_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { int input = -1; @@ -589,9 +590,23 @@ static ssize_t fadump_release_opalcore_store(struct kobject *kobj, return count; } -static struct kobj_attribute opalcore_rel_attr = __ATTR(fadump_release_opalcore, - 0200, NULL, - fadump_release_opalcore_store); +static struct kobj_attribute opalcore_rel_attr = __ATTR_WO(release_core); + +static struct attribute *mpipl_attr[] = { + &opalcore_rel_attr.attr, + NULL, +}; + +static struct bin_attribute *mpipl_bin_attr[] = { + &opal_core_attr, + NULL, + +}; + +static struct attribute_group mpipl_group = { + .attrs = mpipl_attr, + .bin_attrs = mpipl_bin_attr, +}; static int __init opalcore_init(void) { @@ -609,7 +624,7 @@ static int __init opalcore_init(void) * then capture the dump. */ if (!(is_opalcore_usable())) { - pr_err("Failed to export /sys/firmware/opal/core\n"); + pr_err("Failed to export /sys/firmware/opal/mpipl/core\n"); opalcore_cleanup(); return rc; } @@ -617,18 +632,28 @@ static int __init opalcore_init(void) /* Set OPAL core file size */ opal_core_attr.size = oc_conf->opalcore_size; + mpipl_kobj = kobject_create_and_add("mpipl", opal_kobj); + if (!mpipl_kobj) { + pr_err("unable to create mpipl kobject\n"); + return -ENOMEM; + } + /* Export OPAL core sysfs file */ - rc = sysfs_create_bin_file(opal_kobj, &opal_core_attr); - if (rc != 0) { - pr_err("Failed to export /sys/firmware/opal/core\n"); + rc = sysfs_create_group(mpipl_kobj, &mpipl_group); + if (rc) { + pr_err("mpipl sysfs group creation failed (%d)", rc); opalcore_cleanup(); return rc; } - - rc = sysfs_create_file(kernel_kobj, &opalcore_rel_attr.attr); + /* The /sys/firmware/opal/core is moved to /sys/firmware/opal/mpipl/ + * directory, need to create symlink at old location to maintain + * backward compatibility. + */ + rc = compat_only_sysfs_link_entry_to_kobj(opal_kobj, mpipl_kobj, + "core", NULL); if (rc) { - pr_warn("unable to create sysfs file fadump_release_opalcore (%d)\n", - rc); + pr_err("unable to create core symlink (%d)\n", rc); + return rc; } return 0; From 3f5f1f22ef10ee0278cef1243944c93aca01b236 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:09 +0530 Subject: [PATCH 083/809] Documentation/ABI: Mark /sys/kernel/fadump_* sysfs files deprecated Add a deprecation note in FADump sysfs ABI documentation files and move them from ABI/testing to ABI/obsolete directory. Signed-off-by: Sourabh Jain [mpe: Use a proper table to fix errors from the documentation build] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-6-sourabhjain@linux.ibm.com --- .../sysfs-kernel-fadump_enabled | 2 ++ .../sysfs-kernel-fadump_registered | 2 ++ .../sysfs-kernel-fadump_release_mem | 2 ++ Documentation/powerpc/firmware-assisted-dump.rst | 12 ++++++++++++ 4 files changed, 18 insertions(+) rename Documentation/ABI/{testing => obsolete}/sysfs-kernel-fadump_enabled (73%) rename Documentation/ABI/{testing => obsolete}/sysfs-kernel-fadump_registered (77%) rename Documentation/ABI/{testing => obsolete}/sysfs-kernel-fadump_release_mem (78%) diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_enabled b/Documentation/ABI/obsolete/sysfs-kernel-fadump_enabled similarity index 73% rename from Documentation/ABI/testing/sysfs-kernel-fadump_enabled rename to Documentation/ABI/obsolete/sysfs-kernel-fadump_enabled index f73632b1c006..e9c2de8b3688 100644 --- a/Documentation/ABI/testing/sysfs-kernel-fadump_enabled +++ b/Documentation/ABI/obsolete/sysfs-kernel-fadump_enabled @@ -1,3 +1,5 @@ +This ABI is renamed and moved to a new location /sys/kernel/fadump/enabled. + What: /sys/kernel/fadump_enabled Date: Feb 2012 Contact: linuxppc-dev@lists.ozlabs.org diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_registered b/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered similarity index 77% rename from Documentation/ABI/testing/sysfs-kernel-fadump_registered rename to Documentation/ABI/obsolete/sysfs-kernel-fadump_registered index dcf925e53f0f..0360be39c98e 100644 --- a/Documentation/ABI/testing/sysfs-kernel-fadump_registered +++ b/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered @@ -1,3 +1,5 @@ +This ABI is renamed and moved to a new location /sys/kernel/fadump/registered.¬ + What: /sys/kernel/fadump_registered Date: Feb 2012 Contact: linuxppc-dev@lists.ozlabs.org diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump_release_mem b/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem similarity index 78% rename from Documentation/ABI/testing/sysfs-kernel-fadump_release_mem rename to Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem index 9c20d64ab48d..6ce0b129ab12 100644 --- a/Documentation/ABI/testing/sysfs-kernel-fadump_release_mem +++ b/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem @@ -1,3 +1,5 @@ +This ABI is renamed and moved to a new location /sys/kernel/fadump/release_mem.¬ + What: /sys/kernel/fadump_release_mem Date: Feb 2012 Contact: linuxppc-dev@lists.ozlabs.org diff --git a/Documentation/powerpc/firmware-assisted-dump.rst b/Documentation/powerpc/firmware-assisted-dump.rst index 345a3405206e..2cd65a0df9b8 100644 --- a/Documentation/powerpc/firmware-assisted-dump.rst +++ b/Documentation/powerpc/firmware-assisted-dump.rst @@ -295,6 +295,18 @@ Note: /sys/kernel/fadump_release_opalcore sysfs has moved to echo 1 > /sys/firmware/opal/mpipl/release_core +Note: The following FADump sysfs files are deprecated. + ++----------------------------------+--------------------------------+ +| Deprecated | Alternative | ++----------------------------------+--------------------------------+ +| /sys/kernel/fadump_enabled | /sys/kernel/fadump/enabled | ++----------------------------------+--------------------------------+ +| /sys/kernel/fadump_registered | /sys/kernel/fadump/registered | ++----------------------------------+--------------------------------+ +| /sys/kernel/fadump_release_mem | /sys/kernel/fadump/release_mem | ++----------------------------------+--------------------------------+ + Here is the list of files under powerpc debugfs: (Assuming debugfs is mounted on /sys/kernel/debug directory.) From d8e73458f33a24810413ee3a0cd020b644de2f98 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 11 Dec 2019 21:39:10 +0530 Subject: [PATCH 084/809] powerpc/fadump: sysfs for fadump memory reservation Add a sys interface to allow querying the memory reserved by FADump for saving the crash dump. Also added Documentation/ABI for the new sysfs file. Signed-off-by: Sourabh Jain Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191211160910.21656-7-sourabhjain@linux.ibm.com --- Documentation/ABI/testing/sysfs-kernel-fadump | 7 +++++++ Documentation/powerpc/firmware-assisted-dump.rst | 5 +++++ arch/powerpc/kernel/fadump.c | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-kernel-fadump b/Documentation/ABI/testing/sysfs-kernel-fadump index 5d988b919e81..8f7a64a81783 100644 --- a/Documentation/ABI/testing/sysfs-kernel-fadump +++ b/Documentation/ABI/testing/sysfs-kernel-fadump @@ -31,3 +31,10 @@ Description: write only the system is booted to capture the vmcore using FADump. It is used to release the memory reserved by FADump to save the crash dump. + +What: /sys/kernel/fadump/mem_reserved +Date: Dec 2019 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Provide information about the amount of memory reserved by + FADump to save the crash dump in bytes. diff --git a/Documentation/powerpc/firmware-assisted-dump.rst b/Documentation/powerpc/firmware-assisted-dump.rst index 2cd65a0df9b8..b3f3ee135dbe 100644 --- a/Documentation/powerpc/firmware-assisted-dump.rst +++ b/Documentation/powerpc/firmware-assisted-dump.rst @@ -268,6 +268,11 @@ Here is the list of files under kernel sysfs: be handled and vmcore will not be captured. This interface can be easily integrated with kdump service start/stop. + /sys/kernel/fadump/mem_reserved + + This is used to display the memory reserved by FADump for saving the + crash dump. + /sys/kernel/fadump_release_mem This file is available only when FADump is active during second kernel. This is used to release the reserved memory diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 1182ae44ef14..265b4aa72252 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1369,6 +1369,13 @@ static ssize_t enabled_show(struct kobject *kobj, return sprintf(buf, "%d\n", fw_dump.fadump_enabled); } +static ssize_t mem_reserved_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size); +} + static ssize_t registered_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -1433,10 +1440,12 @@ static int fadump_region_show(struct seq_file *m, void *private) static struct kobj_attribute release_attr = __ATTR_WO(release_mem); static struct kobj_attribute enable_attr = __ATTR_RO(enabled); static struct kobj_attribute register_attr = __ATTR_RW(registered); +static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved); static struct attribute *fadump_attrs[] = { &enable_attr.attr, ®ister_attr.attr, + &mem_reserved_attr.attr, NULL, }; From 030e347430957f6f7f29db9099368f8b86c0bf76 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 1 Feb 2020 08:04:31 +0000 Subject: [PATCH 085/809] powerpc/32s: Don't flush all TLBs when flushing one page When flushing any memory range, the flushing function flushes all TLBs. When (start) and (end - 1) are in the same memory page, flush that page instead. Signed-off-by: Christophe Leroy Reviewed-by: Segher Boessenkool Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/b30b2eae6960502eaf0d9e36c60820b839693c33.1580542939.git.christophe.leroy@c-s.fr --- arch/powerpc/mm/book3s32/tlb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c index 2fcd321040ff..724c0490fb17 100644 --- a/arch/powerpc/mm/book3s32/tlb.c +++ b/arch/powerpc/mm/book3s32/tlb.c @@ -79,11 +79,14 @@ static void flush_range(struct mm_struct *mm, unsigned long start, int count; unsigned int ctx = mm->context.id; + start &= PAGE_MASK; if (!Hash) { - _tlbia(); + if (end - start <= PAGE_SIZE) + _tlbie(start); + else + _tlbia(); return; } - start &= PAGE_MASK; if (start >= end) return; end = (end - 1) | ~PAGE_MASK; From 9e27086292aa880921a0f2b8501e5189d5efcf03 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 31 Jan 2020 11:34:54 +0000 Subject: [PATCH 086/809] powerpc/32: Warn and return ENOSYS on syscalls from kernel Since commit b86fb88855ea ("powerpc/32: implement fast entry for syscalls on non BOOKE") and commit 1a4b739bbb4f ("powerpc/32: implement fast entry for syscalls on BOOKE"), syscalls from kernel are unexpected and can have catastrophic consequences as it will destroy the kernel stack. Test MSR_PR on syscall entry. In case syscall is from kernel, emit a warning and return ENOSYS error. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/8ee3bdbbdfdfc64ca7001e90c43b2aee6f333578.1580470482.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/entry_32.S | 27 +++++++++++++++++++++++++++ arch/powerpc/kernel/head_32.h | 16 +++++++++------- arch/powerpc/kernel/head_booke.h | 5 ++++- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 0713daa651d9..ad000cbb5252 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -575,6 +575,33 @@ syscall_exit_work: bl do_syscall_trace_leave b ret_from_except_full + /* + * System call was called from kernel. We get here with SRR1 in r9. + * Mark the exception as recoverable once we have retrieved SRR0, + * trap a warning and return ENOSYS with CR[SO] set. + */ + .globl ret_from_kernel_syscall +ret_from_kernel_syscall: + mfspr r9, SPRN_SRR0 + mfspr r10, SPRN_SRR1 +#if !defined(CONFIG_4xx) && !defined(CONFIG_BOOKE) + LOAD_REG_IMMEDIATE(r11, MSR_KERNEL & ~(MSR_IR|MSR_DR)) + mtmsr r11 +#endif + +0: trap + EMIT_BUG_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING + + li r3, ENOSYS + crset so +#if defined(CONFIG_PPC_8xx) && defined(CONFIG_PERF_EVENTS) + mtspr SPRN_NRI, r0 +#endif + mtspr SPRN_SRR0, r9 + mtspr SPRN_SRR1, r10 + SYNC + RFI + /* * The fork/clone functions need to copy the full register set into * the child process. Therefore we need to save all the nonvolatile diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h index a6a5fbbf8504..0e7bf28fe53a 100644 --- a/arch/powerpc/kernel/head_32.h +++ b/arch/powerpc/kernel/head_32.h @@ -111,14 +111,16 @@ .macro SYSCALL_ENTRY trapno mfspr r12,SPRN_SPRG_THREAD + mfspr r9, SPRN_SRR1 #ifdef CONFIG_VMAP_STACK - mfspr r9, SPRN_SRR0 - mfspr r11, SPRN_SRR1 - stw r9, SRR0(r12) - stw r11, SRR1(r12) + mfspr r11, SPRN_SRR0 + stw r11, SRR0(r12) + stw r9, SRR1(r12) #endif mfcr r10 + andi. r11, r9, MSR_PR lwz r11,TASK_STACK-THREAD(r12) + beq- 99f rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */ addi r11, r11, THREAD_SIZE - INT_FRAME_SIZE #ifdef CONFIG_VMAP_STACK @@ -128,15 +130,14 @@ #endif tovirt_vmstack r12, r12 tophys_novmstack r11, r11 - mflr r9 stw r10,_CCR(r11) /* save registers */ - stw r9, _LINK(r11) + mflr r10 + stw r10, _LINK(r11) #ifdef CONFIG_VMAP_STACK lwz r10, SRR0(r12) lwz r9, SRR1(r12) #else mfspr r10,SPRN_SRR0 - mfspr r9,SPRN_SRR1 #endif stw r1,GPR1(r11) stw r1,0(r11) @@ -209,6 +210,7 @@ mtspr SPRN_SRR0,r11 SYNC RFI /* jump to handler, enable MMU */ +99: b ret_from_kernel_syscall .endm .macro save_dar_dsisr_on_stack reg1, reg2, sp diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index 37fc84ed90e3..bd2e5ed8dd50 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -104,16 +104,18 @@ FTR_SECTION_ELSE #ifdef CONFIG_KVM_BOOKE_HV ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV) #endif + mfspr r9, SPRN_SRR1 BOOKE_CLEAR_BTB(r11) + andi. r11, r9, MSR_PR lwz r11, TASK_STACK - THREAD(r10) rlwinm r12,r12,0,4,2 /* Clear SO bit in CR */ + beq- 99f ALLOC_STACK_FRAME(r11, THREAD_SIZE - INT_FRAME_SIZE) stw r12, _CCR(r11) /* save various registers */ mflr r12 stw r12,_LINK(r11) mfspr r12,SPRN_SRR0 stw r1, GPR1(r11) - mfspr r9,SPRN_SRR1 stw r1, 0(r11) mr r1, r11 stw r12,_NIP(r11) @@ -176,6 +178,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV) mtspr SPRN_SRR0,r11 SYNC RFI /* jump to handler, enable MMU */ +99: b ret_from_kernel_syscall .endm /* To handle the additional exception priority levels on 40x and Book-E From c06f0aff035ed5a7eaff5daa8e11e7ad28ab0d54 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 31 Jan 2020 11:34:55 +0000 Subject: [PATCH 087/809] powerpc: Don't use thread struct for saving SRR0/1 on syscall. CR0 can be saved later, and CTR can also be used for saving. Keep SRR1 in r9 and stash SRR0 in CTR, this avoids using thread_struct in memory for that. Saves 3 cycles (ie 1%) in null_syscall selftest on 8xx. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/b94c3bc03bac9431fec2dadb686384c481889422.1580470483.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/head_32.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h index 0e7bf28fe53a..4a1faeded069 100644 --- a/arch/powerpc/kernel/head_32.h +++ b/arch/powerpc/kernel/head_32.h @@ -114,28 +114,23 @@ mfspr r9, SPRN_SRR1 #ifdef CONFIG_VMAP_STACK mfspr r11, SPRN_SRR0 - stw r11, SRR0(r12) - stw r9, SRR1(r12) + mtctr r11 #endif - mfcr r10 andi. r11, r9, MSR_PR lwz r11,TASK_STACK-THREAD(r12) beq- 99f - rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */ addi r11, r11, THREAD_SIZE - INT_FRAME_SIZE #ifdef CONFIG_VMAP_STACK - li r9, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */ - mtmsr r9 + li r10, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */ + mtmsr r10 isync #endif tovirt_vmstack r12, r12 tophys_novmstack r11, r11 - stw r10,_CCR(r11) /* save registers */ mflr r10 stw r10, _LINK(r11) #ifdef CONFIG_VMAP_STACK - lwz r10, SRR0(r12) - lwz r9, SRR1(r12) + mfctr r10 #else mfspr r10,SPRN_SRR0 #endif @@ -143,6 +138,9 @@ stw r1,0(r11) tovirt_novmstack r1, r11 /* set new kernel sp */ stw r10,_NIP(r11) + mfcr r10 + rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */ + stw r10,_CCR(r11) /* save registers */ #ifdef CONFIG_40x rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */ #else From a83836dbc53e96f13fec248ecc201d18e1e3111d Mon Sep 17 00:00:00 2001 From: Libor Pechacek Date: Fri, 31 Jan 2020 14:28:29 +0100 Subject: [PATCH 088/809] powerpc/pseries: Avoid NULL pointer dereference when drmem is unavailable In guests without hotplugagble memory drmem structure is only zero initialized. Trying to manipulate DLPAR parameters results in a crash. $ echo "memory add count 1" > /sys/kernel/dlpar Oops: Kernel access of bad area, sig: 11 [#1] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries ... NIP: c0000000000ff294 LR: c0000000000ff248 CTR: 0000000000000000 REGS: c0000000fb9d3880 TRAP: 0300 Tainted: G E (5.5.0-rc6-2-default) MSR: 8000000000009033 CR: 28242428 XER: 20000000 CFAR: c0000000009a6c10 DAR: 0000000000000010 DSISR: 40000000 IRQMASK: 0 ... NIP dlpar_memory+0x6e4/0xd00 LR dlpar_memory+0x698/0xd00 Call Trace: dlpar_memory+0x698/0xd00 (unreliable) handle_dlpar_errorlog+0xc0/0x190 dlpar_store+0x198/0x4a0 kobj_attr_store+0x30/0x50 sysfs_kf_write+0x64/0x90 kernfs_fop_write+0x1b0/0x290 __vfs_write+0x3c/0x70 vfs_write+0xd0/0x260 ksys_write+0xdc/0x130 system_call+0x5c/0x68 Taking closer look at the code, I can see that for_each_drmem_lmb is a macro expanding into `for (lmb = &drmem_info->lmbs[0]; lmb <= &drmem_info->lmbs[drmem_info->n_lmbs - 1]; lmb++)`. When drmem_info->lmbs is NULL, the loop would iterate through the whole address range if it weren't stopped by the NULL pointer dereference on the next line. This patch aligns for_each_drmem_lmb and for_each_drmem_lmb_in_range macro behavior with the common C semantics, where the end marker does not belong to the scanned range, and alters get_lmb_range() semantics. As a side effect, the wraparound observed in the crash is prevented. Fixes: 6c6ea53725b3 ("powerpc/mm: Separate ibm, dynamic-memory data from DT format") Cc: stable@vger.kernel.org # v4.16+ Signed-off-by: Libor Pechacek Signed-off-by: Michal Suchanek Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200131132829.10281-1-msuchanek@suse.de --- arch/powerpc/include/asm/drmem.h | 4 ++-- arch/powerpc/platforms/pseries/hotplug-memory.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/drmem.h b/arch/powerpc/include/asm/drmem.h index 3d76e1c388c2..28c3d936fdf3 100644 --- a/arch/powerpc/include/asm/drmem.h +++ b/arch/powerpc/include/asm/drmem.h @@ -27,12 +27,12 @@ struct drmem_lmb_info { extern struct drmem_lmb_info *drmem_info; #define for_each_drmem_lmb_in_range(lmb, start, end) \ - for ((lmb) = (start); (lmb) <= (end); (lmb)++) + for ((lmb) = (start); (lmb) < (end); (lmb)++) #define for_each_drmem_lmb(lmb) \ for_each_drmem_lmb_in_range((lmb), \ &drmem_info->lmbs[0], \ - &drmem_info->lmbs[drmem_info->n_lmbs - 1]) + &drmem_info->lmbs[drmem_info->n_lmbs]) /* * The of_drconf_cell_v1 struct defines the layout of the LMB data diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index a4d40a3ceea3..fd22ec41c008 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -223,7 +223,7 @@ static int get_lmb_range(u32 drc_index, int n_lmbs, struct drmem_lmb **end_lmb) { struct drmem_lmb *lmb, *start, *end; - struct drmem_lmb *last_lmb; + struct drmem_lmb *limit; start = NULL; for_each_drmem_lmb(lmb) { @@ -236,10 +236,10 @@ static int get_lmb_range(u32 drc_index, int n_lmbs, if (!start) return -EINVAL; - end = &start[n_lmbs - 1]; + end = &start[n_lmbs]; - last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1]; - if (end > last_lmb) + limit = &drmem_info->lmbs[drmem_info->n_lmbs]; + if (end > limit) return -EINVAL; *start_lmb = start; From e1347a020b81fe47c80cd277bfaa61295a9482a4 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 3 Feb 2020 16:47:37 +0000 Subject: [PATCH 089/809] powerpc/32s: Slenderize _tlbia() for powerpc 603/603e _tlbia() is a function used only on 603/603e core, ie on CPUs which don't have a hash table. _tlbia() uses the tlbia macro which implements a loop of 1024 tlbie. On the 603/603e core, flushing the entire TLB requires no more than 32 tlbie. Replace tlbia by a loop of 32 tlbie. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/12f4f4f0ff89aeab3b937fc96c84fb35e1b2517e.1580748445.git.christophe.leroy@c-s.fr --- arch/powerpc/mm/book3s32/hash_low.S | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/book3s32/hash_low.S b/arch/powerpc/mm/book3s32/hash_low.S index c11b0a005196..a5039ad10429 100644 --- a/arch/powerpc/mm/book3s32/hash_low.S +++ b/arch/powerpc/mm/book3s32/hash_low.S @@ -696,18 +696,21 @@ _GLOBAL(_tlbia) bne- 10b stwcx. r8,0,r9 bne- 10b +#endif /* CONFIG_SMP */ + li r5, 32 + lis r4, KERNELBASE@h + mtctr r5 sync - tlbia +0: tlbie r4 + addi r4, r4, 0x1000 + bdnz 0b sync +#ifdef CONFIG_SMP TLBSYNC li r0,0 stw r0,0(r9) /* clear mmu_hash_lock */ mtmsr r10 SYNC_601 isync -#else /* CONFIG_SMP */ - sync - tlbia - sync #endif /* CONFIG_SMP */ blr From dd62abd2d84d8fe09c644a7407a34c22cb3d43be Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 10 Feb 2020 14:56:41 +0100 Subject: [PATCH 090/809] s390/qdio: clean up cdev access in qdio_setup_irq() Some parts use init_data->cdev, others use irq_ptr->cdev. In the end it's all the same, but unnecessarily confusing. Use a single reference instead. Signed-off-by: Julian Wiedmann Reviewed-by: Steffen Maier Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio_setup.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 3ab8e80d7bbc..36890ed68083 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -453,7 +453,8 @@ static void setup_qib(struct qdio_irq *irq_ptr, int qdio_setup_irq(struct qdio_initialize *init_data) { struct ciw *ciw; - struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data; + struct ccw_device *cdev = init_data->cdev; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); @@ -470,9 +471,9 @@ int qdio_setup_irq(struct qdio_initialize *init_data) irq_ptr->int_parm = init_data->int_parm; irq_ptr->nr_input_qs = init_data->no_input_qs; irq_ptr->nr_output_qs = init_data->no_output_qs; - irq_ptr->cdev = init_data->cdev; + irq_ptr->cdev = cdev; irq_ptr->scan_threshold = init_data->scan_threshold; - ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid); + ccw_device_get_schid(cdev, &irq_ptr->schid); setup_queues(irq_ptr, init_data); setup_qib(irq_ptr, init_data); @@ -488,14 +489,14 @@ int qdio_setup_irq(struct qdio_initialize *init_data) /* qdr, qib, sls, slsbs, slibs, sbales are filled now */ /* get qdio commands */ - ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_EQUEUE); if (!ciw) { DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); return -EINVAL; } irq_ptr->equeue = *ciw; - ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_AQUEUE); if (!ciw) { DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); return -EINVAL; @@ -503,10 +504,10 @@ int qdio_setup_irq(struct qdio_initialize *init_data) irq_ptr->aqueue = *ciw; /* set new interrupt handler */ - spin_lock_irq(get_ccwdev_lock(irq_ptr->cdev)); - irq_ptr->orig_handler = init_data->cdev->handler; - init_data->cdev->handler = qdio_int_handler; - spin_unlock_irq(get_ccwdev_lock(irq_ptr->cdev)); + spin_lock_irq(get_ccwdev_lock(cdev)); + irq_ptr->orig_handler = cdev->handler; + cdev->handler = qdio_int_handler; + spin_unlock_irq(get_ccwdev_lock(cdev)); return 0; } From 014816b66218d9f5f90e6d92951abc9d3749b4cd Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 10 Feb 2020 14:58:07 +0100 Subject: [PATCH 091/809] s390/qdio: reduce access to cdev->private->qdio_data Remove all usage of cdev->private->qdio_data that's buried deep in internal code. This should only be used by the exported driver API, which can then pass around a proper qdio_irq pointer. Also trivially merge some initializations with their definitions. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio.h | 2 +- drivers/s390/cio/qdio_main.c | 13 +++++-------- drivers/s390/cio/qdio_setup.c | 3 +-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index ff74eb5fce50..85d530927e4e 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -392,7 +392,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, struct subchannel_id *schid, struct qdio_ssqd_desc *data); -int qdio_setup_irq(struct qdio_initialize *init_data); +int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_release_memory(struct qdio_irq *irq_ptr); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3475317c42e5..2886b95f4741 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1105,9 +1105,8 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); -static void qdio_shutdown_queues(struct ccw_device *cdev) +static void qdio_shutdown_queues(struct qdio_irq *irq_ptr) { - struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct qdio_q *q; int i; @@ -1155,7 +1154,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how) qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); tiqdio_remove_device(irq_ptr); - qdio_shutdown_queues(cdev); + qdio_shutdown_queues(irq_ptr); qdio_shutdown_debug_entries(irq_ptr); /* cleanup subchannel */ @@ -1316,19 +1315,18 @@ static void qdio_detect_hsicq(struct qdio_irq *irq_ptr) int qdio_establish(struct qdio_initialize *init_data) { struct ccw_device *cdev = init_data->cdev; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; - struct qdio_irq *irq_ptr; int rc; ccw_device_get_schid(cdev, &schid); DBF_EVENT("qestablish:%4x", schid.sch_no); - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; mutex_lock(&irq_ptr->setup_mutex); - qdio_setup_irq(init_data); + qdio_setup_irq(irq_ptr, init_data); rc = qdio_establish_thinint(irq_ptr); if (rc) { @@ -1386,14 +1384,13 @@ EXPORT_SYMBOL_GPL(qdio_establish); */ int qdio_activate(struct ccw_device *cdev) { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; - struct qdio_irq *irq_ptr; int rc; ccw_device_get_schid(cdev, &schid); DBF_EVENT("qactivate:%4x", schid.sch_no); - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 36890ed68083..c56ff92c6e0c 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -450,11 +450,10 @@ static void setup_qib(struct qdio_irq *irq_ptr, memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8); } -int qdio_setup_irq(struct qdio_initialize *init_data) +int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) { struct ciw *ciw; struct ccw_device *cdev = init_data->cdev; - struct qdio_irq *irq_ptr = cdev->private->qdio_data; memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); From b059a39cfa27c04e8e03e4ddf44f16501f36357d Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Mon, 20 Jan 2020 13:10:37 +0100 Subject: [PATCH 092/809] s390/arch: install kernels with their proper version ID In case $INSTALLKERNEL is not available, we should install the kernel image with its version number, and save the previous one accordingly. Also, we're adding a hint so users know that they still need to perform one more configuration step (usually adjusting zipl config). Signed-off-by: Stefan Raspl Signed-off-by: Vasily Gorbik --- arch/s390/boot/install.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/arch/s390/boot/install.sh b/arch/s390/boot/install.sh index bed227f267ae..515b27a996b3 100644 --- a/arch/s390/boot/install.sh +++ b/arch/s390/boot/install.sh @@ -21,15 +21,10 @@ if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi -# Default install - same as make zlilo +echo "Warning: '${INSTALLKERNEL}' command not available - additional " \ + "bootloader config required" >&2 +if [ -f $4/vmlinuz-$1 ]; then mv $4/vmlinuz-$1 $4/vmlinuz-$1.old; fi +if [ -f $4/System.map-$1 ]; then mv $4/System.map-$1 $4/System.map-$1.old; fi -if [ -f $4/vmlinuz ]; then - mv $4/vmlinuz $4/vmlinuz.old -fi - -if [ -f $4/System.map ]; then - mv $4/System.map $4/System.old -fi - -cat $2 > $4/vmlinuz -cp $3 $4/System.map +cat $2 > $4/vmlinuz-$1 +cp $3 $4/System.map-$1 From a18c8e0b76979881f3b31e96c398e62ab30a1662 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 19 Feb 2020 09:49:28 +0100 Subject: [PATCH 093/809] clk: meson: g12a: add support for the SPICC SCLK Source clocks This adds the clocks used for the Amlogic G12A and compatible SoCs SPICC controller to provide a more complete range of frequencies instead of the SPICC internal divider over Xtal. Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/g12a.c | 129 +++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/g12a.h | 6 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index d2760a021301..fad616cac01e 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -3862,6 +3862,111 @@ static struct clk_regmap g12a_ts = { }, }; +/* SPICC SCLK source clock */ + +static const struct clk_parent_data spicc_sclk_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_clk81.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12a_spicc0_sclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SPICC_CLK_CNTL, + .mask = 7, + .shift = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = spicc_sclk_parent_data, + .num_parents = ARRAY_SIZE(spicc_sclk_parent_data), + }, +}; + +static struct clk_regmap g12a_spicc0_sclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SPICC_CLK_CNTL, + .shift = 0, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc0_sclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc0_sclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SPICC_CLK_CNTL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc0_sclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc1_sclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SPICC_CLK_CNTL, + .mask = 7, + .shift = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = spicc_sclk_parent_data, + .num_parents = ARRAY_SIZE(spicc_sclk_parent_data), + }, +}; + +static struct clk_regmap g12a_spicc1_sclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SPICC_CLK_CNTL, + .shift = 16, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc1_sclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc1_sclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SPICC_CLK_CNTL, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc1_sclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + #define MESON_GATE(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) @@ -4159,6 +4264,12 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, [CLKID_TS_DIV] = &g12a_ts_div.hw, [CLKID_TS] = &g12a_ts.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4408,6 +4519,12 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = { [CLKID_CPUB_CLK_AXI] = &g12b_cpub_clk_axi.hw, [CLKID_CPUB_CLK_TRACE_SEL] = &g12b_cpub_clk_trace_sel.hw, [CLKID_CPUB_CLK_TRACE] = &g12b_cpub_clk_trace.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4642,6 +4759,12 @@ static struct clk_hw_onecell_data sm1_hw_onecell_data = { [CLKID_CPU1_CLK] = &sm1_cpu1_clk.hw, [CLKID_CPU2_CLK] = &sm1_cpu2_clk.hw, [CLKID_CPU3_CLK] = &sm1_cpu3_clk.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4877,6 +5000,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &sm1_cpu1_clk, &sm1_cpu2_clk, &sm1_cpu3_clk, + &g12a_spicc0_sclk_sel, + &g12a_spicc0_sclk_div, + &g12a_spicc0_sclk, + &g12a_spicc1_sclk_sel, + &g12a_spicc1_sclk_div, + &g12a_spicc1_sclk, }; static const struct reg_sequence g12a_init_regs[] = { diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index 9df4068aced1..a8852556836e 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -255,8 +255,12 @@ #define CLKID_DSU_CLK_DYN1 249 #define CLKID_DSU_CLK_DYN 250 #define CLKID_DSU_CLK_FINAL 251 +#define CLKID_SPICC0_SCLK_SEL 256 +#define CLKID_SPICC0_SCLK_DIV 257 +#define CLKID_SPICC1_SCLK_SEL 259 +#define CLKID_SPICC1_SCLK_DIV 260 -#define NR_CLKS 256 +#define NR_CLKS 262 /* include the CLKIDs that have been made part of the DT binding */ #include From b36368f685d66a53da73a05b63af32233e32cf36 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Sun, 9 Feb 2020 15:26:00 +0530 Subject: [PATCH 094/809] gpio: rcar: Fix typo in comment "Positive" is spelled incorrectly as "Postive" in comment fix this. Signed-off-by: Ashish Chavan Link: https://lore.kernel.org/r/20200209095600.16394-1-ashish.gschavan@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index f800b250971c..7284473c9fe3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -116,7 +116,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, spin_lock_irqsave(&p->lock, flags); - /* Configure postive or negative logic in POSNEG */ + /* Configure positive or negative logic in POSNEG */ gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge); /* Configure edge or level trigger in EDGLEVEL */ @@ -228,7 +228,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, spin_lock_irqsave(&p->lock, flags); - /* Configure postive logic in POSNEG */ + /* Configure positive logic in POSNEG */ gpio_rcar_modify_bit(p, POSNEG, gpio, false); /* Select "General Input/Output Mode" in IOINTSEL */ From f6e51bb331d51d4b08fe9b766c5ed442f889c853 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 10 Feb 2020 16:50:59 +0100 Subject: [PATCH 095/809] gpio: mockup: coding-style fix The indentation is wrong in gpio_mockup_apply_pull(). This patch makes the code more readable. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200210155059.29609-1-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 7d343bea784a..3eb94f3740d1 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -171,7 +171,7 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, /* Change the value unless we're actively driving the line. */ if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) + !test_bit(FLAG_IS_OUT, &desc->flags)) __gpio_mockup_set(chip, offset, value); out: From 71202c412478d6553281726a6772d0d5510c42fb Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Thu, 20 Feb 2020 21:44:33 +0100 Subject: [PATCH 096/809] clk: meson: meson8b: set audio output clock hierarchy The aiu devices peripheral clocks needs the aiu and aiu_glue clocks to operate. Reflect this hierarchy in the clock tree. Fixes: e31a1900c1ff73 ("meson: clk: Add support for clock gates") Suggested-by: Jerome Brunet Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson8b.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 9fd31f23b2a9..34a70c4b4899 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -2605,14 +2605,6 @@ static MESON_GATE(meson8b_spi, HHI_GCLK_MPEG0, 30); static MESON_GATE(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); static MESON_GATE(meson8b_eth, HHI_GCLK_MPEG1, 3); static MESON_GATE(meson8b_demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6); -static MESON_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7); -static MESON_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9); -static MESON_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10); -static MESON_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11); -static MESON_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13); static MESON_GATE(meson8b_blkmv, HHI_GCLK_MPEG1, 14); static MESON_GATE(meson8b_aiu, HHI_GCLK_MPEG1, 15); static MESON_GATE(meson8b_uart1, HHI_GCLK_MPEG1, 16); @@ -2659,6 +2651,19 @@ static MESON_GATE(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); static MESON_GATE(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); static MESON_GATE(meson8b_edp, HHI_GCLK_OTHER, 31); +/* AIU gates */ +#define MESON_AIU_GLUE_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw) + +static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw); +static MESON_AIU_GLUE_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7); +static MESON_AIU_GLUE_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_AIU_GLUE_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9); +static MESON_AIU_GLUE_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_AIU_GLUE_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11); +static MESON_AIU_GLUE_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_AIU_GLUE_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13); + /* Always On (AO) domain gates */ static MESON_GATE(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); From 068e7f85234c0b56f55cc0259ad9c05f2c64b8fb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 18 Feb 2020 12:25:25 +0100 Subject: [PATCH 097/809] clk: renesas: Remove use of ARCH_R8A7795 CONFIG_ARCH_R8A7795 was split in CONFIG_ARCH_R8A77950 and CONFIG_ARCH_R8A77951 in commit b925adfceb529389 ("soc: renesas: Add ARCH_R8A7795[01] for existing R-Car H3"), so its users can be removed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200218112525.5834-1-geert+renesas@glider.be --- drivers/clk/renesas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 250d8165167a..879d96ead06b 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -20,7 +20,7 @@ config CLK_RENESAS select CLK_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793 select CLK_R8A7792 if ARCH_R8A7792 select CLK_R8A7794 if ARCH_R8A7794 - select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951 || ARCH_R8A7795 + select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951 select CLK_R8A77960 if ARCH_R8A77960 select CLK_R8A77961 if ARCH_R8A77961 select CLK_R8A77965 if ARCH_R8A77965 From 023892ec80f0efcffe22045e92bb89f3f1480f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 11 Feb 2020 14:51:21 +0100 Subject: [PATCH 098/809] gpio: siox: use raw spinlock for irq related locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the irq related callbacks are called with the (raw) spinlock desc->lock being held. So the lock here must be raw as well. Also irqs were already disabled by the caller for the irq chip callbacks, so the non-irq variants of spin_lock must be used there. Fixes: be8c8facc707 ("gpio: new driver to work with a 8x12 siox") Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20200211135121.15752-1-uwe@kleine-koenig.org Signed-off-by: Linus Walleij --- drivers/gpio/gpio-siox.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c index 311f66757b92..26e1fe092304 100644 --- a/drivers/gpio/gpio-siox.c +++ b/drivers/gpio/gpio-siox.c @@ -15,7 +15,7 @@ struct gpio_siox_ddata { u8 setdata[1]; u8 getdata[3]; - spinlock_t irqlock; + raw_spinlock_t irqlock; u32 irq_enable; u32 irq_status; u32 irq_type[20]; @@ -44,7 +44,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) mutex_lock(&ddata->lock); - spin_lock_irq(&ddata->irqlock); + raw_spin_lock_irq(&ddata->irqlock); for (offset = 0; offset < 12; ++offset) { unsigned int bitpos = 11 - offset; @@ -66,7 +66,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) trigger = ddata->irq_status & ddata->irq_enable; - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock_irq(&ddata->irqlock); ddata->getdata[0] = buf[0]; ddata->getdata[1] = buf[1]; @@ -84,9 +84,9 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) * handler of the irq chip. But it doesn't, so we have * to clean the irq_status here. */ - spin_lock_irq(&ddata->irqlock); + raw_spin_lock_irq(&ddata->irqlock); ddata->irq_status &= ~(1 << offset); - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock_irq(&ddata->irqlock); handle_nested_irq(irq); } @@ -101,9 +101,9 @@ static void gpio_siox_irq_ack(struct irq_data *d) struct gpio_siox_ddata *ddata = container_of(ic, struct gpio_siox_ddata, ichip); - spin_lock_irq(&ddata->irqlock); + raw_spin_lock(&ddata->irqlock); ddata->irq_status &= ~(1 << d->hwirq); - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock(&ddata->irqlock); } static void gpio_siox_irq_mask(struct irq_data *d) @@ -112,9 +112,9 @@ static void gpio_siox_irq_mask(struct irq_data *d) struct gpio_siox_ddata *ddata = container_of(ic, struct gpio_siox_ddata, ichip); - spin_lock_irq(&ddata->irqlock); + raw_spin_lock(&ddata->irqlock); ddata->irq_enable &= ~(1 << d->hwirq); - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock(&ddata->irqlock); } static void gpio_siox_irq_unmask(struct irq_data *d) @@ -123,9 +123,9 @@ static void gpio_siox_irq_unmask(struct irq_data *d) struct gpio_siox_ddata *ddata = container_of(ic, struct gpio_siox_ddata, ichip); - spin_lock_irq(&ddata->irqlock); + raw_spin_lock(&ddata->irqlock); ddata->irq_enable |= 1 << d->hwirq; - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock(&ddata->irqlock); } static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) @@ -134,9 +134,9 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) struct gpio_siox_ddata *ddata = container_of(ic, struct gpio_siox_ddata, ichip); - spin_lock_irq(&ddata->irqlock); + raw_spin_lock(&ddata->irqlock); ddata->irq_type[d->hwirq] = type; - spin_unlock_irq(&ddata->irqlock); + raw_spin_unlock(&ddata->irqlock); return 0; } @@ -222,7 +222,7 @@ static int gpio_siox_probe(struct siox_device *sdevice) dev_set_drvdata(dev, ddata); mutex_init(&ddata->lock); - spin_lock_init(&ddata->irqlock); + raw_spin_lock_init(&ddata->irqlock); ddata->gchip.base = -1; ddata->gchip.can_sleep = 1; From 1739a2d852265977836152be43073ead5c64d1ea Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 19 Feb 2020 10:47:02 +0100 Subject: [PATCH 099/809] gpiolib: use gpiochip_get_desc() where applicable Whenever retrieving a descriptor from a gpiochip: use the provided helper which checks for errors. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200219094702.6463-1-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f73077f26eff..611709fd560f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3143,7 +3143,9 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) if (offset >= chip->ngpio) return NULL; - desc = &chip->gpiodev->descs[offset]; + desc = gpiochip_get_desc(chip, offset); + if (IS_ERR(desc)) + return NULL; if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) return NULL; From f8850206e160bfe35de9ca2e726ab6d6b8cb77dd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 20 Feb 2020 15:56:24 +0100 Subject: [PATCH 100/809] gpio: Switch timestamps to ktime_get_ns() The existing use of ktime_get_real_ns() in the timestamps from the GPIO events is dubious. We have had several discussions about this timestamp, and it is unclear whether userspace has ever taken into account that a timestamp from ktime_get_real_ns() can actually move backwards in time relative the previous timetamp, and userspace is more likely to expect a monotonic counter. Background: https://lore.kernel.org/linux-gpio/CAK8P3a1Skvm48sje8FNDPLYqyz9Lf8q0qX1QETWtyZTxuX4k1g@mail.gmail.com/ https://marc.info/?l=linux-gpio&m=151661955709074&w=2 The change is ABI incompatible, but incompatible in a way that is IMO more likely to fix future bugs rather than break current userspace. To the best of my knowledge all userspace expects a monotonic timestamp and users are just lucky that they very seldom move backwards in time. Cc: Arnd Bergmann Acked-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 611709fd560f..2c3a9c1c76be 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -954,7 +954,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) * we didn't get the timestamp from lineevent_irq_handler(). */ if (!le->timestamp) - ge.timestamp = ktime_get_real_ns(); + ge.timestamp = ktime_get_ns(); else ge.timestamp = le->timestamp; @@ -995,7 +995,7 @@ static irqreturn_t lineevent_irq_handler(int irq, void *p) * Just store the timestamp in hardirq context so we get it as * close in time as possible to the actual event. */ - le->timestamp = ktime_get_real_ns(); + le->timestamp = ktime_get_ns(); return IRQ_WAKE_THREAD; } From bc21077e084b80c22072a40d32beb24ea33938ec Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2020 14:01:48 +0100 Subject: [PATCH 101/809] gpio: of: Extract of_gpiochip_add_hog() Extract the code to add all GPIO hogs of a gpio-hog node into its own function, so it can be reused. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200220130149.26283-2-geert+renesas@glider.be Reviewed-by: Frank Rowand Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 49 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index c6d30f73df07..2b47f9388607 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -604,6 +604,35 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, return desc; } +/** + * of_gpiochip_add_hog - Add all hogs in a hog device node + * @chip: gpio chip to act on + * @hog: device node describing the hogs + * + * Returns error if it fails otherwise 0 on success. + */ +static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog) +{ + enum gpiod_flags dflags; + struct gpio_desc *desc; + unsigned long lflags; + const char *name; + unsigned int i; + int ret; + + for (i = 0;; i++) { + desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags); + if (IS_ERR(desc)) + break; + + ret = gpiod_hog(desc, name, lflags, dflags); + if (ret < 0) + return ret; + } + + return 0; +} + /** * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * @chip: gpio chip to act on @@ -614,29 +643,17 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, */ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) { - struct gpio_desc *desc = NULL; struct device_node *np; - const char *name; - unsigned long lflags; - enum gpiod_flags dflags; - unsigned int i; int ret; for_each_available_child_of_node(chip->of_node, np) { if (!of_property_read_bool(np, "gpio-hog")) continue; - for (i = 0;; i++) { - desc = of_parse_own_gpio(np, chip, i, &name, &lflags, - &dflags); - if (IS_ERR(desc)) - break; - - ret = gpiod_hog(desc, name, lflags, dflags); - if (ret < 0) { - of_node_put(np); - return ret; - } + ret = of_gpiochip_add_hog(chip, np); + if (ret < 0) { + of_node_put(np); + return ret; } } From 63636d956c455c0fbe2118078a03f563ddd6bf6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2020 14:01:49 +0100 Subject: [PATCH 102/809] gpio: of: Add DT overlay support for GPIO hogs As GPIO hogs are configured at GPIO controller initialization time, adding/removing GPIO hogs in DT overlays does not work. Add support for GPIO hogs described in DT overlays by registering an OF reconfiguration notifier, to handle the addition and removal of GPIO hog subnodes to/from a GPIO controller device node. Note that when a GPIO hog device node is being removed, its "gpios" properties is no longer available, so we have to keep track of which node a hog belongs to, which is done by adding a pointer to the hog's device node to struct gpio_desc. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200220130149.26283-3-geert+renesas@glider.be Reviewed-by: Frank Rowand Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 90 +++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib-of.h | 2 + drivers/gpio/gpiolib.c | 14 ++++-- drivers/gpio/gpiolib.h | 3 ++ 4 files changed, 106 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 2b47f9388607..ccc449df3792 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -628,6 +628,10 @@ static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog) ret = gpiod_hog(desc, name, lflags, dflags); if (ret < 0) return ret; + +#ifdef CONFIG_OF_DYNAMIC + desc->hog = hog; +#endif } return 0; @@ -655,11 +659,97 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) of_node_put(np); return ret; } + + of_node_set_flag(np, OF_POPULATED); } return 0; } +#ifdef CONFIG_OF_DYNAMIC +/** + * of_gpiochip_remove_hog - Remove all hogs in a hog device node + * @chip: gpio chip to act on + * @hog: device node describing the hogs + */ +static void of_gpiochip_remove_hog(struct gpio_chip *chip, + struct device_node *hog) +{ + struct gpio_desc *descs = chip->gpiodev->descs; + unsigned int i; + + for (i = 0; i < chip->ngpio; i++) { + if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) && + descs[i].hog == hog) + gpiochip_free_own_desc(&descs[i]); + } +} + +static int of_gpiochip_match_node(struct gpio_chip *chip, void *data) +{ + return chip->gpiodev->dev.of_node == data; +} + +static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np) +{ + return gpiochip_find(np, of_gpiochip_match_node); +} + +static int of_gpio_notify(struct notifier_block *nb, unsigned long action, + void *arg) +{ + struct of_reconfig_data *rd = arg; + struct gpio_chip *chip; + int ret; + + /* + * This only supports adding and removing complete gpio-hog nodes. + * Modifying an existing gpio-hog node is not supported (except for + * changing its "status" property, which is treated the same as + * addition/removal). + */ + switch (of_reconfig_get_state_change(action, arg)) { + case OF_RECONFIG_CHANGE_ADD: + if (!of_property_read_bool(rd->dn, "gpio-hog")) + return NOTIFY_OK; /* not for us */ + + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + + chip = of_find_gpiochip_by_node(rd->dn->parent); + if (chip == NULL) + return NOTIFY_OK; /* not for us */ + + ret = of_gpiochip_add_hog(chip, rd->dn); + if (ret < 0) { + pr_err("%s: failed to add hogs for %pOF\n", __func__, + rd->dn); + of_node_clear_flag(rd->dn, OF_POPULATED); + return notifier_from_errno(ret); + } + break; + + case OF_RECONFIG_CHANGE_REMOVE: + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; /* already depopulated */ + + chip = of_find_gpiochip_by_node(rd->dn->parent); + if (chip == NULL) + return NOTIFY_OK; /* not for us */ + + of_gpiochip_remove_hog(chip, rd->dn); + of_node_clear_flag(rd->dn, OF_POPULATED); + break; + } + + return NOTIFY_OK; +} + +struct notifier_block gpio_of_notifier = { + .notifier_call = of_gpio_notify, +}; +#endif /* CONFIG_OF_DYNAMIC */ + /** * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags * @gc: pointer to the gpio_chip structure diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h index 9768831b1fe2..ed26664f1537 100644 --- a/drivers/gpio/gpiolib-of.h +++ b/drivers/gpio/gpiolib-of.h @@ -35,4 +35,6 @@ static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc) } #endif /* CONFIG_OF_GPIO */ +extern struct notifier_block gpio_of_notifier; + #endif /* GPIOLIB_OF_H */ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2c3a9c1c76be..9ad86477af9c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3103,6 +3103,9 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_PULL_DOWN, &desc->flags); clear_bit(FLAG_BIAS_DISABLE, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); +#ifdef CONFIG_OF_DYNAMIC + desc->hog = NULL; +#endif ret = true; } @@ -5281,10 +5284,15 @@ static int __init gpiolib_dev_init(void) if (ret < 0) { pr_err("gpiolib: failed to allocate char dev region\n"); bus_unregister(&gpio_bus_type); - } else { - gpiolib_initialized = true; - gpiochip_setup_devs(); + return ret; } + + gpiolib_initialized = true; + gpiochip_setup_devs(); + + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_register(&gpio_of_notifier)); + return ret; } core_initcall(gpiolib_dev_init); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 5ab90746b519..853ce681b4a4 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -120,6 +120,9 @@ struct gpio_desc { const char *label; /* Name of the GPIO */ const char *name; +#ifdef CONFIG_OF_DYNAMIC + struct device_node *hog; +#endif }; int gpiod_request(struct gpio_desc *desc, const char *label); From c267bd443f38972ab4ad29976f15f5eee9ed6f45 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 19 Feb 2020 14:04:09 +0800 Subject: [PATCH 103/809] clk: imx8mp: Rename the IMX8MP_CLK_HDMI_27M clock On i.MX8MP, internal HDMI 27M clock is actually 24MHz, so rename the IMX8MP_CLK_HDMI_27M to IMX8MP_CLK_HDMI_24M. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 4 ++-- include/dt-bindings/clock/imx8mp-clock.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 3adc8aa46200..a6313cf4a30c 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -342,7 +342,7 @@ static const char * const imx8mp_hdmi_fdcc_tst_sels[] = {"osc_24m", "sys_pll1_26 "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", }; -static const char * const imx8mp_hdmi_27m_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", +static const char * const imx8mp_hdmi_24m_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; @@ -632,7 +632,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_IPP_DO_CLKO1] = imx8m_clk_hw_composite("ipp_do_clko1", imx8mp_ipp_do_clko1_sels, ccm_base + 0xba00); hws[IMX8MP_CLK_IPP_DO_CLKO2] = imx8m_clk_hw_composite("ipp_do_clko2", imx8mp_ipp_do_clko2_sels, ccm_base + 0xba80); hws[IMX8MP_CLK_HDMI_FDCC_TST] = imx8m_clk_hw_composite("hdmi_fdcc_tst", imx8mp_hdmi_fdcc_tst_sels, ccm_base + 0xbb00); - hws[IMX8MP_CLK_HDMI_27M] = imx8m_clk_hw_composite("hdmi_27m", imx8mp_hdmi_27m_sels, ccm_base + 0xbb80); + hws[IMX8MP_CLK_HDMI_24M] = imx8m_clk_hw_composite("hdmi_24m", imx8mp_hdmi_24m_sels, ccm_base + 0xbb80); hws[IMX8MP_CLK_HDMI_REF_266M] = imx8m_clk_hw_composite("hdmi_ref_266m", imx8mp_hdmi_ref_266m_sels, ccm_base + 0xbc00); hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80); hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00); diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h index 2fab63186bca..00d4d2288990 100644 --- a/include/dt-bindings/clock/imx8mp-clock.h +++ b/include/dt-bindings/clock/imx8mp-clock.h @@ -173,7 +173,7 @@ #define IMX8MP_CLK_IPP_DO_CLKO1 164 #define IMX8MP_CLK_IPP_DO_CLKO2 165 #define IMX8MP_CLK_HDMI_FDCC_TST 166 -#define IMX8MP_CLK_HDMI_27M 167 +#define IMX8MP_CLK_HDMI_24M 167 #define IMX8MP_CLK_HDMI_REF_266M 168 #define IMX8MP_CLK_USDHC3 169 #define IMX8MP_CLK_MEDIA_CAM1_PIX 170 From d6fb02f054127c23b048f4753176c57f3e440e79 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 18:17:06 +0800 Subject: [PATCH 104/809] clk: imx: imx8mq: fix a53 cpu clock The A53 CCM clk root only accepts input up to 1GHz, CCM A53 root signoff timing is 1Ghz, however the A53 core which sources from CCM root could run above 1GHz which violates the CCM. There is a CORE_SEL slice before A53 core, we need to configure the CORE_SEL slice source from ARM PLL, not A53 CCM clk root. The A53 CCM clk root should only be used when need to change ARM PLL frequency. Add arm_a53_core clk that could source from arm_a53_div and arm_pll_out. Configure a53 ccm root sources from 800MHz sys pll Configure a53 core sources from arm_pll_out Mark arm_a53_core as critical clock Fixes: db27e40b27f1 ("clk: imx8mq: Add the missing ARM clock") Reviewed-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mq.c | 16 ++++++++++++---- include/dt-bindings/clock/imx8mq-clock.h | 4 +++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 1f5ea1eaad65..b81f02ab7eb1 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -41,6 +41,8 @@ static const char * const video2_pll_out_sels[] = {"video2_pll1_ref_sel", }; static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll_out", }; +static const char * const imx8mq_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", }; + static const char * const imx8mq_arm_m4_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_250m", "sys1_pll_266m", "sys1_pll_800m", "audio_pll1_out", "video_pll1_out", "sys3_pll_out", }; @@ -425,6 +427,9 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_CLK_GPU_SHADER_CG] = hws[IMX8MQ_CLK_GPU_SHADER]; hws[IMX8MQ_CLK_GPU_SHADER_DIV] = hws[IMX8MQ_CLK_GPU_SHADER]; + /* CORE SEL */ + hws[IMX8MQ_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels), CLK_IS_CRITICAL); + /* BUS */ hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800); hws[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mq_enet_axi_sels, base + 0x8880); @@ -588,11 +593,14 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc_25m", 1, 8); hws[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); - hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div", - hws[IMX8MQ_CLK_A53_DIV]->clk, - hws[IMX8MQ_CLK_A53_SRC]->clk, + clk_hw_set_parent(hws[IMX8MQ_CLK_A53_SRC], hws[IMX8MQ_SYS1_PLL_800M]); + clk_hw_set_parent(hws[IMX8MQ_CLK_A53_CORE], hws[IMX8MQ_ARM_PLL_OUT]); + + hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", + hws[IMX8MQ_CLK_A53_CORE]->clk, + hws[IMX8MQ_CLK_A53_CORE]->clk, hws[IMX8MQ_ARM_PLL_OUT]->clk, - hws[IMX8MQ_SYS1_PLL_800M]->clk); + hws[IMX8MQ_CLK_A53_DIV]->clk); imx_check_clk_hws(hws, IMX8MQ_CLK_END); diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 2b88723310bd..9b8045d75b8b 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -429,6 +429,8 @@ #define IMX8MQ_CLK_M4_CORE 287 #define IMX8MQ_CLK_VPU_CORE 288 -#define IMX8MQ_CLK_END 289 +#define IMX8MQ_CLK_A53_CORE 289 + +#define IMX8MQ_CLK_END 290 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ From d3b70cd87e773bb298eb78fbafed68afaf06b1a2 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 18:17:07 +0800 Subject: [PATCH 105/809] clk: imx: imx8mm: fix a53 cpu clock The A53 CCM clk root only accepts input up to 1GHz, CCM A53 root signoff timing is 1Ghz, however the A53 core which sources from CCM root could run above 1GHz which voilates the CCM. There is a CORE_SEL slice before A53 core, we need configure the CORE_SEL slice source from ARM PLL, not A53 CCM clk root. The A53 CCM clk root should only be used when need to change ARM PLL frequency. Add arm_a53_core clk that could source from arm_a53_div and arm_pll_out. Configure a53 ccm root sources from 800MHz sys pll Configure a53 core sources from arm_pll_out Mark arm_a53_core as critical clock Fixes: ba5625c3e272 ("clk: imx: Add clock driver support for imx8mm") Reviewed-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 16 ++++++++++++---- include/dt-bindings/clock/imx8mm-clock.h | 4 +++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 481d20ae4e0b..9feda4f5b3d6 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -39,6 +39,8 @@ static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; static const char *imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; +static const char * const imx8mm_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", }; + static const char *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m", "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; @@ -437,6 +439,9 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_GPU2D_CG] = hws[IMX8MM_CLK_GPU2D_CORE]; hws[IMX8MM_CLK_GPU2D_DIV] = hws[IMX8MM_CLK_GPU2D_CORE]; + /* CORE SEL */ + hws[IMX8MM_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mm_a53_core_sels, ARRAY_SIZE(imx8mm_a53_core_sels), CLK_IS_CRITICAL); + /* BUS */ hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880); @@ -603,11 +608,14 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); hws[IMX8MM_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL); - hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div", - hws[IMX8MM_CLK_A53_DIV]->clk, - hws[IMX8MM_CLK_A53_SRC]->clk, + clk_hw_set_parent(hws[IMX8MM_CLK_A53_SRC], hws[IMX8MM_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MM_CLK_A53_CORE], hws[IMX8MM_ARM_PLL_OUT]); + + hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", + hws[IMX8MM_CLK_A53_CORE]->clk, + hws[IMX8MM_CLK_A53_CORE]->clk, hws[IMX8MM_ARM_PLL_OUT]->clk, - hws[IMX8MM_SYS_PLL1_800M]->clk); + hws[IMX8MM_CLK_A53_DIV]->clk); imx_check_clk_hws(hws, IMX8MM_CLK_END); diff --git a/include/dt-bindings/clock/imx8mm-clock.h b/include/dt-bindings/clock/imx8mm-clock.h index dbfee6579d6c..e63a5530aed7 100644 --- a/include/dt-bindings/clock/imx8mm-clock.h +++ b/include/dt-bindings/clock/imx8mm-clock.h @@ -272,6 +272,8 @@ #define IMX8MM_CLK_CLKO2 250 -#define IMX8MM_CLK_END 251 +#define IMX8MM_CLK_A53_CORE 251 + +#define IMX8MM_CLK_END 252 #endif From c69def88987995f5d3ea28f12febd1b2c567f511 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 18:17:08 +0800 Subject: [PATCH 106/809] clk: imx: imx8mn: fix a53 cpu clock The A53 CCM clk root only accepts input up to 1GHz, CCM A53 root signoff timing is 1Ghz, however the A53 core which sources from CCM root could run above 1GHz which voilates the CCM. There is a CORE_SEL slice before A53 core, we need configure the CORE_SEL slice source from ARM PLL, not A53 CCM clk root. The A53 CCM clk root should only be used when need to change ARM PLL frequency. Add arm_a53_core clk that could source from arm_a53_div and arm_pll_out. Configure a53 ccm root sources from 800MHz sys pll Configure a53 core sources from arm_pll_out Mark arm_a53_core as critical clk. Fixes: 96d6392b54db ("clk: imx: Add support for i.MX8MN clock driver") Reviewed-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 16 ++++++++++++---- include/dt-bindings/clock/imx8mn-clock.h | 4 +++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index fb47f86e35e8..83618affca8b 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -38,6 +38,8 @@ static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pl "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; +static const char * const imx8mn_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", }; + static const char * const imx8mn_gpu_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; @@ -425,6 +427,9 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_GPU_SHADER_CG] = hws[IMX8MN_CLK_GPU_SHADER]; hws[IMX8MN_CLK_GPU_SHADER_DIV] = hws[IMX8MN_CLK_GPU_SHADER]; + /* CORE SEL */ + hws[IMX8MN_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels), CLK_IS_CRITICAL); + /* BUS */ hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800); hws[IMX8MN_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mn_enet_axi_sels, base + 0x8880); @@ -554,11 +559,14 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); - hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div", - hws[IMX8MN_CLK_A53_DIV]->clk, - hws[IMX8MN_CLK_A53_SRC]->clk, + clk_hw_set_parent(hws[IMX8MN_CLK_A53_SRC], hws[IMX8MN_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MN_CLK_A53_CORE], hws[IMX8MN_ARM_PLL_OUT]); + + hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", + hws[IMX8MN_CLK_A53_CORE]->clk, + hws[IMX8MN_CLK_A53_CORE]->clk, hws[IMX8MN_ARM_PLL_OUT]->clk, - hws[IMX8MN_SYS_PLL1_800M]->clk); + hws[IMX8MN_CLK_A53_DIV]->clk); imx_check_clk_hws(hws, IMX8MN_CLK_END); diff --git a/include/dt-bindings/clock/imx8mn-clock.h b/include/dt-bindings/clock/imx8mn-clock.h index c42a22d3cf7c..6c4364c01c50 100644 --- a/include/dt-bindings/clock/imx8mn-clock.h +++ b/include/dt-bindings/clock/imx8mn-clock.h @@ -232,6 +232,8 @@ #define IMX8MN_CLK_GPU_CORE 212 #define IMX8MN_CLK_GPU_SHADER 213 -#define IMX8MN_CLK_END 214 +#define IMX8MN_CLK_A53_CORE 214 + +#define IMX8MN_CLK_END 215 #endif From 7ab227210110a4137b005b7be3df1ec2d668ac96 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 18:17:09 +0800 Subject: [PATCH 107/809] clk: imx: imx8mp: fix a53 cpu clock The A53 CCM clk root only accepts input up to 1GHz, CCM A53 root signoff timing is 1Ghz, however the A53 core which sources from CCM root could run above 1GHz which voilates the CCM. There is a CORE_SEL slice before A53 core, we need configure the CORE_SEL slice source from ARM PLL, not A53 CCM clk root. The A53 CCM clk root should only be used when need to change ARM PLL frequency. Add arm_a53_core clk that could source from arm_a53_div and arm_pll_out. Configure a53 ccm root sources from 800MHz sys pll Configure a53 core sources from arm_pll_out Mark arm_a53_core as critical clk Reviewed-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 16 ++++++++++++---- include/dt-bindings/clock/imx8mp-clock.h | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index a6313cf4a30c..c6161a4af201 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -34,6 +34,8 @@ static const char * const imx8mp_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pl "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; +static const char * const imx8mp_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", }; + static const char * const imx8mp_m7_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "vpu_pll_out", "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; @@ -554,6 +556,9 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_HSIO_AXI_DIV] = imx_clk_hw_divider2("hsio_axi_div", "hsio_axi_cg", ccm_base + 0x8380, 0, 3); hws[IMX8MP_CLK_MEDIA_ISP_DIV] = imx_clk_hw_divider2("media_isp_div", "media_isp_cg", ccm_base + 0x8400, 0, 3); + /* CORE SEL */ + hws[IMX8MP_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", ccm_base + 0x9880, 24, 1, imx8mp_a53_core_sels, ARRAY_SIZE(imx8mp_a53_core_sels), CLK_IS_CRITICAL); + hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800); hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880); hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900); @@ -724,11 +729,14 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_VPU_ROOT] = imx_clk_hw_gate4("vpu_root_clk", "vpu_bus", ccm_base + 0x4630, 0); hws[IMX8MP_CLK_AUDIO_ROOT] = imx_clk_hw_gate4("audio_root_clk", "ipg_root", ccm_base + 0x4650, 0); - hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div", - hws[IMX8MP_CLK_A53_DIV]->clk, - hws[IMX8MP_CLK_A53_SRC]->clk, + clk_hw_set_parent(hws[IMX8MP_CLK_A53_SRC], hws[IMX8MP_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MP_CLK_A53_CORE], hws[IMX8MP_ARM_PLL_OUT]); + + hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", + hws[IMX8MP_CLK_A53_CORE]->clk, + hws[IMX8MP_CLK_A53_CORE]->clk, hws[IMX8MP_ARM_PLL_OUT]->clk, - hws[IMX8MP_SYS_PLL1_800M]->clk); + hws[IMX8MP_CLK_A53_DIV]->clk); imx_check_clk_hws(hws, IMX8MP_CLK_END); diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h index 00d4d2288990..47ab082238b4 100644 --- a/include/dt-bindings/clock/imx8mp-clock.h +++ b/include/dt-bindings/clock/imx8mp-clock.h @@ -294,7 +294,8 @@ #define IMX8MP_CLK_DRAM_ALT_ROOT 285 #define IMX8MP_CLK_DRAM_CORE 286 #define IMX8MP_CLK_ARM 287 +#define IMX8MP_CLK_A53_CORE 288 -#define IMX8MP_CLK_END 288 +#define IMX8MP_CLK_END 289 #endif From 530cf8d49f2a650625eee6ce28793bd7974e14bd Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 21 Feb 2020 14:31:56 +0800 Subject: [PATCH 108/809] clk: imx: pll14xx: Return error if pll type is invalid When pll type is invalid, ONLY output error message is NOT enough, should return error immediately. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pll14xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 37e311e1d058..a83bbbee77d9 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -410,6 +410,8 @@ struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name, default: pr_err("%s: Unknown pll type for pll clk %s\n", __func__, name); + kfree(pll); + return ERR_PTR(-EINVAL); }; pll->base = base; From eeca5721baeb11935dac85e71f7fd5a62919ed85 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 21 Feb 2020 14:59:36 +0800 Subject: [PATCH 109/809] clk: imx: clk-sscg-pll: Drop unnecessary initialization No need to initialize 'ret' in many functions, as it will get the return value from function call, so remove the initializtion of 'ret'. Signed-off-by: Anson Huang Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-sscg-pll.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-sscg-pll.c b/drivers/clk/imx/clk-sscg-pll.c index acd1b9002be6..d4a2be16d132 100644 --- a/drivers/clk/imx/clk-sscg-pll.c +++ b/drivers/clk/imx/clk-sscg-pll.c @@ -195,10 +195,10 @@ static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup, uint64_t ref) { - int ret = -EINVAL; + int ret; if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ) - return ret; + return -EINVAL; temp_setup->vco1 = ref; @@ -254,10 +254,10 @@ static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup, uint64_t ref) { - int ret = -EINVAL; + int ret; if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ) - return ret; + return -EINVAL; temp_setup->ref = ref; @@ -428,7 +428,7 @@ static int __clk_sscg_pll_determine_rate(struct clk_hw *hw, struct clk_sscg_pll_setup *setup = &pll->setup; struct clk_hw *parent_hw = NULL; int bypass_parent_index; - int ret = -EINVAL; + int ret; req->max_rate = max; req->min_rate = min; @@ -467,10 +467,10 @@ static int clk_sscg_pll_determine_rate(struct clk_hw *hw, uint64_t rate = req->rate; uint64_t min = req->min_rate; uint64_t max = req->max_rate; - int ret = -EINVAL; + int ret; if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ) - return ret; + return -EINVAL; ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate, rate, PLL_BYPASS2); From 5b11e5d784c2dab41cd3171f4d297bdcac1b85ed Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Feb 2020 21:58:12 -0300 Subject: [PATCH 110/809] power/supply: ingenic-battery: Don't print error on -EPROBE_DEFER Don't print an error message if devm_power_supply_register() returns -EPROBE_DEFER, since the driver will simply re-probe later. Signed-off-by: Paul Cercueil Signed-off-by: Sebastian Reichel --- drivers/power/supply/ingenic-battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c index 2748715c4c75..dd3d93dfe3eb 100644 --- a/drivers/power/supply/ingenic-battery.c +++ b/drivers/power/supply/ingenic-battery.c @@ -148,7 +148,8 @@ static int ingenic_battery_probe(struct platform_device *pdev) bat->battery = devm_power_supply_register(dev, desc, &psy_cfg); if (IS_ERR(bat->battery)) { - dev_err(dev, "Unable to register battery\n"); + if (PTR_ERR(bat->battery) != -EPROBE_DEFER) + dev_err(dev, "Unable to register battery\n"); return PTR_ERR(bat->battery); } From 1c5dfc5e3f2df5892a849621d729daa87cfef436 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 14 Feb 2020 13:38:58 +0800 Subject: [PATCH 111/809] power: supply: sc27xx: Add POWER_SUPPLY_PROP_CHARGE_NOW attribute Add the POWER_SUPPLY_PROP_CHARGE_NOW attribute to allow user to get current battery capacity (uAh) to do measurement. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 469c83fdaa8e..a7c8a8453db1 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -614,6 +614,17 @@ static int sc27xx_fgu_get_property(struct power_supply *psy, val->intval = data->total_cap * 1000; break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = sc27xx_fgu_get_clbcnt(data, &value); + if (ret) + goto error; + + value = DIV_ROUND_CLOSEST(value * 10, + 36 * SC27XX_FGU_SAMPLE_HZ); + val->intval = sc27xx_fgu_adc_to_current(data, value); + + break; + default: ret = -EINVAL; break; @@ -682,6 +693,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, POWER_SUPPLY_PROP_CALIBRATE, + POWER_SUPPLY_PROP_CHARGE_NOW }; static const struct power_supply_desc sc27xx_fgu_desc = { From 05642cf7289c5562e5939d2ee8a0529d310010b8 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 7 Jan 2020 09:16:40 +0000 Subject: [PATCH 112/809] powerpc/32: don't restore r0, r6-r8 on exception entry path after trace_hardirqs_off() Since commit b86fb88855ea ("powerpc/32: implement fast entry for syscalls on non BOOKE") and commit 1a4b739bbb4f ("powerpc/32: implement fast entry for syscalls on BOOKE"), syscalls don't use the exception entry path anymore. It is therefore pointless to restore r0 and r6-r8 after calling trace_hardirqs_off(). In the meantime, drop the '2:' label which is unused and misleading. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/d2c6dc65d27e83964eb05f16a126161ab6455eea.1578388585.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/entry_32.S | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index ad000cbb5252..afab378c3d28 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -246,9 +246,8 @@ reenable_mmu: * r3 can be different from GPR3(r1) at this point, r9 and r11 * contains the old MSR and handler address respectively, * r4 & r5 can contain page fault arguments that need to be passed - * along as well. r12, CCR, CTR, XER etc... are left clobbered as - * they aren't useful past this point (aren't syscall arguments), - * the rest is restored from the exception frame. + * along as well. r0, r6-r8, r12, CCR, CTR, XER etc... are left + * clobbered as they aren't useful past this point. */ stwu r1,-32(r1) @@ -262,16 +261,12 @@ reenable_mmu: * lockdep */ 1: bl trace_hardirqs_off -2: lwz r5,24(r1) + lwz r5,24(r1) lwz r4,20(r1) lwz r3,16(r1) lwz r11,12(r1) lwz r9,8(r1) addi r1,r1,32 - lwz r0,GPR0(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) mtctr r11 mtlr r9 bctr /* jump to handler */ From 0b1c524caaae2428b20e714297243e5551251eb5 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 9 Jan 2020 08:25:25 +0000 Subject: [PATCH 113/809] powerpc/32: refactor pmd_offset(pud_offset(pgd_offset... At several places pmd pointer is retrieved through the same action: pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr); or pmd = pmd_offset(pud_offset(pgd_offset_k(addr), addr), addr); Refactor this by implementing two helpers pmd_ptr() and pmd_ptr_k() This will help when adding the p4d level. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/7b065c5be35726af4066cab238ee35cabceda1fa.1578558199.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/pgtable.h | 12 ++++++++++++ arch/powerpc/mm/book3s32/mmu.c | 2 +- arch/powerpc/mm/book3s32/tlb.c | 4 ++-- arch/powerpc/mm/kasan/kasan_init_32.c | 8 ++++---- arch/powerpc/mm/mem.c | 3 +-- arch/powerpc/mm/nohash/40x.c | 4 ++-- arch/powerpc/mm/pgtable_32.c | 2 +- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 8cc543ed114c..22bf7bb666a7 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -41,6 +41,18 @@ struct mm_struct; #ifndef __ASSEMBLY__ +#ifdef CONFIG_PPC32 +static inline pmd_t *pmd_ptr(struct mm_struct *mm, unsigned long va) +{ + return pmd_offset(pud_offset(pgd_offset(mm, va), va), va); +} + +static inline pmd_t *pmd_ptr_k(unsigned long va) +{ + return pmd_offset(pud_offset(pgd_offset_k(va), va), va); +} +#endif + #include /* Keep these as a macros to avoid include dependency mess */ diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c index 0a1c65a2c565..c225b0397ffd 100644 --- a/arch/powerpc/mm/book3s32/mmu.c +++ b/arch/powerpc/mm/book3s32/mmu.c @@ -312,7 +312,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea) if (!Hash) return; - pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea); + pmd = pmd_ptr(mm, ea); if (!pmd_none(*pmd)) add_hash_page(mm->context.id, ea, pmd_val(*pmd)); } diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c index 724c0490fb17..dc9039a170aa 100644 --- a/arch/powerpc/mm/book3s32/tlb.c +++ b/arch/powerpc/mm/book3s32/tlb.c @@ -90,7 +90,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start, if (start >= end) return; end = (end - 1) | ~PAGE_MASK; - pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start); + pmd = pmd_ptr(mm, start); for (;;) { pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1; if (pmd_end > end) @@ -148,7 +148,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) return; } mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm; - pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr); + pmd = pmd_ptr(mm, vmaddr); if (!pmd_none(*pmd)) flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1); } diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/kasan_init_32.c index 16dd95bd0749..b195d085970a 100644 --- a/arch/powerpc/mm/kasan/kasan_init_32.c +++ b/arch/powerpc/mm/kasan/kasan_init_32.c @@ -36,7 +36,7 @@ static int __init kasan_init_shadow_page_tables(unsigned long k_start, unsigned unsigned long k_cur, k_next; pte_t *new = NULL; - pmd = pmd_offset(pud_offset(pgd_offset_k(k_start), k_start), k_start); + pmd = pmd_ptr_k(k_start); for (k_cur = k_start; k_cur != k_end; k_cur = k_next, pmd++) { k_next = pgd_addr_end(k_cur, k_end); @@ -78,7 +78,7 @@ static int __init kasan_init_region(void *start, size_t size) block = memblock_alloc(k_end - k_start, PAGE_SIZE); for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) { - pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur); + pmd_t *pmd = pmd_ptr_k(k_cur); void *va = block + k_cur - k_start; pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL); @@ -102,7 +102,7 @@ static void __init kasan_remap_early_shadow_ro(void) kasan_populate_pte(kasan_early_shadow_pte, prot); for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) { - pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur); + pmd_t *pmd = pmd_ptr_k(k_cur); pte_t *ptep = pte_offset_kernel(pmd, k_cur); if ((pte_val(*ptep) & PTE_RPN_MASK) != pa) @@ -202,7 +202,7 @@ void __init kasan_early_init(void) unsigned long addr = KASAN_SHADOW_START; unsigned long end = KASAN_SHADOW_END; unsigned long next; - pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(addr), addr), addr); + pmd_t *pmd = pmd_ptr_k(addr); BUILD_BUG_ON(KASAN_SHADOW_START & ~PGDIR_MASK); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index ef7b1119b2e2..b7325bb4c890 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -69,8 +69,7 @@ EXPORT_SYMBOL(kmap_prot); static inline pte_t *virt_to_kpte(unsigned long vaddr) { - return pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), - vaddr), vaddr), vaddr); + return pte_offset_kernel(pmd_ptr_k(vaddr), vaddr); } #endif diff --git a/arch/powerpc/mm/nohash/40x.c b/arch/powerpc/mm/nohash/40x.c index f348104eb461..82862723ab42 100644 --- a/arch/powerpc/mm/nohash/40x.c +++ b/arch/powerpc/mm/nohash/40x.c @@ -104,7 +104,7 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top) pmd_t *pmdp; unsigned long val = p | _PMD_SIZE_16M | _PAGE_EXEC | _PAGE_HWWRITE; - pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); + pmdp = pmd_ptr_k(v); *pmdp++ = __pmd(val); *pmdp++ = __pmd(val); *pmdp++ = __pmd(val); @@ -119,7 +119,7 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top) pmd_t *pmdp; unsigned long val = p | _PMD_SIZE_4M | _PAGE_EXEC | _PAGE_HWWRITE; - pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); + pmdp = pmd_ptr_k(v); *pmdp = __pmd(val); v += LARGE_PAGE_SIZE_4M; diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 5fb90edd865e..d90c166bb6e5 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -63,7 +63,7 @@ int __ref map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot) int err = -ENOMEM; /* Use upper 10 bits of VA to index the first level map */ - pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va); + pd = pmd_ptr_k(va); /* Use middle 10 bits of VA to index the second-level map */ if (likely(slab_is_available())) pg = pte_alloc_kernel(pd, va); From 2efc7c085f05870eda6f29ac71eeb83f3bd54415 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 9 Jan 2020 08:25:26 +0000 Subject: [PATCH 114/809] powerpc/32: drop get_pteptr() Commit 8d30c14cab30 ("powerpc/mm: Rework I$/D$ coherency (v3)") and commit 90ac19a8b21b ("[POWERPC] Abolish iopa(), mm_ptov(), io_block_mapping() from arch/powerpc") removed the use of get_pteptr() outside of mm/pgtable_32.c In mm/pgtable_32.c, the only user of get_pteptr() is change_page_attr() which operates on kernel context and on lowmem pages only. Make virt_to_kpte() available outside of mm/mem.c and use it instead of get_pteptr(), and drop get_pteptr() Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/788378c6c3ba5c5298caab7c7f95e6c3c88244b8.1578558199.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/pgtable.h | 5 ++++ arch/powerpc/mm/mem.c | 5 ---- arch/powerpc/mm/pgtable_32.c | 39 ++---------------------------- 3 files changed, 7 insertions(+), 42 deletions(-) diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 22bf7bb666a7..b80bfd41828d 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -51,6 +51,11 @@ static inline pmd_t *pmd_ptr_k(unsigned long va) { return pmd_offset(pud_offset(pgd_offset_k(va), va), va); } + +static inline pte_t *virt_to_kpte(unsigned long vaddr) +{ + return pte_offset_kernel(pmd_ptr_k(vaddr), vaddr); +} #endif #include diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index b7325bb4c890..4f852d2a62f5 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -66,11 +66,6 @@ pte_t *kmap_pte; EXPORT_SYMBOL(kmap_pte); pgprot_t kmap_prot; EXPORT_SYMBOL(kmap_prot); - -static inline pte_t *virt_to_kpte(unsigned long vaddr) -{ - return pte_offset_kernel(pmd_ptr_k(vaddr), vaddr); -} #endif pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index d90c166bb6e5..f62de06e3d07 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -121,44 +121,9 @@ void __init mapin_ram(void) } } -/* Scan the real Linux page tables and return a PTE pointer for - * a virtual address in a context. - * Returns true (1) if PTE was found, zero otherwise. The pointer to - * the PTE pointer is unmodified if PTE is not found. - */ -static int -get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - int retval = 0; - - pgd = pgd_offset(mm, addr & PAGE_MASK); - if (pgd) { - pud = pud_offset(pgd, addr & PAGE_MASK); - if (pud && pud_present(*pud)) { - pmd = pmd_offset(pud, addr & PAGE_MASK); - if (pmd_present(*pmd)) { - pte = pte_offset_map(pmd, addr & PAGE_MASK); - if (pte) { - retval = 1; - *ptep = pte; - if (pmdp) - *pmdp = pmd; - /* XXX caller needs to do pte_unmap, yuck */ - } - } - } - } - return(retval); -} - static int __change_page_attr_noflush(struct page *page, pgprot_t prot) { pte_t *kpte; - pmd_t *kpmd; unsigned long address; BUG_ON(PageHighMem(page)); @@ -166,10 +131,10 @@ static int __change_page_attr_noflush(struct page *page, pgprot_t prot) if (v_block_mapped(address)) return 0; - if (!get_pteptr(&init_mm, address, &kpte, &kpmd)) + kpte = virt_to_kpte(address); + if (!kpte) return -EINVAL; __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0); - pte_unmap(kpte); return 0; } From bc36dfffd5f3f19edcf85954d93eb0bc45875c37 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 24 Feb 2020 12:52:17 +0100 Subject: [PATCH 115/809] ext2: Silence lockdep warning about reclaim under xattr_sem Lockdep complains about a chain: sb_internal#2 --> &ei->xattr_sem#2 --> fs_reclaim and shrink_dentry_list -> ext2_evict_inode -> ext2_xattr_delete_inode -> down_write(ei->xattr_sem) creating a locking cycle in the reclaim path. This is however a false positive because when we are in ext2_evict_inode() we are the only holder of the inode reference and nobody else should touch xattr_sem of that inode. So we cannot ever block on acquiring the xattr_sem in the reclaim path. Silence the lockdep warning by using down_write_trylock() in ext2_xattr_delete_inode() to not create false locking dependency. Reported-by: "J. R. Okajima" Reviewed-by: Ritesh Harjani Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 0456bc990b5e..9ad07c7ef0b3 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -790,7 +790,15 @@ ext2_xattr_delete_inode(struct inode *inode) struct buffer_head *bh = NULL; struct ext2_sb_info *sbi = EXT2_SB(inode->i_sb); - down_write(&EXT2_I(inode)->xattr_sem); + /* + * We are the only ones holding inode reference. The xattr_sem should + * better be unlocked! We could as well just not acquire xattr_sem at + * all but this makes the code more futureproof. OTOH we need trylock + * here to avoid false-positive warning from lockdep about reclaim + * circular dependency. + */ + if (WARN_ON_ONCE(!down_write_trylock(&EXT2_I(inode)->xattr_sem))) + return; if (!EXT2_I(inode)->i_file_acl) goto cleanup; From 6e2a7b5171ec7fd6005639479961ca28e70d4929 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 19 Feb 2020 11:19:15 +0100 Subject: [PATCH 116/809] s390/qdio: use QDIO_IRQ_STATE_INACTIVE instead of 0 Don't rely on the numeric value of enum constants. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio_setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index c56ff92c6e0c..d57b115867a3 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -462,7 +462,8 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL; - irq_ptr->sch_token = irq_ptr->state = irq_ptr->perf_stat_enabled = 0; + irq_ptr->sch_token = irq_ptr->perf_stat_enabled = 0; + irq_ptr->state = QDIO_IRQ_STATE_INACTIVE; /* wipes qib.ac, required by ar7063 */ memset(irq_ptr->qdr, 0, sizeof(struct qdr)); From d5d006fa0927c34fa083c8d48e33b1c30b29fd1b Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 21 Feb 2020 10:54:41 +0100 Subject: [PATCH 117/809] s390/qdio: simplify debugfs code There's no need for error handling, the debugfs core is smart enough to deal with IS_ERR() internally. This will also keep us from creating the debugfs files if the device directory doesn't exist. Currently (because irq_ptr->debugfs_dev gets set to NULL on error) the files would be placed into the debugfs root - without any association to their parent device. On teardown, use the debugfs_remove_recursive() helper to avoid keeping track of each created file/directory. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio.h | 2 -- drivers/s390/cio/qdio_debug.c | 34 ++++++++-------------------------- drivers/s390/cio/qdio_setup.c | 2 +- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 85d530927e4e..e24a2cde487a 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -254,7 +254,6 @@ struct qdio_q { /* upper-layer program handler */ qdio_handler_t (*handler); - struct dentry *debugfs_q; struct qdio_irq *irq_ptr; struct sl *sl; /* @@ -270,7 +269,6 @@ struct qdio_irq { struct ccw_device *cdev; struct list_head entry; /* list of thinint devices */ struct dentry *debugfs_dev; - struct dentry *debugfs_perf; unsigned long int_parm; struct subchannel_id schid; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 9c0370b27426..bf8d82503870 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -284,17 +284,14 @@ static const struct file_operations debugfs_perf_fops = { .release = single_release, }; -static void setup_debugfs_entry(struct qdio_q *q) +static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q) { char name[QDIO_DEBUGFS_NAME_LEN]; snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", q->is_input_q ? "input" : "output", q->nr); - q->debugfs_q = debugfs_create_file(name, 0444, - q->irq_ptr->debugfs_dev, q, &qstat_fops); - if (IS_ERR(q->debugfs_q)) - q->debugfs_q = NULL; + debugfs_create_file(name, 0444, parent, q, &qstat_fops); } void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -304,33 +301,18 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), debugfs_root); - if (IS_ERR(irq_ptr->debugfs_dev)) - irq_ptr->debugfs_dev = NULL; - - irq_ptr->debugfs_perf = debugfs_create_file("statistics", - S_IFREG | S_IRUGO | S_IWUSR, - irq_ptr->debugfs_dev, irq_ptr, - &debugfs_perf_fops); - if (IS_ERR(irq_ptr->debugfs_perf)) - irq_ptr->debugfs_perf = NULL; + debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, + irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); for_each_input_queue(irq_ptr, q, i) - setup_debugfs_entry(q); + setup_debugfs_entry(irq_ptr->debugfs_dev, q); for_each_output_queue(irq_ptr, q, i) - setup_debugfs_entry(q); + setup_debugfs_entry(irq_ptr->debugfs_dev, q); } void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr) { - struct qdio_q *q; - int i; - - for_each_input_queue(irq_ptr, q, i) - debugfs_remove(q->debugfs_q); - for_each_output_queue(irq_ptr, q, i) - debugfs_remove(q->debugfs_q); - debugfs_remove(irq_ptr->debugfs_perf); - debugfs_remove(irq_ptr->debugfs_dev); + debugfs_remove_recursive(irq_ptr->debugfs_dev); } int __init qdio_debug_init(void) @@ -352,7 +334,7 @@ int __init qdio_debug_init(void) void qdio_debug_exit(void) { qdio_clear_dbf_list(); - debugfs_remove(debugfs_root); + debugfs_remove_recursive(debugfs_root); debug_unregister(qdio_dbf_setup); debug_unregister(qdio_dbf_error); } diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index d57b115867a3..ad04947a0032 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -461,7 +461,7 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc)); memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); - irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL; + irq_ptr->debugfs_dev = NULL; irq_ptr->sch_token = irq_ptr->perf_stat_enabled = 0; irq_ptr->state = QDIO_IRQ_STATE_INACTIVE; From fa226f1d81e2d3798d30eaa14550d7f35c35e6f3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 21 Feb 2020 09:06:12 -0600 Subject: [PATCH 118/809] s390: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Link: https://lkml.kernel.org/r/20200221150612.GA9717@embeddedor Signed-off-by: Gustavo A. R. Silva Signed-off-by: Vasily Gorbik --- arch/s390/appldata/appldata_os.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.h | 2 +- drivers/s390/char/raw3270.h | 2 +- drivers/s390/char/sclp_pci.c | 2 +- drivers/s390/cio/idset.c | 2 +- drivers/s390/crypto/pkey_api.c | 2 +- drivers/s390/crypto/zcrypt_ccamisc.h | 2 +- drivers/s390/crypto/zcrypt_msgtype6.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index 54f375627532..8bf46d705957 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -75,7 +75,7 @@ struct appldata_os_data { (waiting for I/O) */ /* per cpu data */ - struct appldata_os_per_cpu os_cpu[0]; + struct appldata_os_per_cpu os_cpu[]; } __attribute__((packed)); static struct appldata_os_data *appldata_os_data; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 8d4971645cf1..facb588d09e4 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -58,7 +58,7 @@ struct dasd_diag_private { struct dasd_diag_req { unsigned int block_count; - struct dasd_diag_bio bio[0]; + struct dasd_diag_bio bio[]; }; static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */ diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 6943508d0f1d..ca24a78a256e 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -220,7 +220,7 @@ struct LRE_eckd_data { __u8 imbedded_count; __u8 extended_operation; __u16 extended_parameter_length; - __u8 extended_parameter[0]; + __u8 extended_parameter[]; } __attribute__ ((packed)); /* Prefix data for format 0x00 and 0x01 */ diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index 3afaa35f7351..08f36e973b43 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h @@ -211,7 +211,7 @@ struct string struct list_head update; unsigned long size; unsigned long len; - char string[0]; + char string[]; } __attribute__ ((aligned(8))); static inline struct string * diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c index 995e9196852e..a3e5a5fb0c1e 100644 --- a/drivers/s390/char/sclp_pci.c +++ b/drivers/s390/char/sclp_pci.c @@ -39,7 +39,7 @@ struct err_notify_evbuf { u8 atype; u32 fh; u32 fid; - u8 data[0]; + u8 data[]; } __packed; struct err_notify_sccb { diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 835de44dbbcc..77d0ea7b381b 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -13,7 +13,7 @@ struct idset { int num_ssid; int num_id; - unsigned long bitmap[0]; + unsigned long bitmap[]; }; static inline unsigned long bitmap_size(int num_ssid, int num_id) diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 2f33c5fcf676..74e63ec49068 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -80,7 +80,7 @@ struct clearaeskeytoken { u8 res1[3]; u32 keytype; /* key type, one of the PKEY_KEYTYPE values */ u32 len; /* bytes actually stored in clearkey[] */ - u8 clearkey[0]; /* clear key value */ + u8 clearkey[]; /* clear key value */ } __packed; /* diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index 3a9876d5ab0e..8b7a641671c9 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -90,7 +90,7 @@ struct cipherkeytoken { u16 kmf1; /* key management field 1 */ u16 kmf2; /* key management field 2 */ u16 kmf3; /* key management field 3 */ - u8 vdata[0]; /* variable part data follows */ + u8 vdata[]; /* variable part data follows */ } __packed; /* Some defines for the CCA AES cipherkeytoken kmf1 field */ diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index a36251d138fb..eadd3a438a4b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -590,7 +590,7 @@ struct type86x_reply { struct CPRBX cprbx; unsigned char pad[4]; /* 4 byte function code/rules block ? */ unsigned short length; - char text[0]; + char text[]; } __packed; struct type86_ep11_reply { From 4a559cd15dbc79958fa9b18ad4e8afe4a0bf4744 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Tue, 25 Feb 2020 15:34:30 +0100 Subject: [PATCH 119/809] s390/crypto: explicitly memzero stack key material in aes_s390.c aes_s390.c has several functions which allocate space for key material on the stack and leave the used keys there. It is considered good practice to clean these locations before the function returns. Link: https://lkml.kernel.org/r/20200221165511.GB6928@lst.de Signed-off-by: Torsten Duwe Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- arch/s390/crypto/aes_s390.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 1c23d84a9097..73044634d342 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -342,6 +342,7 @@ static int cbc_aes_crypt(struct skcipher_request *req, unsigned long modifier) memcpy(walk.iv, param.iv, AES_BLOCK_SIZE); ret = skcipher_walk_done(&walk, nbytes - n); } + memzero_explicit(¶m, sizeof(param)); return ret; } @@ -470,6 +471,8 @@ static int xts_aes_crypt(struct skcipher_request *req, unsigned long modifier) walk.dst.virt.addr, walk.src.virt.addr, n); ret = skcipher_walk_done(&walk, nbytes - n); } + memzero_explicit(&pcc_param, sizeof(pcc_param)); + memzero_explicit(&xts_param, sizeof(xts_param)); return ret; } From 701dc81e7412daaf3c5bf4bc55d35c8b1525112a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 19 Feb 2020 13:29:15 +0100 Subject: [PATCH 120/809] s390/mm: remove fake numa support It turned out that fake numa support is rather useless on s390, since there are no scenarios where there is any performance or other benefit when used. However it does provide maintenance cost and breaks from time to time. Therefore remove it. CONFIG_NUMA is still supported with a very small backend and only one node. This way userspace applications which require NUMA interfaces continue to work. Note that NODES_SHIFT is set to 1 (= 2 nodes) instead of 0 (= 1 node), since there is quite a bit of kernel code which assumes that more than one node is possible if CONFIG_NUMA is enabled. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 61 +--- arch/s390/include/asm/numa.h | 13 +- arch/s390/include/asm/topology.h | 9 +- arch/s390/kernel/setup.c | 1 + arch/s390/kernel/topology.c | 2 - arch/s390/numa/Makefile | 2 - arch/s390/numa/mode_emu.c | 577 ------------------------------- arch/s390/numa/numa.c | 147 +------- arch/s390/numa/numa_mode.h | 25 -- arch/s390/numa/toptree.c | 351 ------------------- arch/s390/numa/toptree.h | 61 ---- drivers/s390/char/sclp_cmd.c | 2 +- 12 files changed, 20 insertions(+), 1231 deletions(-) delete mode 100644 arch/s390/numa/mode_emu.c delete mode 100644 arch/s390/numa/numa_mode.h delete mode 100644 arch/s390/numa/toptree.c delete mode 100644 arch/s390/numa/toptree.h diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8abe77536d9d..6b1f715dd8bb 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -450,14 +450,6 @@ config NR_CPUS config HOTPLUG_CPU def_bool y -# Some NUMA nodes have memory ranges that span -# other nodes. Even though a pfn is valid and -# between a node's start and end pfns, it may not -# reside on that node. See memmap_init_zone() -# for details. <- They meant memory holes! -config NODES_SPAN_OTHER_NODES - def_bool NUMA - config NUMA bool "NUMA support" depends on SCHED_TOPOLOGY @@ -467,58 +459,9 @@ config NUMA This option adds NUMA support to the kernel. - An operation mode can be selected by appending - numa= to the kernel command line. - - The default behaviour is identical to appending numa=plain to - the command line. This will create just one node with all - available memory and all CPUs in it. - config NODES_SHIFT - int "Maximum NUMA nodes (as a power of 2)" - range 1 10 - depends on NUMA - default "4" - help - Specify the maximum number of NUMA nodes available on the target - system. Increases memory reserved to accommodate various tables. - -menu "Select NUMA modes" - depends on NUMA - -config NUMA_EMU - bool "NUMA emulation" - default y - help - Numa emulation mode will split the available system memory into - equal chunks which then are distributed over the configured number - of nodes in a round-robin manner. - - The number of fake nodes is limited by the number of available memory - chunks (i.e. memory size / fake size) and the number of supported - nodes in the kernel. - - The CPUs are assigned to the nodes in a way that partially respects - the original machine topology (if supported by the machine). - Fair distribution of the CPUs is not guaranteed. - -config EMU_SIZE - hex "NUMA emulation memory chunk size" - default 0x10000000 - range 0x400000 0x100000000 - depends on NUMA_EMU - help - Select the default size by which the memory is chopped and then - assigned to emulated NUMA nodes. - - This can be overridden by specifying - - emu_size= - - on the kernel command line where also suffixes K, M, G, and T are - supported. - -endmenu + int + default "1" config SCHED_SMT def_bool n diff --git a/arch/s390/include/asm/numa.h b/arch/s390/include/asm/numa.h index 35f8cbe7e5bb..23cd5d1b734b 100644 --- a/arch/s390/include/asm/numa.h +++ b/arch/s390/include/asm/numa.h @@ -13,24 +13,13 @@ #ifdef CONFIG_NUMA #include -#include void numa_setup(void); -int numa_pfn_to_nid(unsigned long pfn); -int __node_distance(int a, int b); -void numa_update_cpu_topology(void); - -extern cpumask_t node_to_cpumask_map[MAX_NUMNODES]; -extern int numa_debug_enabled; #else static inline void numa_setup(void) { } -static inline void numa_update_cpu_topology(void) { } -static inline int numa_pfn_to_nid(unsigned long pfn) -{ - return 0; -} #endif /* CONFIG_NUMA */ + #endif /* _ASM_S390_NUMA_H */ diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index cca406fdbe51..bd3417185e30 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -16,7 +16,6 @@ struct cpu_topology_s390 { unsigned short socket_id; unsigned short book_id; unsigned short drawer_id; - unsigned short node_id; unsigned short dedicated : 1; cpumask_t thread_mask; cpumask_t core_mask; @@ -71,19 +70,23 @@ static inline void topology_expect_change(void) { } #define cpu_to_node cpu_to_node static inline int cpu_to_node(int cpu) { - return cpu_topology[cpu].node_id; + return 0; } /* Returns a pointer to the cpumask of CPUs on node 'node'. */ #define cpumask_of_node cpumask_of_node static inline const struct cpumask *cpumask_of_node(int node) { - return &node_to_cpumask_map[node]; + return cpu_possible_mask; } #define pcibus_to_node(bus) __pcibus_to_node(bus) #define node_distance(a, b) __node_distance(a, b) +static inline int __node_distance(int a, int b) +{ + return 0; +} #else /* !CONFIG_NUMA */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index b2c2f75860e8..1158a63a8e0e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -790,6 +790,7 @@ static void __init memblock_add_mem_detect_info(void) memblock_physmem_add(start, end - start); } memblock_set_bottom_up(false); + memblock_set_node(0, ULONG_MAX, &memblock.memory, 0); memblock_dump_all(); } diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 3627953007ed..c189f5d996ff 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -26,7 +26,6 @@ #include #include #include -#include #define PTF_HORIZONTAL (0UL) #define PTF_VERTICAL (1UL) @@ -267,7 +266,6 @@ static void update_cpu_masks(void) cpumask_set_cpu(cpu, &cpus_with_topology); } } - numa_update_cpu_topology(); } void store_topology(struct sysinfo_15_1_x *info) diff --git a/arch/s390/numa/Makefile b/arch/s390/numa/Makefile index 66c2dff74895..c89d26f4f77d 100644 --- a/arch/s390/numa/Makefile +++ b/arch/s390/numa/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += numa.o -obj-y += toptree.o -obj-$(CONFIG_NUMA_EMU) += mode_emu.o diff --git a/arch/s390/numa/mode_emu.c b/arch/s390/numa/mode_emu.c deleted file mode 100644 index 72d742bb2d17..000000000000 --- a/arch/s390/numa/mode_emu.c +++ /dev/null @@ -1,577 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * NUMA support for s390 - * - * NUMA emulation (aka fake NUMA) distributes the available memory to nodes - * without using real topology information about the physical memory of the - * machine. - * - * It distributes the available CPUs to nodes while respecting the original - * machine topology information. This is done by trying to avoid to separate - * CPUs which reside on the same book or even on the same MC. - * - * Because the current Linux scheduler code requires a stable cpu to node - * mapping, cores are pinned to nodes when the first CPU thread is set online. - * - * Copyright IBM Corp. 2015 - */ - -#define KMSG_COMPONENT "numa_emu" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include "numa_mode.h" -#include "toptree.h" - -/* Distances between the different system components */ -#define DIST_EMPTY 0 -#define DIST_CORE 1 -#define DIST_MC 2 -#define DIST_BOOK 3 -#define DIST_DRAWER 4 -#define DIST_MAX 5 - -/* Node distance reported to common code */ -#define EMU_NODE_DIST 10 - -/* Node ID for free (not yet pinned) cores */ -#define NODE_ID_FREE -1 - -/* Different levels of toptree */ -enum toptree_level {CORE, MC, BOOK, DRAWER, NODE, TOPOLOGY}; - -/* The two toptree IDs */ -enum {TOPTREE_ID_PHYS, TOPTREE_ID_NUMA}; - -/* Number of NUMA nodes */ -static int emu_nodes = 1; -/* NUMA stripe size */ -static unsigned long emu_size; - -/* - * Node to core pinning information updates are protected by - * "sched_domains_mutex". - */ -static struct { - s32 to_node_id[CONFIG_NR_CPUS]; /* Pinned core to node mapping */ - int total; /* Total number of pinned cores */ - int per_node_target; /* Cores per node without extra cores */ - int per_node[MAX_NUMNODES]; /* Number of cores pinned to node */ -} *emu_cores; - -/* - * Pin a core to a node - */ -static void pin_core_to_node(int core_id, int node_id) -{ - if (emu_cores->to_node_id[core_id] == NODE_ID_FREE) { - emu_cores->per_node[node_id]++; - emu_cores->to_node_id[core_id] = node_id; - emu_cores->total++; - } else { - WARN_ON(emu_cores->to_node_id[core_id] != node_id); - } -} - -/* - * Number of pinned cores of a node - */ -static int cores_pinned(struct toptree *node) -{ - return emu_cores->per_node[node->id]; -} - -/* - * ID of the node where the core is pinned (or NODE_ID_FREE) - */ -static int core_pinned_to_node_id(struct toptree *core) -{ - return emu_cores->to_node_id[core->id]; -} - -/* - * Number of cores in the tree that are not yet pinned - */ -static int cores_free(struct toptree *tree) -{ - struct toptree *core; - int count = 0; - - toptree_for_each(core, tree, CORE) { - if (core_pinned_to_node_id(core) == NODE_ID_FREE) - count++; - } - return count; -} - -/* - * Return node of core - */ -static struct toptree *core_node(struct toptree *core) -{ - return core->parent->parent->parent->parent; -} - -/* - * Return drawer of core - */ -static struct toptree *core_drawer(struct toptree *core) -{ - return core->parent->parent->parent; -} - -/* - * Return book of core - */ -static struct toptree *core_book(struct toptree *core) -{ - return core->parent->parent; -} - -/* - * Return mc of core - */ -static struct toptree *core_mc(struct toptree *core) -{ - return core->parent; -} - -/* - * Distance between two cores - */ -static int dist_core_to_core(struct toptree *core1, struct toptree *core2) -{ - if (core_drawer(core1)->id != core_drawer(core2)->id) - return DIST_DRAWER; - if (core_book(core1)->id != core_book(core2)->id) - return DIST_BOOK; - if (core_mc(core1)->id != core_mc(core2)->id) - return DIST_MC; - /* Same core or sibling on same MC */ - return DIST_CORE; -} - -/* - * Distance of a node to a core - */ -static int dist_node_to_core(struct toptree *node, struct toptree *core) -{ - struct toptree *core_node; - int dist_min = DIST_MAX; - - toptree_for_each(core_node, node, CORE) - dist_min = min(dist_min, dist_core_to_core(core_node, core)); - return dist_min == DIST_MAX ? DIST_EMPTY : dist_min; -} - -/* - * Unify will delete empty nodes, therefore recreate nodes. - */ -static void toptree_unify_tree(struct toptree *tree) -{ - int nid; - - toptree_unify(tree); - for (nid = 0; nid < emu_nodes; nid++) - toptree_get_child(tree, nid); -} - -/* - * Find the best/nearest node for a given core and ensure that no node - * gets more than "emu_cores->per_node_target + extra" cores. - */ -static struct toptree *node_for_core(struct toptree *numa, struct toptree *core, - int extra) -{ - struct toptree *node, *node_best = NULL; - int dist_cur, dist_best, cores_target; - - cores_target = emu_cores->per_node_target + extra; - dist_best = DIST_MAX; - node_best = NULL; - toptree_for_each(node, numa, NODE) { - /* Already pinned cores must use their nodes */ - if (core_pinned_to_node_id(core) == node->id) { - node_best = node; - break; - } - /* Skip nodes that already have enough cores */ - if (cores_pinned(node) >= cores_target) - continue; - dist_cur = dist_node_to_core(node, core); - if (dist_cur < dist_best) { - dist_best = dist_cur; - node_best = node; - } - } - return node_best; -} - -/* - * Find the best node for each core with respect to "extra" core count - */ -static void toptree_to_numa_single(struct toptree *numa, struct toptree *phys, - int extra) -{ - struct toptree *node, *core, *tmp; - - toptree_for_each_safe(core, tmp, phys, CORE) { - node = node_for_core(numa, core, extra); - if (!node) - return; - toptree_move(core, node); - pin_core_to_node(core->id, node->id); - } -} - -/* - * Move structures of given level to specified NUMA node - */ -static void move_level_to_numa_node(struct toptree *node, struct toptree *phys, - enum toptree_level level, bool perfect) -{ - int cores_free, cores_target = emu_cores->per_node_target; - struct toptree *cur, *tmp; - - toptree_for_each_safe(cur, tmp, phys, level) { - cores_free = cores_target - toptree_count(node, CORE); - if (perfect) { - if (cores_free == toptree_count(cur, CORE)) - toptree_move(cur, node); - } else { - if (cores_free >= toptree_count(cur, CORE)) - toptree_move(cur, node); - } - } -} - -/* - * Move structures of a given level to NUMA nodes. If "perfect" is specified - * move only perfectly fitting structures. Otherwise move also smaller - * than needed structures. - */ -static void move_level_to_numa(struct toptree *numa, struct toptree *phys, - enum toptree_level level, bool perfect) -{ - struct toptree *node; - - toptree_for_each(node, numa, NODE) - move_level_to_numa_node(node, phys, level, perfect); -} - -/* - * For the first run try to move the big structures - */ -static void toptree_to_numa_first(struct toptree *numa, struct toptree *phys) -{ - struct toptree *core; - - /* Always try to move perfectly fitting structures first */ - move_level_to_numa(numa, phys, DRAWER, true); - move_level_to_numa(numa, phys, DRAWER, false); - move_level_to_numa(numa, phys, BOOK, true); - move_level_to_numa(numa, phys, BOOK, false); - move_level_to_numa(numa, phys, MC, true); - move_level_to_numa(numa, phys, MC, false); - /* Now pin all the moved cores */ - toptree_for_each(core, numa, CORE) - pin_core_to_node(core->id, core_node(core)->id); -} - -/* - * Allocate new topology and create required nodes - */ -static struct toptree *toptree_new(int id, int nodes) -{ - struct toptree *tree; - int nid; - - tree = toptree_alloc(TOPOLOGY, id); - if (!tree) - goto fail; - for (nid = 0; nid < nodes; nid++) { - if (!toptree_get_child(tree, nid)) - goto fail; - } - return tree; -fail: - panic("NUMA emulation could not allocate topology"); -} - -/* - * Allocate and initialize core to node mapping - */ -static void __ref create_core_to_node_map(void) -{ - int i; - - emu_cores = memblock_alloc(sizeof(*emu_cores), 8); - if (!emu_cores) - panic("%s: Failed to allocate %zu bytes align=0x%x\n", - __func__, sizeof(*emu_cores), 8); - for (i = 0; i < ARRAY_SIZE(emu_cores->to_node_id); i++) - emu_cores->to_node_id[i] = NODE_ID_FREE; -} - -/* - * Move cores from physical topology into NUMA target topology - * and try to keep as much of the physical topology as possible. - */ -static struct toptree *toptree_to_numa(struct toptree *phys) -{ - static int first = 1; - struct toptree *numa; - int cores_total; - - cores_total = emu_cores->total + cores_free(phys); - emu_cores->per_node_target = cores_total / emu_nodes; - numa = toptree_new(TOPTREE_ID_NUMA, emu_nodes); - if (first) { - toptree_to_numa_first(numa, phys); - first = 0; - } - toptree_to_numa_single(numa, phys, 0); - toptree_to_numa_single(numa, phys, 1); - toptree_unify_tree(numa); - - WARN_ON(cpumask_weight(&phys->mask)); - return numa; -} - -/* - * Create a toptree out of the physical topology that we got from the hypervisor - */ -static struct toptree *toptree_from_topology(void) -{ - struct toptree *phys, *node, *drawer, *book, *mc, *core; - struct cpu_topology_s390 *top; - int cpu; - - phys = toptree_new(TOPTREE_ID_PHYS, 1); - - for_each_cpu(cpu, &cpus_with_topology) { - top = &cpu_topology[cpu]; - node = toptree_get_child(phys, 0); - drawer = toptree_get_child(node, top->drawer_id); - book = toptree_get_child(drawer, top->book_id); - mc = toptree_get_child(book, top->socket_id); - core = toptree_get_child(mc, smp_get_base_cpu(cpu)); - if (!drawer || !book || !mc || !core) - panic("NUMA emulation could not allocate memory"); - cpumask_set_cpu(cpu, &core->mask); - toptree_update_mask(mc); - } - return phys; -} - -/* - * Add toptree core to topology and create correct CPU masks - */ -static void topology_add_core(struct toptree *core) -{ - struct cpu_topology_s390 *top; - int cpu; - - for_each_cpu(cpu, &core->mask) { - top = &cpu_topology[cpu]; - cpumask_copy(&top->thread_mask, &core->mask); - cpumask_copy(&top->core_mask, &core_mc(core)->mask); - cpumask_copy(&top->book_mask, &core_book(core)->mask); - cpumask_copy(&top->drawer_mask, &core_drawer(core)->mask); - cpumask_set_cpu(cpu, &node_to_cpumask_map[core_node(core)->id]); - top->node_id = core_node(core)->id; - } -} - -/* - * Apply toptree to topology and create CPU masks - */ -static void toptree_to_topology(struct toptree *numa) -{ - struct toptree *core; - int i; - - /* Clear all node masks */ - for (i = 0; i < MAX_NUMNODES; i++) - cpumask_clear(&node_to_cpumask_map[i]); - - /* Rebuild all masks */ - toptree_for_each(core, numa, CORE) - topology_add_core(core); -} - -/* - * Show the node to core mapping - */ -static void print_node_to_core_map(void) -{ - int nid, cid; - - if (!numa_debug_enabled) - return; - printk(KERN_DEBUG "NUMA node to core mapping\n"); - for (nid = 0; nid < emu_nodes; nid++) { - printk(KERN_DEBUG " node %3d: ", nid); - for (cid = 0; cid < ARRAY_SIZE(emu_cores->to_node_id); cid++) { - if (emu_cores->to_node_id[cid] == nid) - printk(KERN_CONT "%d ", cid); - } - printk(KERN_CONT "\n"); - } -} - -static void pin_all_possible_cpus(void) -{ - int core_id, node_id, cpu; - static int initialized; - - if (initialized) - return; - print_node_to_core_map(); - node_id = 0; - for_each_possible_cpu(cpu) { - core_id = smp_get_base_cpu(cpu); - if (emu_cores->to_node_id[core_id] != NODE_ID_FREE) - continue; - pin_core_to_node(core_id, node_id); - cpu_topology[cpu].node_id = node_id; - node_id = (node_id + 1) % emu_nodes; - } - print_node_to_core_map(); - initialized = 1; -} - -/* - * Transfer physical topology into a NUMA topology and modify CPU masks - * according to the NUMA topology. - * - * Must be called with "sched_domains_mutex" lock held. - */ -static void emu_update_cpu_topology(void) -{ - struct toptree *phys, *numa; - - if (emu_cores == NULL) - create_core_to_node_map(); - phys = toptree_from_topology(); - numa = toptree_to_numa(phys); - toptree_free(phys); - toptree_to_topology(numa); - toptree_free(numa); - pin_all_possible_cpus(); -} - -/* - * If emu_size is not set, use CONFIG_EMU_SIZE. Then round to minimum - * alignment (needed for memory hotplug). - */ -static unsigned long emu_setup_size_adjust(unsigned long size) -{ - unsigned long size_new; - - size = size ? : CONFIG_EMU_SIZE; - size_new = roundup(size, memory_block_size_bytes()); - if (size_new == size) - return size; - pr_warn("Increasing memory stripe size from %ld MB to %ld MB\n", - size >> 20, size_new >> 20); - return size_new; -} - -/* - * If we have not enough memory for the specified nodes, reduce the node count. - */ -static int emu_setup_nodes_adjust(int nodes) -{ - int nodes_max; - - nodes_max = memblock.memory.total_size / emu_size; - nodes_max = max(nodes_max, 1); - if (nodes_max >= nodes) - return nodes; - pr_warn("Not enough memory for %d nodes, reducing node count\n", nodes); - return nodes_max; -} - -/* - * Early emu setup - */ -static void emu_setup(void) -{ - int nid; - - emu_size = emu_setup_size_adjust(emu_size); - emu_nodes = emu_setup_nodes_adjust(emu_nodes); - for (nid = 0; nid < emu_nodes; nid++) - node_set(nid, node_possible_map); - pr_info("Creating %d nodes with memory stripe size %ld MB\n", - emu_nodes, emu_size >> 20); -} - -/* - * Return node id for given page number - */ -static int emu_pfn_to_nid(unsigned long pfn) -{ - return (pfn / (emu_size >> PAGE_SHIFT)) % emu_nodes; -} - -/* - * Return stripe size - */ -static unsigned long emu_align(void) -{ - return emu_size; -} - -/* - * Return distance between two nodes - */ -static int emu_distance(int node1, int node2) -{ - return (node1 != node2) * EMU_NODE_DIST; -} - -/* - * Define callbacks for generic s390 NUMA infrastructure - */ -const struct numa_mode numa_mode_emu = { - .name = "emu", - .setup = emu_setup, - .update_cpu_topology = emu_update_cpu_topology, - .__pfn_to_nid = emu_pfn_to_nid, - .align = emu_align, - .distance = emu_distance, -}; - -/* - * Kernel parameter: emu_nodes= - */ -static int __init early_parse_emu_nodes(char *p) -{ - int count; - - if (!p || kstrtoint(p, 0, &count) != 0 || count <= 0) - return 0; - emu_nodes = min(count, MAX_NUMNODES); - return 0; -} -early_param("emu_nodes", early_parse_emu_nodes); - -/* - * Kernel parameter: emu_size=[[k|M|G|T]] - */ -static int __init early_parse_emu_size(char *p) -{ - if (p) - emu_size = memparse(p, NULL); - return 0; -} -early_param("emu_size", early_parse_emu_size); diff --git a/arch/s390/numa/numa.c b/arch/s390/numa/numa.c index d2910fa834c8..51c5a9f6e525 100644 --- a/arch/s390/numa/numa.c +++ b/arch/s390/numa/numa.c @@ -7,165 +7,36 @@ * Copyright IBM Corp. 2015 */ -#define KMSG_COMPONENT "numa" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - #include #include #include #include -#include #include - #include -#include "numa_mode.h" -pg_data_t *node_data[MAX_NUMNODES]; +struct pglist_data *node_data[MAX_NUMNODES]; EXPORT_SYMBOL(node_data); -cpumask_t node_to_cpumask_map[MAX_NUMNODES]; -EXPORT_SYMBOL(node_to_cpumask_map); - -static void plain_setup(void) +void __init numa_setup(void) { + int nid; + + nodes_clear(node_possible_map); node_set(0, node_possible_map); -} - -const struct numa_mode numa_mode_plain = { - .name = "plain", - .setup = plain_setup, -}; - -static const struct numa_mode *mode = &numa_mode_plain; - -int numa_pfn_to_nid(unsigned long pfn) -{ - return mode->__pfn_to_nid ? mode->__pfn_to_nid(pfn) : 0; -} - -void numa_update_cpu_topology(void) -{ - if (mode->update_cpu_topology) - mode->update_cpu_topology(); -} - -int __node_distance(int a, int b) -{ - return mode->distance ? mode->distance(a, b) : 0; -} -EXPORT_SYMBOL(__node_distance); - -int numa_debug_enabled; - -/* - * numa_setup_memory() - Assign bootmem to nodes - * - * The memory is first added to memblock without any respect to nodes. - * This is fixed before remaining memblock memory is handed over to the - * buddy allocator. - * An important side effect is that large bootmem allocations might easily - * cross node boundaries, which can be needed for large allocations with - * smaller memory stripes in each node (i.e. when using NUMA emulation). - * - * Memory defines nodes: - * Therefore this routine also sets the nodes online with memory. - */ -static void __init numa_setup_memory(void) -{ - unsigned long cur_base, align, end_of_dram; - int nid = 0; - - end_of_dram = memblock_end_of_DRAM(); - align = mode->align ? mode->align() : ULONG_MAX; - - /* - * Step through all available memory and assign it to the nodes - * indicated by the mode implementation. - * All nodes which are seen here will be set online. - */ - cur_base = 0; - do { - nid = numa_pfn_to_nid(PFN_DOWN(cur_base)); - node_set_online(nid); - memblock_set_node(cur_base, align, &memblock.memory, nid); - cur_base += align; - } while (cur_base < end_of_dram); - - /* Allocate and fill out node_data */ + node_set_online(0); for (nid = 0; nid < MAX_NUMNODES; nid++) { NODE_DATA(nid) = memblock_alloc(sizeof(pg_data_t), 8); if (!NODE_DATA(nid)) panic("%s: Failed to allocate %zu bytes align=0x%x\n", __func__, sizeof(pg_data_t), 8); } - - for_each_online_node(nid) { - unsigned long start_pfn, end_pfn; - unsigned long t_start, t_end; - int i; - - start_pfn = ULONG_MAX; - end_pfn = 0; - for_each_mem_pfn_range(i, nid, &t_start, &t_end, NULL) { - if (t_start < start_pfn) - start_pfn = t_start; - if (t_end > end_pfn) - end_pfn = t_end; - } - NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn; - NODE_DATA(nid)->node_id = nid; - } + NODE_DATA(0)->node_spanned_pages = memblock_end_of_DRAM() >> PAGE_SHIFT; + NODE_DATA(0)->node_id = 0; } -/* - * numa_setup() - Earliest initialization - * - * Assign the mode and call the mode's setup routine. - */ -void __init numa_setup(void) -{ - pr_info("NUMA mode: %s\n", mode->name); - nodes_clear(node_possible_map); - /* Initially attach all possible CPUs to node 0. */ - cpumask_copy(&node_to_cpumask_map[0], cpu_possible_mask); - if (mode->setup) - mode->setup(); - numa_setup_memory(); - memblock_dump_all(); -} - -/* - * numa_init_late() - Initialization initcall - * - * Register NUMA nodes. - */ static int __init numa_init_late(void) { - int nid; - - for_each_online_node(nid) - register_one_node(nid); + register_one_node(0); return 0; } arch_initcall(numa_init_late); - -static int __init parse_debug(char *parm) -{ - numa_debug_enabled = 1; - return 0; -} -early_param("numa_debug", parse_debug); - -static int __init parse_numa(char *parm) -{ - if (!parm) - return 1; - if (strcmp(parm, numa_mode_plain.name) == 0) - mode = &numa_mode_plain; -#ifdef CONFIG_NUMA_EMU - if (strcmp(parm, numa_mode_emu.name) == 0) - mode = &numa_mode_emu; -#endif - return 0; -} -early_param("numa", parse_numa); diff --git a/arch/s390/numa/numa_mode.h b/arch/s390/numa/numa_mode.h deleted file mode 100644 index dfd3e2784081..000000000000 --- a/arch/s390/numa/numa_mode.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * NUMA support for s390 - * - * Define declarations used for communication between NUMA mode - * implementations and NUMA core functionality. - * - * Copyright IBM Corp. 2015 - */ -#ifndef __S390_NUMA_MODE_H -#define __S390_NUMA_MODE_H - -struct numa_mode { - char *name; /* Name of mode */ - void (*setup)(void); /* Initizalize mode */ - void (*update_cpu_topology)(void); /* Called by topology code */ - int (*__pfn_to_nid)(unsigned long pfn); /* PFN to node ID */ - unsigned long (*align)(void); /* Minimum node alignment */ - int (*distance)(int a, int b); /* Distance between two nodes */ -}; - -extern const struct numa_mode numa_mode_plain; -extern const struct numa_mode numa_mode_emu; - -#endif /* __S390_NUMA_MODE_H */ diff --git a/arch/s390/numa/toptree.c b/arch/s390/numa/toptree.c deleted file mode 100644 index 71a608cd4f61..000000000000 --- a/arch/s390/numa/toptree.c +++ /dev/null @@ -1,351 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * NUMA support for s390 - * - * A tree structure used for machine topology mangling - * - * Copyright IBM Corp. 2015 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "toptree.h" - -/** - * toptree_alloc - Allocate and initialize a new tree node. - * @level: The node's vertical level; level 0 contains the leaves. - * @id: ID number, explicitly not unique beyond scope of node's siblings - * - * Allocate a new tree node and initialize it. - * - * RETURNS: - * Pointer to the new tree node or NULL on error - */ -struct toptree __ref *toptree_alloc(int level, int id) -{ - struct toptree *res; - - if (slab_is_available()) - res = kzalloc(sizeof(*res), GFP_KERNEL); - else - res = memblock_alloc(sizeof(*res), 8); - if (!res) - return res; - - INIT_LIST_HEAD(&res->children); - INIT_LIST_HEAD(&res->sibling); - cpumask_clear(&res->mask); - res->level = level; - res->id = id; - return res; -} - -/** - * toptree_remove - Remove a tree node from a tree - * @cand: Pointer to the node to remove - * - * The node is detached from its parent node. The parent node's - * masks will be updated to reflect the loss of the child. - */ -static void toptree_remove(struct toptree *cand) -{ - struct toptree *oldparent; - - list_del_init(&cand->sibling); - oldparent = cand->parent; - cand->parent = NULL; - toptree_update_mask(oldparent); -} - -/** - * toptree_free - discard a tree node - * @cand: Pointer to the tree node to discard - * - * Checks if @cand is attached to a parent node. Detaches it - * cleanly using toptree_remove. Possible children are freed - * recursively. In the end @cand itself is freed. - */ -void __ref toptree_free(struct toptree *cand) -{ - struct toptree *child, *tmp; - - if (cand->parent) - toptree_remove(cand); - toptree_for_each_child_safe(child, tmp, cand) - toptree_free(child); - if (slab_is_available()) - kfree(cand); - else - memblock_free_early((unsigned long)cand, sizeof(*cand)); -} - -/** - * toptree_update_mask - Update node bitmasks - * @cand: Pointer to a tree node - * - * The node's cpumask will be updated by combining all children's - * masks. Then toptree_update_mask is called recursively for the - * parent if applicable. - * - * NOTE: - * This must not be called on leaves. If called on a leaf, its - * CPU mask is cleared and lost. - */ -void toptree_update_mask(struct toptree *cand) -{ - struct toptree *child; - - cpumask_clear(&cand->mask); - list_for_each_entry(child, &cand->children, sibling) - cpumask_or(&cand->mask, &cand->mask, &child->mask); - if (cand->parent) - toptree_update_mask(cand->parent); -} - -/** - * toptree_insert - Insert a tree node into tree - * @cand: Pointer to the node to insert - * @target: Pointer to the node to which @cand will added as a child - * - * Insert a tree node into a tree. Masks will be updated automatically. - * - * RETURNS: - * 0 on success, -1 if NULL is passed as argument or the node levels - * don't fit. - */ -static int toptree_insert(struct toptree *cand, struct toptree *target) -{ - if (!cand || !target) - return -1; - if (target->level != (cand->level + 1)) - return -1; - list_add_tail(&cand->sibling, &target->children); - cand->parent = target; - toptree_update_mask(target); - return 0; -} - -/** - * toptree_move_children - Move all child nodes of a node to a new place - * @cand: Pointer to the node whose children are to be moved - * @target: Pointer to the node to which @cand's children will be attached - * - * Take all child nodes of @cand and move them using toptree_move. - */ -static void toptree_move_children(struct toptree *cand, struct toptree *target) -{ - struct toptree *child, *tmp; - - toptree_for_each_child_safe(child, tmp, cand) - toptree_move(child, target); -} - -/** - * toptree_unify - Merge children with same ID - * @cand: Pointer to node whose direct children should be made unique - * - * When mangling the tree it is possible that a node has two or more children - * which have the same ID. This routine merges these children into one and - * moves all children of the merged nodes into the unified node. - */ -void toptree_unify(struct toptree *cand) -{ - struct toptree *child, *tmp, *cand_copy; - - /* Threads cannot be split, cores are not split */ - if (cand->level < 2) - return; - - cand_copy = toptree_alloc(cand->level, 0); - toptree_for_each_child_safe(child, tmp, cand) { - struct toptree *tmpchild; - - if (!cpumask_empty(&child->mask)) { - tmpchild = toptree_get_child(cand_copy, child->id); - toptree_move_children(child, tmpchild); - } - toptree_free(child); - } - toptree_move_children(cand_copy, cand); - toptree_free(cand_copy); - - toptree_for_each_child(child, cand) - toptree_unify(child); -} - -/** - * toptree_move - Move a node to another context - * @cand: Pointer to the node to move - * @target: Pointer to the node where @cand should go - * - * In the easiest case @cand is exactly on the level below @target - * and will be immediately moved to the target. - * - * If @target's level is not the direct parent level of @cand, - * nodes for the missing levels are created and put between - * @cand and @target. The "stacking" nodes' IDs are taken from - * @cand's parents. - * - * After this it is likely to have redundant nodes in the tree - * which are addressed by means of toptree_unify. - */ -void toptree_move(struct toptree *cand, struct toptree *target) -{ - struct toptree *stack_target, *real_insert_point, *ptr, *tmp; - - if (cand->level + 1 == target->level) { - toptree_remove(cand); - toptree_insert(cand, target); - return; - } - - real_insert_point = NULL; - ptr = cand; - stack_target = NULL; - - do { - tmp = stack_target; - stack_target = toptree_alloc(ptr->level + 1, - ptr->parent->id); - toptree_insert(tmp, stack_target); - if (!real_insert_point) - real_insert_point = stack_target; - ptr = ptr->parent; - } while (stack_target->level < (target->level - 1)); - - toptree_remove(cand); - toptree_insert(cand, real_insert_point); - toptree_insert(stack_target, target); -} - -/** - * toptree_get_child - Access a tree node's child by its ID - * @cand: Pointer to tree node whose child is to access - * @id: The desired child's ID - * - * @cand's children are searched for a child with matching ID. - * If no match can be found, a new child with the desired ID - * is created and returned. - */ -struct toptree *toptree_get_child(struct toptree *cand, int id) -{ - struct toptree *child; - - toptree_for_each_child(child, cand) - if (child->id == id) - return child; - child = toptree_alloc(cand->level-1, id); - toptree_insert(child, cand); - return child; -} - -/** - * toptree_first - Find the first descendant on specified level - * @context: Pointer to tree node whose descendants are to be used - * @level: The level of interest - * - * RETURNS: - * @context's first descendant on the specified level, or NULL - * if there is no matching descendant - */ -struct toptree *toptree_first(struct toptree *context, int level) -{ - struct toptree *child, *tmp; - - if (context->level == level) - return context; - - if (!list_empty(&context->children)) { - list_for_each_entry(child, &context->children, sibling) { - tmp = toptree_first(child, level); - if (tmp) - return tmp; - } - } - return NULL; -} - -/** - * toptree_next_sibling - Return next sibling - * @cur: Pointer to a tree node - * - * RETURNS: - * If @cur has a parent and is not the last in the parent's children list, - * the next sibling is returned. Or NULL when there are no siblings left. - */ -static struct toptree *toptree_next_sibling(struct toptree *cur) -{ - if (cur->parent == NULL) - return NULL; - - if (cur == list_last_entry(&cur->parent->children, - struct toptree, sibling)) - return NULL; - return (struct toptree *) list_next_entry(cur, sibling); -} - -/** - * toptree_next - Tree traversal function - * @cur: Pointer to current element - * @context: Pointer to the root node of the tree or subtree to - * be traversed. - * @level: The level of interest. - * - * RETURNS: - * Pointer to the next node on level @level - * or NULL when there is no next node. - */ -struct toptree *toptree_next(struct toptree *cur, struct toptree *context, - int level) -{ - struct toptree *cur_context, *tmp; - - if (!cur) - return NULL; - - if (context->level == level) - return NULL; - - tmp = toptree_next_sibling(cur); - if (tmp != NULL) - return tmp; - - cur_context = cur; - while (cur_context->level < context->level - 1) { - /* Step up */ - cur_context = cur_context->parent; - /* Step aside */ - tmp = toptree_next_sibling(cur_context); - if (tmp != NULL) { - /* Step down */ - tmp = toptree_first(tmp, level); - if (tmp != NULL) - return tmp; - } - } - return NULL; -} - -/** - * toptree_count - Count descendants on specified level - * @context: Pointer to node whose descendants are to be considered - * @level: Only descendants on the specified level will be counted - * - * RETURNS: - * Number of descendants on the specified level - */ -int toptree_count(struct toptree *context, int level) -{ - struct toptree *cur; - int cnt = 0; - - toptree_for_each(cur, context, level) - cnt++; - return cnt; -} diff --git a/arch/s390/numa/toptree.h b/arch/s390/numa/toptree.h deleted file mode 100644 index 5246371ec713..000000000000 --- a/arch/s390/numa/toptree.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * NUMA support for s390 - * - * A tree structure used for machine topology mangling - * - * Copyright IBM Corp. 2015 - */ -#ifndef S390_TOPTREE_H -#define S390_TOPTREE_H - -#include -#include - -struct toptree { - int level; - int id; - cpumask_t mask; - struct toptree *parent; - struct list_head sibling; - struct list_head children; -}; - -struct toptree *toptree_alloc(int level, int id); -void toptree_free(struct toptree *cand); -void toptree_update_mask(struct toptree *cand); -void toptree_unify(struct toptree *cand); -struct toptree *toptree_get_child(struct toptree *cand, int id); -void toptree_move(struct toptree *cand, struct toptree *target); -int toptree_count(struct toptree *context, int level); - -struct toptree *toptree_first(struct toptree *context, int level); -struct toptree *toptree_next(struct toptree *cur, struct toptree *context, - int level); - -#define toptree_for_each_child(child, ptree) \ - list_for_each_entry(child, &ptree->children, sibling) - -#define toptree_for_each_child_safe(child, ptmp, ptree) \ - list_for_each_entry_safe(child, ptmp, &ptree->children, sibling) - -#define toptree_is_last(ptree) \ - ((ptree->parent == NULL) || \ - (ptree->parent->children.prev == &ptree->sibling)) - -#define toptree_for_each(ptree, cont, ttype) \ - for (ptree = toptree_first(cont, ttype); \ - ptree != NULL; \ - ptree = toptree_next(ptree, cont, ttype)) - -#define toptree_for_each_safe(ptree, tmp, cont, ttype) \ - for (ptree = toptree_first(cont, ttype), \ - tmp = toptree_next(ptree, cont, ttype); \ - ptree != NULL; \ - ptree = tmp, \ - tmp = toptree_next(ptree, cont, ttype)) - -#define toptree_for_each_sibling(ptree, start) \ - toptree_for_each(ptree, start->parent, start->level) - -#endif /* S390_TOPTREE_H */ diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 37d42de06079..a864b21af602 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -406,7 +406,7 @@ static void __init add_memory_merged(u16 rn) if (!size) goto skip_add; for (addr = start; addr < start + size; addr += block_size) - add_memory(numa_pfn_to_nid(PFN_DOWN(addr)), addr, block_size); + add_memory(0, addr, block_size); skip_add: first_rn = rn; num = 1; From 5cbe0f13b51ac2fb2fd55902cff8d0077fc084c0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 10 Feb 2020 13:00:12 +0000 Subject: [PATCH 121/809] random: split primary/secondary crng init paths Currently crng_initialize() is used for both the primary CRNG and secondary CRNGs. While we wish to share common logic, we need to do a number of additional things for the primary CRNG, and this would be easier to deal with were these handled in separate functions. This patch splits crng_initialize() into crng_initialize_primary() and crng_initialize_secondary(), with common logic factored out into a crng_init_try_arch() helper. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland Cc: Mark Brown Cc: Theodore Ts'o Link: https://lore.kernel.org/r/20200210130015.17664-2-mark.rutland@arm.com Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c7f9584de2c8..62d32e62f2da 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -781,27 +781,37 @@ static int __init parse_trust_cpu(char *arg) } early_param("random.trust_cpu", parse_trust_cpu); -static void crng_initialize(struct crng_state *crng) +static bool crng_init_try_arch(struct crng_state *crng) { int i; - int arch_init = 1; + bool arch_init = true; unsigned long rv; - memcpy(&crng->state[0], "expand 32-byte k", 16); - if (crng == &primary_crng) - _extract_entropy(&input_pool, &crng->state[4], - sizeof(__u32) * 12, 0); - else - _get_random_bytes(&crng->state[4], sizeof(__u32) * 12); for (i = 4; i < 16; i++) { if (!arch_get_random_seed_long(&rv) && !arch_get_random_long(&rv)) { rv = random_get_entropy(); - arch_init = 0; + arch_init = false; } crng->state[i] ^= rv; } - if (trust_cpu && arch_init && crng == &primary_crng) { + + return arch_init; +} + +static void crng_initialize_secondary(struct crng_state *crng) +{ + memcpy(&crng->state[0], "expand 32-byte k", 16); + _get_random_bytes(&crng->state[4], sizeof(__u32) * 12); + crng_init_try_arch(crng); + crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; +} + +static void __init crng_initialize_primary(struct crng_state *crng) +{ + memcpy(&crng->state[0], "expand 32-byte k", 16); + _extract_entropy(&input_pool, &crng->state[4], sizeof(__u32) * 12, 0); + if (crng_init_try_arch(crng) && trust_cpu) { invalidate_batched_entropy(); numa_crng_init(); crng_init = 2; @@ -822,7 +832,7 @@ static void do_numa_crng_init(struct work_struct *work) crng = kmalloc_node(sizeof(struct crng_state), GFP_KERNEL | __GFP_NOFAIL, i); spin_lock_init(&crng->lock); - crng_initialize(crng); + crng_initialize_secondary(crng); pool[i] = crng; } mb(); @@ -1771,7 +1781,7 @@ static void __init init_std_data(struct entropy_store *r) int __init rand_initialize(void) { init_std_data(&input_pool); - crng_initialize(&primary_crng); + crng_initialize_primary(&primary_crng); crng_global_init_time = jiffies; if (ratelimit_disable) { urandom_warning.interval = 0; From 253d3194c2b58152fe830fd27c2fd83ebc6fe5ee Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 10 Feb 2020 13:00:13 +0000 Subject: [PATCH 122/809] random: add arch_get_random_*long_early() Some architectures (e.g. arm64) can have heterogeneous CPUs, and the boot CPU may be able to provide entropy while secondary CPUs cannot. On such systems, arch_get_random_long() and arch_get_random_seed_long() will fail unless support for RNG instructions has been detected on all CPUs. This prevents the boot CPU from being able to provide (potentially) trusted entropy when seeding the primary CRNG. To make it possible to seed the primary CRNG from the boot CPU without adversely affecting the runtime versions of arch_get_random_long() and arch_get_random_seed_long(), this patch adds new early versions of the functions used when initializing the primary CRNG. Default implementations are provided atop of the existing arch_get_random_long() and arch_get_random_seed_long() so that only architectures with such constraints need to provide the new helpers. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland Cc: Mark Brown Cc: Theodore Ts'o Link: https://lore.kernel.org/r/20200210130015.17664-3-mark.rutland@arm.com Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 20 +++++++++++++++++++- include/linux/random.h | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 62d32e62f2da..02a85b87b993 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -799,6 +799,24 @@ static bool crng_init_try_arch(struct crng_state *crng) return arch_init; } +static bool __init crng_init_try_arch_early(struct crng_state *crng) +{ + int i; + bool arch_init = true; + unsigned long rv; + + for (i = 4; i < 16; i++) { + if (!arch_get_random_seed_long_early(&rv) && + !arch_get_random_long_early(&rv)) { + rv = random_get_entropy(); + arch_init = false; + } + crng->state[i] ^= rv; + } + + return arch_init; +} + static void crng_initialize_secondary(struct crng_state *crng) { memcpy(&crng->state[0], "expand 32-byte k", 16); @@ -811,7 +829,7 @@ static void __init crng_initialize_primary(struct crng_state *crng) { memcpy(&crng->state[0], "expand 32-byte k", 16); _extract_entropy(&input_pool, &crng->state[4], sizeof(__u32) * 12, 0); - if (crng_init_try_arch(crng) && trust_cpu) { + if (crng_init_try_arch_early(crng) && trust_cpu) { invalidate_batched_entropy(); numa_crng_init(); crng_init = 2; diff --git a/include/linux/random.h b/include/linux/random.h index d319f9a1e429..45e1f8fa742b 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -7,6 +7,8 @@ #ifndef _LINUX_RANDOM_H #define _LINUX_RANDOM_H +#include +#include #include #include @@ -185,6 +187,26 @@ static inline bool __must_check arch_get_random_seed_int(unsigned int *v) } #endif +/* + * Called from the boot CPU during startup; not valid to call once + * secondary CPUs are up and preemption is possible. + */ +#ifndef arch_get_random_seed_long_early +static inline bool __init arch_get_random_seed_long_early(unsigned long *v) +{ + WARN_ON(system_state != SYSTEM_BOOTING); + return arch_get_random_seed_long(v); +} +#endif + +#ifndef arch_get_random_long_early +static inline bool __init arch_get_random_long_early(unsigned long *v) +{ + WARN_ON(system_state != SYSTEM_BOOTING); + return arch_get_random_long(v); +} +#endif + /* Pseudo random number generator from numerical recipes. */ static inline u32 next_pseudo_random32(u32 seed) { From ead5084cdf5af51445d219800c2ac8b01eb85f2f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 10 Feb 2020 13:00:14 +0000 Subject: [PATCH 123/809] arm64: add credited/trusted RNG support Currently arm64 doesn't initialize the primary CRNG in a (potentially) trusted manner as we only detect the presence of the RNG once secondary CPUs are up. Now that the core RNG code distinguishes the early initialization of the primary CRNG, we can implement arch_get_random_seed_long_early() to support this. This patch does so. Signed-off-by: Mark Rutland Cc: Catalin Marinas Cc: Mark Brown Cc: Theodore Ts'o Cc: Will Deacon Link: https://lore.kernel.org/r/20200210130015.17664-4-mark.rutland@arm.com Signed-off-by: Theodore Ts'o --- arch/arm64/include/asm/archrandom.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h index 3fe02da70004..fc1594a0710e 100644 --- a/arch/arm64/include/asm/archrandom.h +++ b/arch/arm64/include/asm/archrandom.h @@ -4,6 +4,8 @@ #ifdef CONFIG_ARCH_RANDOM +#include +#include #include #include @@ -66,6 +68,18 @@ static inline bool __init __early_cpu_has_rndr(void) return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf; } +static inline bool __init __must_check +arch_get_random_seed_long_early(unsigned long *v) +{ + WARN_ON(system_state != SYSTEM_BOOTING); + + if (!__early_cpu_has_rndr()) + return false; + + return __arm64_rndr(v); +} +#define arch_get_random_seed_long_early arch_get_random_seed_long_early + #else static inline bool __arm64_rndr(unsigned long *v) { return false; } From 23ae0c17b89cfeb511aa0770735a319d35597072 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Feb 2020 13:00:15 +0000 Subject: [PATCH 124/809] random: Make RANDOM_TRUST_CPU depend on ARCH_RANDOM Listing the set of host architectures does not scale. Depend instead on the existence of the architecture rng. This will allow RANDOM_TRUST_CPU to be selected on arm64. Today ARCH_RANDOM is only selected by x86, s390, and powerpc, so this does not adversely affect other architectures. Signed-off-by: Richard Henderson Signed-off-by: Mark Rutland Link: https://lore.kernel.org/r/20200210130015.17664-5-mark.rutland@arm.com Signed-off-by: Theodore Ts'o --- drivers/char/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 26956c006987..84207d5a9bb0 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -539,7 +539,7 @@ endmenu config RANDOM_TRUST_CPU bool "Trust the CPU manufacturer to initialize Linux's CRNG" - depends on X86 || S390 || PPC + depends on ARCH_RANDOM default n help Assume that CPU manufacturer (e.g., Intel or AMD for RDSEED or From 69efea712f5b0489e67d07565aad5c94e09a3e52 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 21 Feb 2020 21:10:37 +0100 Subject: [PATCH 125/809] random: always use batched entropy for get_random_u{32,64} It turns out that RDRAND is pretty slow. Comparing these two constructions: for (i = 0; i < CHACHA_BLOCK_SIZE; i += sizeof(ret)) arch_get_random_long(&ret); and long buf[CHACHA_BLOCK_SIZE / sizeof(long)]; extract_crng((u8 *)buf); it amortizes out to 352 cycles per long for the top one and 107 cycles per long for the bottom one, on Coffee Lake Refresh, Intel Core i9-9880H. And importantly, the top one has the drawback of not benefiting from the real rng, whereas the bottom one has all the nice benefits of using our own chacha rng. As get_random_u{32,64} gets used in more places (perhaps beyond what it was originally intended for when it was introduced as get_random_{int,long} back in the md5 monstrosity era), it seems like it might be a good thing to strengthen its posture a tiny bit. Doing this should only be stronger and not any weaker because that pool is already initialized with a bunch of rdrand data (when available). This way, we get the benefits of the hardware rng as well as our own rng. Another benefit of this is that we no longer hit pitfalls of the recent stream of AMD bugs in RDRAND. One often used code pattern for various things is: do { val = get_random_u32(); } while (hash_table_contains_key(val)); That recent AMD bug rendered that pattern useless, whereas we're really very certain that chacha20 output will give pretty distributed numbers, no matter what. So, this simplification seems better both from a security perspective and from a performance perspective. Signed-off-by: Jason A. Donenfeld Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20200221201037.30231-1-Jason@zx2c4.com Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 02a85b87b993..c33e7a3cdb13 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2177,11 +2177,11 @@ struct batched_entropy { /* * Get a random word for internal kernel use only. The quality of the random - * number is either as good as RDRAND or as good as /dev/urandom, with the - * goal of being quite fast and not depleting entropy. In order to ensure + * number is good as /dev/urandom, but there is no backtrack protection, with + * the goal of being quite fast and not depleting entropy. In order to ensure * that the randomness provided by this function is okay, the function - * wait_for_random_bytes() should be called and return 0 at least once - * at any point prior. + * wait_for_random_bytes() should be called and return 0 at least once at any + * point prior. */ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = { .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock), @@ -2194,15 +2194,6 @@ u64 get_random_u64(void) struct batched_entropy *batch; static void *previous; -#if BITS_PER_LONG == 64 - if (arch_get_random_long((unsigned long *)&ret)) - return ret; -#else - if (arch_get_random_long((unsigned long *)&ret) && - arch_get_random_long((unsigned long *)&ret + 1)) - return ret; -#endif - warn_unseeded_randomness(&previous); batch = raw_cpu_ptr(&batched_entropy_u64); @@ -2227,9 +2218,6 @@ u32 get_random_u32(void) struct batched_entropy *batch; static void *previous; - if (arch_get_random_int(&ret)) - return ret; - warn_unseeded_randomness(&previous); batch = raw_cpu_ptr(&batched_entropy_u32); From e00d996a4317aff5351c4338dd97d390225412c2 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Tue, 25 Feb 2020 11:27:04 -0500 Subject: [PATCH 126/809] random: fix data races at timer_rand_state Fields in "struct timer_rand_state" could be accessed concurrently. Lockless plain reads and writes result in data races. Fix them by adding pairs of READ|WRITE_ONCE(). The data races were reported by KCSAN, BUG: KCSAN: data-race in add_timer_randomness / add_timer_randomness write to 0xffff9f320a0a01d0 of 8 bytes by interrupt on cpu 22: add_timer_randomness+0x100/0x190 add_timer_randomness at drivers/char/random.c:1152 add_disk_randomness+0x85/0x280 scsi_end_request+0x43a/0x4a0 scsi_io_completion+0xb7/0x7e0 scsi_finish_command+0x1ed/0x2a0 scsi_softirq_done+0x1c9/0x1d0 blk_done_softirq+0x181/0x1d0 __do_softirq+0xd9/0x57c irq_exit+0xa2/0xc0 do_IRQ+0x8b/0x190 ret_from_intr+0x0/0x42 cpuidle_enter_state+0x15e/0x980 cpuidle_enter+0x69/0xc0 call_cpuidle+0x23/0x40 do_idle+0x248/0x280 cpu_startup_entry+0x1d/0x1f start_secondary+0x1b2/0x230 secondary_startup_64+0xb6/0xc0 no locks held by swapper/22/0. irq event stamp: 32871382 _raw_spin_unlock_irqrestore+0x53/0x60 _raw_spin_lock_irqsave+0x21/0x60 _local_bh_enable+0x21/0x30 irq_exit+0xa2/0xc0 read to 0xffff9f320a0a01d0 of 8 bytes by interrupt on cpu 2: add_timer_randomness+0xe8/0x190 add_disk_randomness+0x85/0x280 scsi_end_request+0x43a/0x4a0 scsi_io_completion+0xb7/0x7e0 scsi_finish_command+0x1ed/0x2a0 scsi_softirq_done+0x1c9/0x1d0 blk_done_softirq+0x181/0x1d0 __do_softirq+0xd9/0x57c irq_exit+0xa2/0xc0 do_IRQ+0x8b/0x190 ret_from_intr+0x0/0x42 cpuidle_enter_state+0x15e/0x980 cpuidle_enter+0x69/0xc0 call_cpuidle+0x23/0x40 do_idle+0x248/0x280 cpu_startup_entry+0x1d/0x1f start_secondary+0x1b2/0x230 secondary_startup_64+0xb6/0xc0 no locks held by swapper/2/0. irq event stamp: 37846304 _raw_spin_unlock_irqrestore+0x53/0x60 _raw_spin_lock_irqsave+0x21/0x60 _local_bh_enable+0x21/0x30 irq_exit+0xa2/0xc0 Reported by Kernel Concurrency Sanitizer on: Hardware name: HP ProLiant BL660c Gen9, BIOS I38 10/17/2018 Link: https://lore.kernel.org/r/1582648024-13111-1-git-send-email-cai@lca.pw Signed-off-by: Qian Cai Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c33e7a3cdb13..f43f65c2195d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1170,14 +1170,14 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * We take into account the first, second and third-order deltas * in order to make our estimate. */ - delta = sample.jiffies - state->last_time; - state->last_time = sample.jiffies; + delta = sample.jiffies - READ_ONCE(state->last_time); + WRITE_ONCE(state->last_time, sample.jiffies); - delta2 = delta - state->last_delta; - state->last_delta = delta; + delta2 = delta - READ_ONCE(state->last_delta); + WRITE_ONCE(state->last_delta, delta); - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; + delta3 = delta2 - READ_ONCE(state->last_delta2); + WRITE_ONCE(state->last_delta2, delta2); if (delta < 0) delta = -delta; From c3944ec8c6df256ab480b56cb776f36df44b2ba5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 25 Feb 2020 14:42:48 +0100 Subject: [PATCH 127/809] clk: Fix phase init check Commit 2760878662a2 ("clk: Bail out when calculating phase fails during clk registration") introduced a check on error values at the time the clock is registered to bail out when such an error occurs. However, it doesn't check whether the returned value is positive which will happen if the driver returns a non-zero phase. Since a phase is usually a non-zero positive number this ends up returning something that isn't 0 to the caller of __clk_core_init(), making most clks fail to register if they implement a phase clk op and return anything besides 0 for the phase. Fix this by returning the error if phase is less than zero or just return zero if the phase is a positive number. Fixes: 2760878662a2 ("clk: Bail out when calculating phase fails during clk registration") Signed-off-by: Maxime Ripard Link: https://lkml.kernel.org/r/20200225134248.919889-1-maxime@cerno.tech Reported-by: "kernelci.org bot" [sboyd@kernel.org: Reword commit text to provide clarity] Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ed1797857bae..4d6fd7de05ae 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3344,6 +3344,7 @@ static int __clk_core_init(struct clk_core *core) int ret; struct clk_core *parent; unsigned long rate; + int phase; if (!core) return -EINVAL; @@ -3457,8 +3458,9 @@ static int __clk_core_init(struct clk_core *core) * Since a phase is by definition relative to its parent, just * query the current clock phase, or just assume it's in phase. */ - ret = clk_core_get_phase(core); - if (ret < 0) { + phase = clk_core_get_phase(core); + if (phase < 0) { + ret = phase; pr_warn("%s: Failed to get phase for clk '%s'\n", __func__, core->name); goto out; From 869233f81337bfb33c79f1e7539147d52c0ba383 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 25 Feb 2020 13:47:25 +0200 Subject: [PATCH 128/809] gpiolib: Optimize gpiochip_remove() when check for requested line Here are the following optimizations have been done: - break the loop after first found requested line - due to above, drop redundant boolean variable - replace open coded variant of gpiochip_is_requested() - due to above, drop redundant pointer to struct gpio_desc - use 'unsigned int' instead of 'unsigned' for loop counter Note, pointer to struct gpio_chip followed by pointer to struct gpio_device is still valid, back link is not. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200225114725.839-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9ad86477af9c..2253ab495349 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1797,10 +1797,8 @@ EXPORT_SYMBOL_GPL(gpiochip_get_data); void gpiochip_remove(struct gpio_chip *chip) { struct gpio_device *gdev = chip->gpiodev; - struct gpio_desc *desc; unsigned long flags; - unsigned i; - bool requested = false; + unsigned int i; /* FIXME: should the legacy sysfs handling be moved to gpio_device? */ gpiochip_sysfs_unregister(gdev); @@ -1820,13 +1818,12 @@ void gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); for (i = 0; i < gdev->ngpio; i++) { - desc = &gdev->descs[i]; - if (test_bit(FLAG_REQUESTED, &desc->flags)) - requested = true; + if (gpiochip_is_requested(chip, i)) + break; } spin_unlock_irqrestore(&gpio_lock, flags); - if (requested) + if (i == gdev->ngpio) dev_crit(&gdev->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); From ec18d7e7d28625355bf2f5c18d47c09b1cde5cde Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 11 Feb 2020 15:06:18 -0600 Subject: [PATCH 129/809] gpio: uniphier: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertenly introduced[3] to the codebase from now on. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 7ec97499b7f7..f99f3c10bed0 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -30,7 +30,7 @@ struct uniphier_gpio_priv { struct irq_domain *domain; void __iomem *regs; spinlock_t lock; - u32 saved_vals[0]; + u32 saved_vals[]; }; static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank) From df2cd589766cf7c35a73690fc22d6a6be179cb57 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Feb 2020 19:09:04 +0200 Subject: [PATCH 130/809] gpiolib: Rename 'event' to 'ge' to be consistent with other use Rename 'event' to 'ge' to be consistent with other use. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2253ab495349..2982d983c4fd 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -830,11 +830,11 @@ static ssize_t lineevent_read(struct file *filep, loff_t *f_ps) { struct lineevent_state *le = filep->private_data; - struct gpioevent_data event; + struct gpioevent_data ge; ssize_t bytes_read = 0; int ret; - if (count < sizeof(event)) + if (count < sizeof(ge)) return -EINVAL; do { @@ -858,7 +858,7 @@ static ssize_t lineevent_read(struct file *filep, } } - ret = kfifo_out(&le->events, &event, 1); + ret = kfifo_out(&le->events, &ge, 1); spin_unlock(&le->wait.lock); if (ret != 1) { /* @@ -870,10 +870,10 @@ static ssize_t lineevent_read(struct file *filep, break; } - if (copy_to_user(buf + bytes_read, &event, sizeof(event))) + if (copy_to_user(buf + bytes_read, &ge, sizeof(ge))) return -EFAULT; - bytes_read += sizeof(event); - } while (count >= bytes_read + sizeof(event)); + bytes_read += sizeof(ge); + } while (count >= bytes_read + sizeof(ge)); return bytes_read; } From 48543bd8e92880b1ca81b15cf392103dc82cd3e0 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 24 Feb 2020 14:49:53 +0000 Subject: [PATCH 131/809] gpiolib: fix unwatch ioctl() Fix the field having a bit cleared by the unwatch ioctl(). Fixes: 51c1064e82e7 ("gpiolib: add new ioctl() for monitoring changes in line info") Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2982d983c4fd..20683695c598 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1276,7 +1276,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); - clear_bit(desc_to_gpio(desc), &desc->flags); + clear_bit(desc_to_gpio(desc), priv->watched_lines); return 0; } return -EINVAL; From 1931479788c5e3c0396a0bde3606e517c64b9f95 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 26 Feb 2020 14:53:23 +0100 Subject: [PATCH 132/809] gpiolib: fix bitmap operations related to line event watching When operating on the bits of watched_lines bitmap, we're using desc_to_gpio() which returns the GPIO number from the global numberspace. This leads to all sorts of memory corruptions and invalid behavior. We should switch to using gpio_chip_hwgpio() instead. Fixes: 51c1064e82e7 ("gpiolib: add new ioctl() for monitoring changes in line info") Reported-by: Kent Gibson Signed-off-by: Bartosz Golaszewski Tested-by: Kent Gibson --- drivers/gpio/gpiolib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 20683695c598..bc71f05d5193 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1261,7 +1261,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -EFAULT; if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) - set_bit(desc_to_gpio(desc), priv->watched_lines); + set_bit(gpio_chip_hwgpio(desc), priv->watched_lines); return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { @@ -1276,7 +1276,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); - clear_bit(desc_to_gpio(desc), priv->watched_lines); + clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines); return 0; } return -EINVAL; @@ -1304,7 +1304,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, struct gpio_desc *desc = data; int ret; - if (!test_bit(desc_to_gpio(desc), priv->watched_lines)) + if (!test_bit(gpio_chip_hwgpio(desc), priv->watched_lines)) return NOTIFY_DONE; memset(&chg, 0, sizeof(chg)); From 66e4f4a9cc389b277e187c115a285fad2cba5485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 21 Feb 2020 16:47:39 +0200 Subject: [PATCH 133/809] rtc: cmos: Use spin_lock_irqsave() in cmos_interrupt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmos_interrupt() isn't always called from hardirq context, so we must use spin_lock_irqsave() & co. ================================ WARNING: inconsistent lock state 5.6.0-rc2-CI-CI_DRM_7981+ #1 Tainted: G U -------------------------------- inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. rtcwake/4315 [HC0[0]:SC0[0]:HE1:SE1] takes: ffffffff82635198 (rtc_lock){?...}, at: cmos_interrupt+0x18/0x100 {IN-HARDIRQ-W} state was registered at: lock_acquire+0xa7/0x1c0 _raw_spin_lock+0x2a/0x40 cmos_interrupt+0x18/0x100 rtc_handler+0x75/0xc0 acpi_ev_fixed_event_detect+0xf9/0x132 acpi_ev_sci_xrupt_handler+0xb/0x28 acpi_irq+0x13/0x30 __handle_irq_event_percpu+0x41/0x2c0 handle_irq_event_percpu+0x2b/0x70 handle_irq_event+0x2f/0x50 handle_fasteoi_irq+0x8e/0x150 do_IRQ+0x7e/0x160 ret_from_intr+0x0/0x35 mwait_idle+0x7e/0x200 do_idle+0x1bb/0x260 cpu_startup_entry+0x14/0x20 start_secondary+0x15f/0x1b0 secondary_startup_64+0xa4/0xb0 irq event stamp: 42003 hardirqs last enabled at (42003): [] _raw_spin_unlock_irqrestore+0x47/0x60 hardirqs last disabled at (42002): [] _raw_spin_lock_irqsave+0xd/0x50 softirqs last enabled at (41848): [] __do_softirq+0x385/0x47f softirqs last disabled at (41841): [] irq_exit+0xba/0xc0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(rtc_lock); lock(rtc_lock); *** DEADLOCK *** 6 locks held by rtcwake/4315: #0: ffff888175dc9408 (sb_writers#5){.+.+}, at: vfs_write+0x1a4/0x1d0 #1: ffff88817406ca80 (&of->mutex){+.+.}, at: kernfs_fop_write+0xdd/0x1b0 #2: ffff888179be85e0 (kn->count#236){.+.+}, at: kernfs_fop_write+0xe6/0x1b0 #3: ffffffff82641e00 (system_transition_mutex){+.+.}, at: pm_suspend+0xb3/0x3b0 #4: ffffffff826b3ee0 (acpi_scan_lock){+.+.}, at: acpi_suspend_begin+0x47/0x80 #5: ffff888178fc3960 (&dev->mutex){....}, at: device_resume+0x92/0x1c0 stack backtrace: CPU: 3 PID: 4315 Comm: rtcwake Tainted: G U 5.6.0-rc2-CI-CI_DRM_7981+ #1 Hardware name: Google Soraka/Soraka, BIOS MrChromebox-4.10 08/25/2019 Call Trace: dump_stack+0x71/0x9b mark_lock+0x49a/0x500 ? print_shortest_lock_dependencies+0x200/0x200 __lock_acquire+0x6d4/0x15d0 ? __lock_acquire+0x460/0x15d0 lock_acquire+0xa7/0x1c0 ? cmos_interrupt+0x18/0x100 _raw_spin_lock+0x2a/0x40 ? cmos_interrupt+0x18/0x100 cmos_interrupt+0x18/0x100 cmos_resume+0x1fd/0x290 ? __acpi_pm_set_device_wakeup+0x24/0x100 pnp_bus_resume+0x5e/0x90 ? pnp_bus_suspend+0x10/0x10 dpm_run_callback+0x64/0x280 device_resume+0xd4/0x1c0 ? dpm_watchdog_set+0x60/0x60 dpm_resume+0x106/0x410 ? dpm_resume_early+0x38c/0x3e0 dpm_resume_end+0x8/0x10 suspend_devices_and_enter+0x16f/0xbe0 ? rcu_read_lock_sched_held+0x4d/0x80 pm_suspend+0x344/0x3b0 state_store+0x78/0xe0 kernfs_fop_write+0x112/0x1b0 vfs_write+0xb9/0x1d0 ksys_write+0x9f/0xe0 do_syscall_64+0x4f/0x220 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7ff934307154 Code: 89 02 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 8d 05 b1 07 2e 00 8b 00 85 c0 75 13 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 f3 c3 66 90 41 54 55 49 89 d4 53 48 89 f5 RSP: 002b:00007ffe2647c168 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007ff934307154 RDX: 0000000000000004 RSI: 000055de3ec4e5a0 RDI: 000000000000000a RBP: 000055de3ec4e5a0 R08: 000055de3ec4c5e0 R09: 00007ff9349f3740 R10: 000055de3ec4a010 R11: 0000000000000246 R12: 000055de3ec4c500 R13: 0000000000000004 R14: 00007ff9345df2a0 R15: 00007ff9345de760 Fixes: c6d3a278cc12 ("rtc: cmos: acknowledge ACPI driven wake alarms upon resume") Fixes: 311ee9c151ad ("rtc: cmos: allow using ACPI for RTC alarm instead of HPET") Signed-off-by: Ville Syrjälä Link: https://lore.kernel.org/r/20200221144739.11746-1-ville.syrjala@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index b795fe4cbd2e..fb13993fad31 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -649,10 +649,11 @@ static struct cmos_rtc cmos_rtc; static irqreturn_t cmos_interrupt(int irq, void *p) { + unsigned long flags; u8 irqstat; u8 rtc_control; - spin_lock(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); /* When the HPET interrupt handler calls us, the interrupt * status is passed as arg1 instead of the irq number. But @@ -686,7 +687,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p) hpet_mask_rtc_irq_bit(RTC_AIE); CMOS_READ(RTC_INTR_FLAGS); } - spin_unlock(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); if (is_intr(irqstat)) { rtc_update_irq(p, 1, irqstat); From ca18a852ee3696ea625efa13b1fac3c33f025a53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Mar 2020 09:24:48 +0100 Subject: [PATCH 134/809] gpiolib: Fix inverted check in gpiochip_remove() The optimization to check for requested lines actually optimized for the uncomon error case, where one of the GPIO lines is still in use. Hence the error message must be printed when the loop is terminated early, not when it went through all available GPIO lines. Fixes: 869233f81337bfb3 ("gpiolib: Optimize gpiochip_remove() when check for requested line") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200302082448.11795-1-geert+renesas@glider.be Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2253ab495349..0879731caf25 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1823,7 +1823,7 @@ void gpiochip_remove(struct gpio_chip *chip) } spin_unlock_irqrestore(&gpio_lock, flags); - if (i == gdev->ngpio) + if (i != gdev->ngpio) dev_crit(&gdev->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); From b396bfdebffcc05a855137775e38f4652cbca454 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 12 Feb 2020 12:21:03 -0500 Subject: [PATCH 135/809] tracing: Have hwlat ts be first instance and record count of instances The hwlat tracer runs a loop of width time during a given window. It then reports the max latency over a given threshold and records a timestamp. But this timestamp is the time after the width has finished, and not the time it actually triggered. Record the actual time when the latency was greater than the threshold as well as the number of times it was greater in a given width per window. Signed-off-by: Steven Rostedt (VMware) --- Documentation/trace/ftrace.rst | 32 ++++++++++++++++++++++---------- kernel/trace/trace_entries.h | 4 +++- kernel/trace/trace_hwlat.c | 24 +++++++++++++++++------- kernel/trace/trace_output.c | 4 ++-- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index ff658e27d25b..99a0890e20ec 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -2126,6 +2126,8 @@ periodically make a CPU constantly busy with interrupts disabled. # cat trace # tracer: hwlat # + # entries-in-buffer/entries-written: 13/13 #P:8 + # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq @@ -2133,12 +2135,18 @@ periodically make a CPU constantly busy with interrupts disabled. # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | - <...>-3638 [001] d... 19452.055471: #1 inner/outer(us): 12/14 ts:1499801089.066141940 - <...>-3638 [003] d... 19454.071354: #2 inner/outer(us): 11/9 ts:1499801091.082164365 - <...>-3638 [002] dn.. 19461.126852: #3 inner/outer(us): 12/9 ts:1499801098.138150062 - <...>-3638 [001] d... 19488.340960: #4 inner/outer(us): 8/12 ts:1499801125.354139633 - <...>-3638 [003] d... 19494.388553: #5 inner/outer(us): 8/12 ts:1499801131.402150961 - <...>-3638 [003] d... 19501.283419: #6 inner/outer(us): 0/12 ts:1499801138.297435289 nmi-total:4 nmi-count:1 + <...>-1729 [001] d... 678.473449: #1 inner/outer(us): 11/12 ts:1581527483.343962693 count:6 + <...>-1729 [004] d... 689.556542: #2 inner/outer(us): 16/9 ts:1581527494.889008092 count:1 + <...>-1729 [005] d... 714.756290: #3 inner/outer(us): 16/16 ts:1581527519.678961629 count:5 + <...>-1729 [001] d... 718.788247: #4 inner/outer(us): 9/17 ts:1581527523.889012713 count:1 + <...>-1729 [002] d... 719.796341: #5 inner/outer(us): 13/9 ts:1581527524.912872606 count:1 + <...>-1729 [006] d... 844.787091: #6 inner/outer(us): 9/12 ts:1581527649.889048502 count:2 + <...>-1729 [003] d... 849.827033: #7 inner/outer(us): 18/9 ts:1581527654.889013793 count:1 + <...>-1729 [007] d... 853.859002: #8 inner/outer(us): 9/12 ts:1581527658.889065736 count:1 + <...>-1729 [001] d... 855.874978: #9 inner/outer(us): 9/11 ts:1581527660.861991877 count:1 + <...>-1729 [001] d... 863.938932: #10 inner/outer(us): 9/11 ts:1581527668.970010500 count:1 nmi-total:7 nmi-count:1 + <...>-1729 [007] d... 878.050780: #11 inner/outer(us): 9/12 ts:1581527683.385002600 count:1 nmi-total:5 nmi-count:1 + <...>-1729 [007] d... 886.114702: #12 inner/outer(us): 9/12 ts:1581527691.385001600 count:1 The above output is somewhat the same in the header. All events will have @@ -2148,7 +2156,7 @@ interrupts disabled 'd'. Under the FUNCTION title there is: This is the count of events recorded that were greater than the tracing_threshold (See below). - inner/outer(us): 12/14 + inner/outer(us): 11/11 This shows two numbers as "inner latency" and "outer latency". The test runs in a loop checking a timestamp twice. The latency detected within @@ -2156,11 +2164,15 @@ interrupts disabled 'd'. Under the FUNCTION title there is: after the previous timestamp and the next timestamp in the loop is the "outer latency". - ts:1499801089.066141940 + ts:1581527483.343962693 - The absolute timestamp that the event happened. + The absolute timestamp that the first latency was recorded in the window. - nmi-total:4 nmi-count:1 + count:6 + + The number of times a latency was detected during the window. + + nmi-total:7 nmi-count:1 On architectures that support it, if an NMI comes in during the test, the time spent in NMI is reported in "nmi-total" (in diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index f22746f3c132..a523da0dae0a 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -325,14 +325,16 @@ FTRACE_ENTRY(hwlat, hwlat_entry, __field_desc( long, timestamp, tv_nsec ) __field( unsigned int, nmi_count ) __field( unsigned int, seqnum ) + __field( unsigned int, count ) ), - F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llu\tnmi-ts:%llu\tnmi-count:%u\n", + F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llu\tcount:%d\tnmi-ts:%llu\tnmi-count:%u\n", __entry->seqnum, __entry->tv_sec, __entry->tv_nsec, __entry->duration, __entry->outer_duration, + __entry->count, __entry->nmi_total_ts, __entry->nmi_count) ); diff --git a/kernel/trace/trace_hwlat.c b/kernel/trace/trace_hwlat.c index a48808c43249..e2be7bb7ef7e 100644 --- a/kernel/trace/trace_hwlat.c +++ b/kernel/trace/trace_hwlat.c @@ -83,6 +83,7 @@ struct hwlat_sample { u64 nmi_total_ts; /* Total time spent in NMIs */ struct timespec64 timestamp; /* wall time */ int nmi_count; /* # NMIs during this sample */ + int count; /* # of iteratons over threash */ }; /* keep the global state somewhere. */ @@ -124,6 +125,7 @@ static void trace_hwlat_sample(struct hwlat_sample *sample) entry->timestamp = sample->timestamp; entry->nmi_total_ts = sample->nmi_total_ts; entry->nmi_count = sample->nmi_count; + entry->count = sample->count; if (!call_filter_check_discard(call, entry, buffer, event)) trace_buffer_unlock_commit_nostack(buffer, event); @@ -167,12 +169,14 @@ void trace_hwlat_callback(bool enter) static int get_sample(void) { struct trace_array *tr = hwlat_trace; + struct hwlat_sample s; time_type start, t1, t2, last_t2; - s64 diff, total, last_total = 0; + s64 diff, outer_diff, total, last_total = 0; u64 sample = 0; u64 thresh = tracing_thresh; u64 outer_sample = 0; int ret = -1; + unsigned int count = 0; do_div(thresh, NSEC_PER_USEC); /* modifies interval value */ @@ -186,6 +190,7 @@ static int get_sample(void) init_time(last_t2, 0); start = time_get(); /* start timestamp */ + outer_diff = 0; do { @@ -194,14 +199,14 @@ static int get_sample(void) if (time_u64(last_t2)) { /* Check the delta from outer loop (t2 to next t1) */ - diff = time_to_us(time_sub(t1, last_t2)); + outer_diff = time_to_us(time_sub(t1, last_t2)); /* This shouldn't happen */ - if (diff < 0) { + if (outer_diff < 0) { pr_err(BANNER "time running backwards\n"); goto out; } - if (diff > outer_sample) - outer_sample = diff; + if (outer_diff > outer_sample) + outer_sample = outer_diff; } last_t2 = t2; @@ -217,6 +222,12 @@ static int get_sample(void) /* This checks the inner loop (t1 to t2) */ diff = time_to_us(time_sub(t2, t1)); /* current diff */ + if (diff > thresh || outer_diff > thresh) { + if (!count) + ktime_get_real_ts64(&s.timestamp); + count++; + } + /* This shouldn't happen */ if (diff < 0) { pr_err(BANNER "time running backwards\n"); @@ -236,7 +247,6 @@ static int get_sample(void) /* If we exceed the threshold value, we have found a hardware latency */ if (sample > thresh || outer_sample > thresh) { - struct hwlat_sample s; u64 latency; ret = 1; @@ -249,9 +259,9 @@ static int get_sample(void) s.seqnum = hwlat_data.count; s.duration = sample; s.outer_duration = outer_sample; - ktime_get_real_ts64(&s.timestamp); s.nmi_total_ts = nmi_total_ts; s.nmi_count = nmi_count; + s.count = count; trace_hwlat_sample(&s); latency = max(sample, outer_sample); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index b4909082f6a4..e25a7da79c6b 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -1158,12 +1158,12 @@ trace_hwlat_print(struct trace_iterator *iter, int flags, trace_assign_type(field, entry); - trace_seq_printf(s, "#%-5u inner/outer(us): %4llu/%-5llu ts:%lld.%09ld", + trace_seq_printf(s, "#%-5u inner/outer(us): %4llu/%-5llu ts:%lld.%09ld count:%d", field->seqnum, field->duration, field->outer_duration, (long long)field->timestamp.tv_sec, - field->timestamp.tv_nsec); + field->timestamp.tv_nsec, field->count); if (field->nmi_count) { /* From 5412e0b763e0c46165fa353f695fa3b68a66ac91 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 14 Feb 2020 16:20:04 -0500 Subject: [PATCH 136/809] tracing: Remove unused TRACE_BUFFER bits Commit 567cd4da54ff ("ring-buffer: User context bit recursion checking") added the TRACE_BUFFER bits to be used in the current task's trace_recursion field. But the final submission of the logic removed the use of those bits, but never removed the bits themselves (they were never used in upstream Linux). These can be safely removed. Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/trace.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 99372dd7d168..c61e1b1c85a6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -557,12 +557,7 @@ struct tracer { * caller, and we can skip the current check. */ enum { - TRACE_BUFFER_BIT, - TRACE_BUFFER_NMI_BIT, - TRACE_BUFFER_IRQ_BIT, - TRACE_BUFFER_SIRQ_BIT, - - /* Start of function recursion bits */ + /* Function recursion bits */ TRACE_FTRACE_BIT, TRACE_FTRACE_NMI_BIT, TRACE_FTRACE_IRQ_BIT, From 306b69dce9269df116bfa94319b1b827c22d5794 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 3 Mar 2020 20:24:40 +0900 Subject: [PATCH 137/809] bootconfig: Support O= option Support O= option to build bootconfig tool in the other directory. As same as other tools, if you specify O=, bootconfig command is build under . Link: http://lkml.kernel.org/r/158323468033.10560.14661631369326294355.stgit@devnote2 Reported-by: Randy Dunlap Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- tools/bootconfig/Makefile | 27 +++++++++++++++++---------- tools/bootconfig/test-bootconfig.sh | 14 ++++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile index a6146ac64458..da5975775337 100644 --- a/tools/bootconfig/Makefile +++ b/tools/bootconfig/Makefile @@ -1,23 +1,30 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for bootconfig command +include ../scripts/Makefile.include bindir ?= /usr/bin -HEADER = include/linux/bootconfig.h -CFLAGS = -Wall -g -I./include +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +endif -PROGS = bootconfig +LIBSRC = $(srctree)/lib/bootconfig.c $(srctree)/include/linux/bootconfig.h +CFLAGS = -Wall -g -I$(CURDIR)/include -all: $(PROGS) +ALL_TARGETS := bootconfig +ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) -bootconfig: ../../lib/bootconfig.c main.c $(HEADER) +all: $(ALL_PROGRAMS) + +$(OUTPUT)bootconfig: main.c $(LIBSRC) $(CC) $(filter %.c,$^) $(CFLAGS) -o $@ -install: $(PROGS) - install bootconfig $(DESTDIR)$(bindir) +test: $(ALL_PROGRAMS) test-bootconfig.sh + ./test-bootconfig.sh $(OUTPUT) -test: bootconfig - ./test-bootconfig.sh +install: $(ALL_PROGRAMS) + install $(OUTPUT)bootconfig $(DESTDIR)$(bindir) clean: - $(RM) -f *.o bootconfig + $(RM) -f $(OUTPUT)*.o $(ALL_PROGRAMS) diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh index 1411f4c3454f..81b350ffd03f 100755 --- a/tools/bootconfig/test-bootconfig.sh +++ b/tools/bootconfig/test-bootconfig.sh @@ -3,9 +3,16 @@ echo "Boot config test script" -BOOTCONF=./bootconfig -INITRD=`mktemp initrd-XXXX` -TEMPCONF=`mktemp temp-XXXX.bconf` +if [ -d "$1" ]; then + TESTDIR=$1 +else + TESTDIR=. +fi +BOOTCONF=${TESTDIR}/bootconfig + +INITRD=`mktemp ${TESTDIR}/initrd-XXXX` +TEMPCONF=`mktemp ${TESTDIR}/temp-XXXX.bconf` +OUTFILE=`mktemp ${TESTDIR}/tempout-XXXX` NG=0 cleanup() { @@ -65,7 +72,6 @@ new_size=$(stat -c %s $INITRD) xpass test $new_size -eq $initrd_size echo "No error messge while applying" -OUTFILE=`mktemp tempout-XXXX` dd if=/dev/zero of=$INITRD bs=4096 count=1 printf " \0\0\0 \0\0\0" >> $INITRD $BOOTCONF -a $TEMPCONF $INITRD > $OUTFILE 2>&1 From 89b74cac7834734d6b2733204c639917d3826083 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 3 Mar 2020 20:24:50 +0900 Subject: [PATCH 138/809] tools/bootconfig: Show line and column in parse error Show line and column when we got a parse error in bootconfig tool. Current lib/bootconfig shows the parse error with byte offset, but that is not human readable. This makes xbc_init() not showing error message itself but able to pass the error message and position to caller, so that the caller can decode it and show the error message with line number and columns. With this patch, bootconfig tool shows an error with line:column as below. $ cat samples/bad-dotword.bconf # do not start keyword with . key { .word = 1 } $ ./bootconfig -a samples/bad-dotword.bconf initrd Parse Error: Invalid keyword at 3:3 Link: http://lkml.kernel.org/r/158323469002.10560.4023923847704522760.stgit@devnote2 Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- include/linux/bootconfig.h | 3 ++- init/main.c | 14 ++++++++++---- lib/bootconfig.c | 35 ++++++++++++++++++++++++++--------- tools/bootconfig/main.c | 35 +++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index d11e183fcb54..9903088891fa 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -216,7 +216,8 @@ static inline int __init xbc_node_compose_key(struct xbc_node *node, } /* XBC node initializer */ -int __init xbc_init(char *buf); +int __init xbc_init(char *buf, const char **emsg, int *epos); + /* XBC cleanup data structures */ void __init xbc_destroy_all(void); diff --git a/init/main.c b/init/main.c index ee4947af823f..e488213857e2 100644 --- a/init/main.c +++ b/init/main.c @@ -353,6 +353,8 @@ static int __init bootconfig_params(char *param, char *val, static void __init setup_boot_config(const char *cmdline) { static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; + const char *msg; + int pos; u32 size, csum; char *data, *copy; u32 *hdr; @@ -400,10 +402,14 @@ static void __init setup_boot_config(const char *cmdline) memcpy(copy, data, size); copy[size] = '\0'; - ret = xbc_init(copy); - if (ret < 0) - pr_err("Failed to parse bootconfig\n"); - else { + ret = xbc_init(copy, &msg, &pos); + if (ret < 0) { + if (pos < 0) + pr_err("Failed to init bootconfig: %s.\n", msg); + else + pr_err("Failed to parse bootconfig: %s at %d.\n", + msg, pos); + } else { pr_info("Load bootconfig: %d bytes %d nodes\n", size, ret); /* keys starting with "kernel." are passed via cmdline */ extra_command_line = xbc_make_cmdline("kernel"); diff --git a/lib/bootconfig.c b/lib/bootconfig.c index ec3ce7fd299f..912ef4921398 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -29,12 +29,14 @@ static int xbc_node_num __initdata; static char *xbc_data __initdata; static size_t xbc_data_size __initdata; static struct xbc_node *last_parent __initdata; +static const char *xbc_err_msg __initdata; +static int xbc_err_pos __initdata; static int __init xbc_parse_error(const char *msg, const char *p) { - int pos = p - xbc_data; + xbc_err_msg = msg; + xbc_err_pos = (int)(p - xbc_data); - pr_err("Parse error at pos %d: %s\n", pos, msg); return -EINVAL; } @@ -738,33 +740,44 @@ void __init xbc_destroy_all(void) /** * xbc_init() - Parse given XBC file and build XBC internal tree * @buf: boot config text + * @emsg: A pointer of const char * to store the error message + * @epos: A pointer of int to store the error position * * This parses the boot config text in @buf. @buf must be a * null terminated string and smaller than XBC_DATA_MAX. * Return the number of stored nodes (>0) if succeeded, or -errno * if there is any error. + * In error cases, @emsg will be updated with an error message and + * @epos will be updated with the error position which is the byte offset + * of @buf. If the error is not a parser error, @epos will be -1. */ -int __init xbc_init(char *buf) +int __init xbc_init(char *buf, const char **emsg, int *epos) { char *p, *q; int ret, c; + if (epos) + *epos = -1; + if (xbc_data) { - pr_err("Error: bootconfig is already initialized.\n"); + if (emsg) + *emsg = "Bootconfig is already initialized"; return -EBUSY; } ret = strlen(buf); if (ret > XBC_DATA_MAX - 1 || ret == 0) { - pr_err("Error: Config data is %s.\n", - ret ? "too big" : "empty"); + if (emsg) + *emsg = ret ? "Config data is too big" : + "Config data is empty"; return -ERANGE; } xbc_nodes = memblock_alloc(sizeof(struct xbc_node) * XBC_NODE_MAX, SMP_CACHE_BYTES); if (!xbc_nodes) { - pr_err("Failed to allocate memory for bootconfig nodes.\n"); + if (emsg) + *emsg = "Failed to allocate bootconfig nodes"; return -ENOMEM; } memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX); @@ -814,9 +827,13 @@ int __init xbc_init(char *buf) if (!ret) ret = xbc_verify_tree(); - if (ret < 0) + if (ret < 0) { + if (epos) + *epos = xbc_err_pos; + if (emsg) + *emsg = xbc_err_msg; xbc_destroy_all(); - else + } else ret = xbc_node_num; return ret; diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c index a9b97814d1a9..16b9a420e6fd 100644 --- a/tools/bootconfig/main.c +++ b/tools/bootconfig/main.c @@ -130,6 +130,7 @@ int load_xbc_from_initrd(int fd, char **buf) int ret; u32 size = 0, csum = 0, rcsum; char magic[BOOTCONFIG_MAGIC_LEN]; + const char *msg; ret = fstat(fd, &stat); if (ret < 0) @@ -182,10 +183,12 @@ int load_xbc_from_initrd(int fd, char **buf) return -EINVAL; } - ret = xbc_init(*buf); + ret = xbc_init(*buf, &msg, NULL); /* Wrong data */ - if (ret < 0) + if (ret < 0) { + pr_err("parse error: %s.\n", msg); return ret; + } return size; } @@ -244,11 +247,34 @@ int delete_xbc(const char *path) return ret; } +static void show_xbc_error(const char *data, const char *msg, int pos) +{ + int lin = 1, col, i; + + if (pos < 0) { + pr_err("Error: %s.\n", msg); + return; + } + + /* Note that pos starts from 0 but lin and col should start from 1. */ + col = pos + 1; + for (i = 0; i < pos; i++) { + if (data[i] == '\n') { + lin++; + col = pos - i; + } + } + pr_err("Parse Error: %s at %d:%d\n", msg, lin, col); + +} + int apply_xbc(const char *path, const char *xbc_path) { u32 size, csum; char *buf, *data; int ret, fd; + const char *msg; + int pos; ret = load_xbc_file(xbc_path, &buf); if (ret < 0) { @@ -267,11 +293,12 @@ int apply_xbc(const char *path, const char *xbc_path) *(u32 *)(data + size + 4) = csum; /* Check the data format */ - ret = xbc_init(buf); + ret = xbc_init(buf, &msg, &pos); if (ret < 0) { - pr_err("Failed to parse %s: %d\n", xbc_path, ret); + show_xbc_error(data, msg, pos); free(data); free(buf); + return ret; } printf("Apply %s to %s\n", xbc_path, path); From bbd9d05618a6d608c72640b1d3d651a75913456a Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 2 Mar 2020 15:50:44 -0800 Subject: [PATCH 139/809] gpu/trace: add a gpu total memory usage tracepoint This change adds the below gpu memory tracepoint: gpu_mem/gpu_mem_total: track global or proc gpu memory total usages Per process tracking of total gpu memory usage in the gem layer is not appropriate and hard to implement with trivial overhead. So for the gfx device driver layer to track total gpu memory usage both globally and per process in an easy and uniform way is to integrate the tracepoint in this patch to the underlying varied implementations of gpu memory tracking system from vendors. Putting this tracepoint in the common trace events can not only help wean the gfx drivers off of debugfs but also greatly help the downstream Android gpu vendors because debugfs is to be deprecated in the upcoming Android release. Then the gpu memory tracking of both Android kernel and the upstream linux kernel can stay closely, which can benefit the whole kernel eco-system in the long term. Link: http://lkml.kernel.org/r/20200302235044.59163-1-zzyiwei@google.com Acked-by: Greg Kroah-Hartman Signed-off-by: Yiwei Zhang Signed-off-by: Steven Rostedt (VMware) --- drivers/Kconfig | 2 ++ drivers/gpu/Makefile | 1 + drivers/gpu/trace/Kconfig | 4 +++ drivers/gpu/trace/Makefile | 3 ++ drivers/gpu/trace/trace_gpu_mem.c | 13 +++++++ include/trace/events/gpu_mem.h | 57 +++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+) create mode 100644 drivers/gpu/trace/Kconfig create mode 100644 drivers/gpu/trace/Makefile create mode 100644 drivers/gpu/trace/trace_gpu_mem.c create mode 100644 include/trace/events/gpu_mem.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 8befa53f43be..e0eda1a5c3f9 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -200,6 +200,8 @@ source "drivers/thunderbolt/Kconfig" source "drivers/android/Kconfig" +source "drivers/gpu/trace/Kconfig" + source "drivers/nvdimm/Kconfig" source "drivers/dax/Kconfig" diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index f17d01f076c7..835c88318cec 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_TEGRA_HOST1X) += host1x/ obj-y += drm/ vga/ obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ +obj-$(CONFIG_TRACE_GPU_MEM) += trace/ diff --git a/drivers/gpu/trace/Kconfig b/drivers/gpu/trace/Kconfig new file mode 100644 index 000000000000..c24e9edd022e --- /dev/null +++ b/drivers/gpu/trace/Kconfig @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config TRACE_GPU_MEM + bool diff --git a/drivers/gpu/trace/Makefile b/drivers/gpu/trace/Makefile new file mode 100644 index 000000000000..b70fbdc5847f --- /dev/null +++ b/drivers/gpu/trace/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_TRACE_GPU_MEM) += trace_gpu_mem.o diff --git a/drivers/gpu/trace/trace_gpu_mem.c b/drivers/gpu/trace/trace_gpu_mem.c new file mode 100644 index 000000000000..01e855897b6d --- /dev/null +++ b/drivers/gpu/trace/trace_gpu_mem.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPU memory trace points + * + * Copyright (C) 2020 Google, Inc. + */ + +#include + +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL(gpu_mem_total); diff --git a/include/trace/events/gpu_mem.h b/include/trace/events/gpu_mem.h new file mode 100644 index 000000000000..1897822a9150 --- /dev/null +++ b/include/trace/events/gpu_mem.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * GPU memory trace points + * + * Copyright (C) 2020 Google, Inc. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gpu_mem + +#if !defined(_TRACE_GPU_MEM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_GPU_MEM_H + +#include + +/* + * The gpu_memory_total event indicates that there's an update to either the + * global or process total gpu memory counters. + * + * This event should be emitted whenever the kernel device driver allocates, + * frees, imports, unimports memory in the GPU addressable space. + * + * @gpu_id: This is the gpu id. + * + * @pid: Put 0 for global total, while positive pid for process total. + * + * @size: Virtual size of the allocation in bytes. + * + */ +TRACE_EVENT(gpu_mem_total, + + TP_PROTO(uint32_t gpu_id, uint32_t pid, uint64_t size), + + TP_ARGS(gpu_id, pid, size), + + TP_STRUCT__entry( + __field(uint32_t, gpu_id) + __field(uint32_t, pid) + __field(uint64_t, size) + ), + + TP_fast_assign( + __entry->gpu_id = gpu_id; + __entry->pid = pid; + __entry->size = size; + ), + + TP_printk("gpu_id=%u pid=%u size=%llu", + __entry->gpu_id, + __entry->pid, + __entry->size) +); + +#endif /* _TRACE_GPU_MEM_H */ + +/* This part must be outside protection */ +#include From 12437759602315d1eaa5ece8169cd1eedd018ff2 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 27 Feb 2020 14:42:29 +0100 Subject: [PATCH 140/809] s390/mm: mark private defines for vm_fault_t as such This fixes several sparse warnings for fault.c: arch/s390/mm/fault.c:336:36: warning: restricted vm_fault_t degrades to integer arch/s390/mm/fault.c:573:23: warning: incorrect type in assignment (different base types) arch/s390/mm/fault.c:573:23: expected restricted vm_fault_t [usertype] fault arch/s390/mm/fault.c:573:23: got int Signed-off-by: Christian Borntraeger Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/mm/fault.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 7b0bb475c166..151adef0d5dd 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -44,11 +44,11 @@ #define __SUBCODE_MASK 0x0600 #define __PF_RES_FIELD 0x8000000000000000ULL -#define VM_FAULT_BADCONTEXT 0x010000 -#define VM_FAULT_BADMAP 0x020000 -#define VM_FAULT_BADACCESS 0x040000 -#define VM_FAULT_SIGNAL 0x080000 -#define VM_FAULT_PFAULT 0x100000 +#define VM_FAULT_BADCONTEXT ((__force vm_fault_t) 0x010000) +#define VM_FAULT_BADMAP ((__force vm_fault_t) 0x020000) +#define VM_FAULT_BADACCESS ((__force vm_fault_t) 0x040000) +#define VM_FAULT_SIGNAL ((__force vm_fault_t) 0x080000) +#define VM_FAULT_PFAULT ((__force vm_fault_t) 0x100000) enum fault_type { KERNEL_FAULT, From e189b172d212adcba33146348d50072bf6323121 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 2 Mar 2020 09:48:08 +0100 Subject: [PATCH 141/809] MAINTAINERS: Update s390/cio maintainer Update maintainer entry for s390 Common I/O Layer. Sebastian has left IBM, Vineeth takes over maintainership. Signed-off-by: Peter Oberparleiter Acked-by: Vineeth Vijayan Signed-off-by: Vasily Gorbik --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a0d86490c2c6..e170f74e0361 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14461,7 +14461,7 @@ F: Documentation/s390/ F: Documentation/driver-api/s390-drivers.rst S390 COMMON I/O LAYER -M: Sebastian Ott +M: Vineeth Vijayan M: Peter Oberparleiter L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ From 5e674c308baba7b3c5912110aaff4fff2131de49 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 2 Mar 2020 09:54:26 +0100 Subject: [PATCH 142/809] MAINTAINERS: Update s390/pci maintainer Update maintainer entry for s390 PCI subsystem. Sebastian has left IBM, Niklas takes over maintainership. Signed-off-by: Peter Oberparleiter Acked-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e170f74e0361..2c73d6d0854e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14503,7 +14503,7 @@ S: Supported F: drivers/s390/net/ S390 PCI SUBSYSTEM -M: Sebastian Ott +M: Niklas Schnelle M: Gerald Schaefer L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ From 365ad0b60d944050d61252e123e6a8b2c3950398 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 8 Feb 2020 15:09:04 +0100 Subject: [PATCH 143/809] powerpc/83xx: Fix some typo in some warning message "couldn;t" should be "couldn't". Signed-off-by: Christophe JAILLET Acked-by: Scott Wood Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200208140904.7521-1-christophe.jaillet@wanadoo.fr --- arch/powerpc/platforms/83xx/km83xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index ada42f03915a..306be75faec7 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -53,13 +53,13 @@ static void quirk_mpc8360e_qe_enet10(void) np_par = of_find_node_by_name(NULL, "par_io"); if (np_par == NULL) { - pr_warn("%s couldn;t find par_io node\n", __func__); + pr_warn("%s couldn't find par_io node\n", __func__); return; } /* Map Parallel I/O ports registers */ ret = of_address_to_resource(np_par, 0, &res); if (ret) { - pr_warn("%s couldn;t map par_io registers\n", __func__); + pr_warn("%s couldn't map par_io registers\n", __func__); return; } From 88654d5b4476a438bd86b257dc4d70bb32266f1b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 8 Feb 2020 15:09:20 +0100 Subject: [PATCH 144/809] powerpc/83xx: Add some error handling in 'quirk_mpc8360e_qe_enet10()' In some error handling path, we should call "of_node_put(np_par)" or some resource may be leaking in case of error. Fixes: 8159df72d43e ("83xx: add support for the kmeter1 board.") Signed-off-by: Christophe JAILLET Acked-by: Scott Wood Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200208140920.7652-1-christophe.jaillet@wanadoo.fr --- arch/powerpc/platforms/83xx/km83xx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index 306be75faec7..bcdc2c203ec9 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -60,10 +60,12 @@ static void quirk_mpc8360e_qe_enet10(void) ret = of_address_to_resource(np_par, 0, &res); if (ret) { pr_warn("%s couldn't map par_io registers\n", __func__); - return; + goto out; } base = ioremap(res.start, resource_size(&res)); + if (!base) + goto out; /* * set output delay adjustments to default values according @@ -111,6 +113,7 @@ static void quirk_mpc8360e_qe_enet10(void) setbits32((base + 0xac), 0x0000c000); } iounmap(base); +out: of_node_put(np_par); } From 860286cf33963fa8a0fe542995bdec2df5cb3abb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:58:56 +0100 Subject: [PATCH 145/809] powerpc/kernel: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-1-gregkh@linuxfoundation.org --- arch/powerpc/kernel/fadump.c | 10 +++------- arch/powerpc/kernel/setup-common.c | 3 +-- arch/powerpc/kernel/traps.c | 25 +++++-------------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 265b4aa72252..59e60a9a9f5c 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1455,7 +1455,6 @@ DEFINE_SHOW_ATTRIBUTE(fadump_region); static void fadump_init_files(void) { - struct dentry *debugfs_file; int rc = 0; fadump_kobj = kobject_create_and_add("fadump", kernel_kobj); @@ -1463,12 +1462,9 @@ static void fadump_init_files(void) pr_err("failed to create fadump kobject\n"); return; } - debugfs_file = debugfs_create_file("fadump_region", 0444, - powerpc_debugfs_root, NULL, - &fadump_region_fops); - if (!debugfs_file) - printk(KERN_ERR "fadump: unable to create debugfs file" - " fadump_region\n"); + + debugfs_create_file("fadump_region", 0444, powerpc_debugfs_root, NULL, + &fadump_region_fops); if (fw_dump.dump_active) { rc = sysfs_create_file(fadump_kobj, &release_attr.attr); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 7f8c890360fe..f9c0d888ce8a 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -787,8 +787,7 @@ EXPORT_SYMBOL(powerpc_debugfs_root); static int powerpc_debugfs_init(void) { powerpc_debugfs_root = debugfs_create_dir("powerpc", NULL); - - return powerpc_debugfs_root == NULL; + return 0; } arch_initcall(powerpc_debugfs_init); #endif diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 82a3438300fd..3fca22276bb1 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -2278,35 +2278,20 @@ void ppc_warn_emulated_print(const char *type) static int __init ppc_warn_emulated_init(void) { - struct dentry *dir, *d; + struct dentry *dir; unsigned int i; struct ppc_emulated_entry *entries = (void *)&ppc_emulated; - if (!powerpc_debugfs_root) - return -ENODEV; - dir = debugfs_create_dir("emulated_instructions", powerpc_debugfs_root); - if (!dir) - return -ENOMEM; - d = debugfs_create_u32("do_warn", 0644, dir, - &ppc_warn_emulated); - if (!d) - goto fail; + debugfs_create_u32("do_warn", 0644, dir, &ppc_warn_emulated); - for (i = 0; i < sizeof(ppc_emulated)/sizeof(*entries); i++) { - d = debugfs_create_u32(entries[i].name, 0644, dir, - (u32 *)&entries[i].val.counter); - if (!d) - goto fail; - } + for (i = 0; i < sizeof(ppc_emulated)/sizeof(*entries); i++) + debugfs_create_u32(entries[i].name, 0644, dir, + (u32 *)&entries[i].val.counter); return 0; - -fail: - debugfs_remove_recursive(dir); - return -ENOMEM; } device_initcall(ppc_warn_emulated_init); From c4fd527f52ecb135018655c7f56f87800872c5bc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:58:57 +0100 Subject: [PATCH 146/809] powerpc/kvm: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Because of this cleanup, we get to remove a few fields in struct kvm_arch that are now unused. Signed-off-by: Greg Kroah-Hartman [mpe: Fix build error in kvm/timing.c, adapt kvmppc_remove_cpu_debugfs()] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-2-gregkh@linuxfoundation.org --- arch/powerpc/include/asm/kvm_host.h | 3 --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 5 ++--- arch/powerpc/kvm/book3s_64_mmu_radix.c | 5 ++--- arch/powerpc/kvm/book3s_hv.c | 9 ++------- arch/powerpc/kvm/timing.c | 17 ++++------------- 5 files changed, 10 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 6e8b8ffd06ad..877f8aa2bc1e 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -308,8 +308,6 @@ struct kvm_arch { pgd_t *pgtable; u64 process_table; struct dentry *debugfs_dir; - struct dentry *htab_dentry; - struct dentry *radix_dentry; struct kvm_resize_hpt *resize_hpt; /* protected by kvm->lock */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE @@ -830,7 +828,6 @@ struct kvm_vcpu_arch { struct kvmhv_tb_accumulator cede_time; /* time napping inside guest */ struct dentry *debugfs_dir; - struct dentry *debugfs_timings; #endif /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */ }; diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 6c372f5c61b6..8b4eac0c9dcd 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -2138,9 +2138,8 @@ static const struct file_operations debugfs_htab_fops = { void kvmppc_mmu_debugfs_init(struct kvm *kvm) { - kvm->arch.htab_dentry = debugfs_create_file("htab", 0400, - kvm->arch.debugfs_dir, kvm, - &debugfs_htab_fops); + debugfs_create_file("htab", 0400, kvm->arch.debugfs_dir, kvm, + &debugfs_htab_fops); } void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 803940d79b73..1d75ed684b53 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -1376,9 +1376,8 @@ static const struct file_operations debugfs_radix_fops = { void kvmhv_radix_debugfs_init(struct kvm *kvm) { - kvm->arch.radix_dentry = debugfs_create_file("radix", 0400, - kvm->arch.debugfs_dir, kvm, - &debugfs_radix_fops); + debugfs_create_file("radix", 0400, kvm->arch.debugfs_dir, kvm, + &debugfs_radix_fops); } int kvmppc_radix_init(void) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 2cefd071b848..33be4d93248a 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2258,14 +2258,9 @@ static void debugfs_vcpu_init(struct kvm_vcpu *vcpu, unsigned int id) struct kvm *kvm = vcpu->kvm; snprintf(buf, sizeof(buf), "vcpu%u", id); - if (IS_ERR_OR_NULL(kvm->arch.debugfs_dir)) - return; vcpu->arch.debugfs_dir = debugfs_create_dir(buf, kvm->arch.debugfs_dir); - if (IS_ERR_OR_NULL(vcpu->arch.debugfs_dir)) - return; - vcpu->arch.debugfs_timings = - debugfs_create_file("timings", 0444, vcpu->arch.debugfs_dir, - vcpu, &debugfs_timings_ops); + debugfs_create_file("timings", 0444, vcpu->arch.debugfs_dir, vcpu, + &debugfs_timings_ops); } #else /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */ diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c index bfe4f106cffc..ba56a5cbba97 100644 --- a/arch/powerpc/kvm/timing.c +++ b/arch/powerpc/kvm/timing.c @@ -211,23 +211,14 @@ void kvmppc_create_vcpu_debugfs(struct kvm_vcpu *vcpu, unsigned int id) snprintf(dbg_fname, sizeof(dbg_fname), "vm%u_vcpu%u_timing", current->pid, id); - debugfs_file = debugfs_create_file(dbg_fname, 0666, - kvm_debugfs_dir, vcpu, - &kvmppc_exit_timing_fops); - - if (!debugfs_file) { - printk(KERN_ERR"%s: error creating debugfs file %s\n", - __func__, dbg_fname); - return; - } + debugfs_file = debugfs_create_file(dbg_fname, 0666, kvm_debugfs_dir, + vcpu, &kvmppc_exit_timing_fops); vcpu->arch.debugfs_exit_timing = debugfs_file; } void kvmppc_remove_vcpu_debugfs(struct kvm_vcpu *vcpu) { - if (vcpu->arch.debugfs_exit_timing) { - debugfs_remove(vcpu->arch.debugfs_exit_timing); - vcpu->arch.debugfs_exit_timing = NULL; - } + debugfs_remove(vcpu->arch.debugfs_exit_timing); + vcpu->arch.debugfs_exit_timing = NULL; } From 08f6a7974ab949d43c2584f966db458d255b2b0a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:58:58 +0100 Subject: [PATCH 147/809] powerpc/mm: book3s64: hash_utils: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-3-gregkh@linuxfoundation.org --- arch/powerpc/mm/book3s64/hash_utils.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index 523d4d39d11e..7e5714a69a58 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -2018,11 +2018,8 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_hpt_order, hpt_order_get, hpt_order_set, "%llu\n") static int __init hash64_debugfs(void) { - if (!debugfs_create_file_unsafe("hpt_order", 0600, powerpc_debugfs_root, - NULL, &fops_hpt_order)) { - pr_err("lpar: unable to create hpt_order debugsfs file\n"); - } - + debugfs_create_file("hpt_order", 0600, powerpc_debugfs_root, NULL, + &fops_hpt_order); return 0; } machine_device_initcall(pseries, hash64_debugfs); From f3c05201950a71c1b8b4f11828303f76c5dd0944 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:58:59 +0100 Subject: [PATCH 148/809] powerpc/mm: ptdump: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-4-gregkh@linuxfoundation.org --- arch/powerpc/mm/ptdump/bats.c | 8 +++----- arch/powerpc/mm/ptdump/hashpagetable.c | 7 ++----- arch/powerpc/mm/ptdump/ptdump.c | 8 +++----- arch/powerpc/mm/ptdump/segment_regs.c | 8 +++----- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/mm/ptdump/bats.c b/arch/powerpc/mm/ptdump/bats.c index 4154feac1da3..d3a5d6b318d1 100644 --- a/arch/powerpc/mm/ptdump/bats.c +++ b/arch/powerpc/mm/ptdump/bats.c @@ -164,10 +164,8 @@ static const struct file_operations bats_fops = { static int __init bats_init(void) { - struct dentry *debugfs_file; - - debugfs_file = debugfs_create_file("block_address_translation", 0400, - powerpc_debugfs_root, NULL, &bats_fops); - return debugfs_file ? 0 : -ENOMEM; + debugfs_create_file("block_address_translation", 0400, + powerpc_debugfs_root, NULL, &bats_fops); + return 0; } device_initcall(bats_init); diff --git a/arch/powerpc/mm/ptdump/hashpagetable.c b/arch/powerpc/mm/ptdump/hashpagetable.c index a07278027c6f..b6ed9578382f 100644 --- a/arch/powerpc/mm/ptdump/hashpagetable.c +++ b/arch/powerpc/mm/ptdump/hashpagetable.c @@ -527,13 +527,10 @@ static const struct file_operations ptdump_fops = { static int ptdump_init(void) { - struct dentry *debugfs_file; - if (!radix_enabled()) { populate_markers(); - debugfs_file = debugfs_create_file("kernel_hash_pagetable", - 0400, NULL, NULL, &ptdump_fops); - return debugfs_file ? 0 : -ENOMEM; + debugfs_create_file("kernel_hash_pagetable", 0400, NULL, NULL, + &ptdump_fops); } return 0; } diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c index 206156255247..d92bb8ea229c 100644 --- a/arch/powerpc/mm/ptdump/ptdump.c +++ b/arch/powerpc/mm/ptdump/ptdump.c @@ -417,12 +417,10 @@ void ptdump_check_wx(void) static int ptdump_init(void) { - struct dentry *debugfs_file; - populate_markers(); build_pgtable_complete_mask(); - debugfs_file = debugfs_create_file("kernel_page_tables", 0400, NULL, - NULL, &ptdump_fops); - return debugfs_file ? 0 : -ENOMEM; + debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, + &ptdump_fops); + return 0; } device_initcall(ptdump_init); diff --git a/arch/powerpc/mm/ptdump/segment_regs.c b/arch/powerpc/mm/ptdump/segment_regs.c index 501843664bb9..dde2fe8de4b2 100644 --- a/arch/powerpc/mm/ptdump/segment_regs.c +++ b/arch/powerpc/mm/ptdump/segment_regs.c @@ -55,10 +55,8 @@ static const struct file_operations sr_fops = { static int __init sr_init(void) { - struct dentry *debugfs_file; - - debugfs_file = debugfs_create_file("segment_registers", 0400, - powerpc_debugfs_root, NULL, &sr_fops); - return debugfs_file ? 0 : -ENOMEM; + debugfs_create_file("segment_registers", 0400, powerpc_debugfs_root, + NULL, &sr_fops); + return 0; } device_initcall(sr_init); From e04906aa1fbaf435b9a1f2ec6bbe7971a3ef8e42 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:59:00 +0100 Subject: [PATCH 149/809] powerpc/cell/axon_msi: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-5-gregkh@linuxfoundation.org --- arch/powerpc/platforms/cell/axon_msi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 57c4e0e86c88..ca2555b8a0c2 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -480,10 +480,6 @@ void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic) snprintf(name, sizeof(name), "msic_%d", of_node_to_nid(dn)); - if (!debugfs_create_file(name, 0600, powerpc_debugfs_root, - msic, &fops_msic)) { - pr_devel("axon_msi: debugfs_create_file failed!\n"); - return; - } + debugfs_create_file(name, 0600, powerpc_debugfs_root, msic, &fops_msic); } #endif /* DEBUG */ From f344f0ab993987ae29cb39cc52054d7346db082f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Feb 2020 11:59:01 +0100 Subject: [PATCH 150/809] powerpc/powernv: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Reviewed-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200209105901.1620958-6-gregkh@linuxfoundation.org --- arch/powerpc/platforms/powernv/memtrace.c | 7 ---- arch/powerpc/platforms/powernv/opal-imc.c | 24 ++++---------- arch/powerpc/platforms/powernv/pci-ioda.c | 5 --- arch/powerpc/platforms/powernv/vas-debug.c | 37 ++-------------------- 4 files changed, 10 insertions(+), 63 deletions(-) diff --git a/arch/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c index eb2e75dac369..d6d64f8718e6 100644 --- a/arch/powerpc/platforms/powernv/memtrace.c +++ b/arch/powerpc/platforms/powernv/memtrace.c @@ -187,11 +187,6 @@ static int memtrace_init_debugfs(void) snprintf(ent->name, 16, "%08x", ent->nid); dir = debugfs_create_dir(ent->name, memtrace_debugfs_dir); - if (!dir) { - pr_err("Failed to create debugfs directory for node %d\n", - ent->nid); - return -1; - } ent->dir = dir; debugfs_create_file("trace", 0400, dir, ent, &memtrace_fops); @@ -314,8 +309,6 @@ static int memtrace_init(void) { memtrace_debugfs_dir = debugfs_create_dir("memtrace", powerpc_debugfs_root); - if (!memtrace_debugfs_dir) - return -1; debugfs_create_file("enable", 0600, memtrace_debugfs_dir, NULL, &memtrace_init_fops); diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c index 000b350d4060..968b9a4d1cd9 100644 --- a/arch/powerpc/platforms/powernv/opal-imc.c +++ b/arch/powerpc/platforms/powernv/opal-imc.c @@ -35,11 +35,10 @@ static int imc_mem_set(void *data, u64 val) } DEFINE_DEBUGFS_ATTRIBUTE(fops_imc_x64, imc_mem_get, imc_mem_set, "0x%016llx\n"); -static struct dentry *imc_debugfs_create_x64(const char *name, umode_t mode, - struct dentry *parent, u64 *value) +static void imc_debugfs_create_x64(const char *name, umode_t mode, + struct dentry *parent, u64 *value) { - return debugfs_create_file_unsafe(name, mode, parent, - value, &fops_imc_x64); + debugfs_create_file_unsafe(name, mode, parent, value, &fops_imc_x64); } /* @@ -59,9 +58,6 @@ static void export_imc_mode_and_cmd(struct device_node *node, imc_debugfs_parent = debugfs_create_dir("imc", powerpc_debugfs_root); - if (!imc_debugfs_parent) - return; - if (of_property_read_u32(node, "cb_offset", &cb_offset)) cb_offset = IMC_CNTL_BLK_OFFSET; @@ -69,21 +65,15 @@ static void export_imc_mode_and_cmd(struct device_node *node, loc = (u64)(ptr->vbase) + cb_offset; imc_mode_addr = (u64 *)(loc + IMC_CNTL_BLK_MODE_OFFSET); sprintf(mode, "imc_mode_%d", (u32)(ptr->id)); - if (!imc_debugfs_create_x64(mode, 0600, imc_debugfs_parent, - imc_mode_addr)) - goto err; + imc_debugfs_create_x64(mode, 0600, imc_debugfs_parent, + imc_mode_addr); imc_cmd_addr = (u64 *)(loc + IMC_CNTL_BLK_CMD_OFFSET); sprintf(cmd, "imc_cmd_%d", (u32)(ptr->id)); - if (!imc_debugfs_create_x64(cmd, 0600, imc_debugfs_parent, - imc_cmd_addr)) - goto err; + imc_debugfs_create_x64(cmd, 0600, imc_debugfs_parent, + imc_cmd_addr); ptr++; } - return; - -err: - debugfs_remove_recursive(imc_debugfs_parent); } /* diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 22c22cd7bd82..57d3a6af1d52 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -3174,11 +3174,6 @@ static void pnv_pci_ioda_create_dbgfs(void) sprintf(name, "PCI%04x", hose->global_number); phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root); - if (!phb->dbgfs) { - pr_warn("%s: Error on creating debugfs on PHB#%x\n", - __func__, hose->global_number); - continue; - } debugfs_create_file_unsafe("dump_diag_regs", 0200, phb->dbgfs, phb, &pnv_pci_diag_data_fops); diff --git a/arch/powerpc/platforms/powernv/vas-debug.c b/arch/powerpc/platforms/powernv/vas-debug.c index 09e63df53c30..44035a3d6414 100644 --- a/arch/powerpc/platforms/powernv/vas-debug.c +++ b/arch/powerpc/platforms/powernv/vas-debug.c @@ -115,7 +115,7 @@ void vas_window_free_dbgdir(struct vas_window *window) void vas_window_init_dbgdir(struct vas_window *window) { - struct dentry *f, *d; + struct dentry *d; if (!window->vinst->dbgdir) return; @@ -127,28 +127,10 @@ void vas_window_init_dbgdir(struct vas_window *window) snprintf(window->dbgname, 16, "w%d", window->winid); d = debugfs_create_dir(window->dbgname, window->vinst->dbgdir); - if (IS_ERR(d)) - goto free_name; - window->dbgdir = d; - f = debugfs_create_file("info", 0444, d, window, &info_fops); - if (IS_ERR(f)) - goto remove_dir; - - f = debugfs_create_file("hvwc", 0444, d, window, &hvwc_fops); - if (IS_ERR(f)) - goto remove_dir; - - return; - -remove_dir: - debugfs_remove_recursive(window->dbgdir); - window->dbgdir = NULL; - -free_name: - kfree(window->dbgname); - window->dbgname = NULL; + debugfs_create_file("info", 0444, d, window, &info_fops); + debugfs_create_file("hvwc", 0444, d, window, &hvwc_fops); } void vas_instance_init_dbgdir(struct vas_instance *vinst) @@ -156,8 +138,6 @@ void vas_instance_init_dbgdir(struct vas_instance *vinst) struct dentry *d; vas_init_dbgdir(); - if (!vas_debugfs) - return; vinst->dbgname = kzalloc(16, GFP_KERNEL); if (!vinst->dbgname) @@ -166,16 +146,7 @@ void vas_instance_init_dbgdir(struct vas_instance *vinst) snprintf(vinst->dbgname, 16, "v%d", vinst->vas_id); d = debugfs_create_dir(vinst->dbgname, vas_debugfs); - if (IS_ERR(d)) - goto free_name; - vinst->dbgdir = d; - return; - -free_name: - kfree(vinst->dbgname); - vinst->dbgname = NULL; - vinst->dbgdir = NULL; } /* @@ -191,6 +162,4 @@ void vas_init_dbgdir(void) first_time = false; vas_debugfs = debugfs_create_dir("vas", NULL); - if (IS_ERR(vas_debugfs)) - vas_debugfs = NULL; } From c4b78169e3667413184c9a20e11b5832288a109f Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 23 Dec 2019 17:03:51 +1100 Subject: [PATCH 151/809] powerpc/book3s64: Fix error handling in mm_iommu_do_alloc() The last jump to free_exit in mm_iommu_do_alloc() happens after page pointers in struct mm_iommu_table_group_mem_t were already converted to physical addresses. Thus calling put_page() on these physical addresses will likely crash. This moves the loop which calculates the pageshift and converts page struct pointers to physical addresses later after the point when we cannot fail; thus eliminating the need to convert pointers back. Fixes: eb9d7a62c386 ("powerpc/mm_iommu: Fix potential deadlock") Reported-by: Jan Kara Signed-off-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191223060351.26359-1-aik@ozlabs.ru --- arch/powerpc/mm/book3s64/iommu_api.c | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/mm/book3s64/iommu_api.c b/arch/powerpc/mm/book3s64/iommu_api.c index eba73ebd8ae5..fa05bbd1f682 100644 --- a/arch/powerpc/mm/book3s64/iommu_api.c +++ b/arch/powerpc/mm/book3s64/iommu_api.c @@ -121,24 +121,6 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, goto free_exit; } - pageshift = PAGE_SHIFT; - for (i = 0; i < entries; ++i) { - struct page *page = mem->hpages[i]; - - /* - * Allow to use larger than 64k IOMMU pages. Only do that - * if we are backed by hugetlb. - */ - if ((mem->pageshift > PAGE_SHIFT) && PageHuge(page)) - pageshift = page_shift(compound_head(page)); - mem->pageshift = min(mem->pageshift, pageshift); - /* - * We don't need struct page reference any more, switch - * to physical address. - */ - mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; - } - good_exit: atomic64_set(&mem->mapped, 1); mem->used = 1; @@ -158,6 +140,27 @@ good_exit: } } + if (mem->dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) { + /* + * Allow to use larger than 64k IOMMU pages. Only do that + * if we are backed by hugetlb. Skip device memory as it is not + * backed with page structs. + */ + pageshift = PAGE_SHIFT; + for (i = 0; i < entries; ++i) { + struct page *page = mem->hpages[i]; + + if ((mem->pageshift > PAGE_SHIFT) && PageHuge(page)) + pageshift = page_shift(compound_head(page)); + mem->pageshift = min(mem->pageshift, pageshift); + /* + * We don't need struct page reference any more, switch + * to physical address. + */ + mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; + } + } + list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list); mutex_unlock(&mem_list_mutex); From 6453f9ed9d4e4b4cdf201bf34bf460c436bf50ea Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 17 Feb 2020 09:41:35 +0000 Subject: [PATCH 152/809] powerpc/mm: Don't kmap_atomic() in pte_offset_map() on PPC32 On PPC32, pte_offset_map() does a kmap_atomic() in order to support page tables allocated in high memory, just like ARM and x86/32. But since at least 2008 and commit 8054a3428fbe ("powerpc: Remove dead CONFIG_HIGHPTE"), page tables are never allocated in high memory. When the page is in low mem, kmap_atomic() just returns the page address but still disable preemption and pagefault. And it is not an inlined function, so we suffer function call for no reason. Make pte_offset_map() the same as pte_offset_kernel() and make pte_unmap() void, in the same way as PPC64 which doesn't have HIGHMEM. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/03c97f0f6b3790d164822563be80f2fd4713a955.1581932480.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/book3s/32/pgtable.h | 6 ++---- arch/powerpc/include/asm/nohash/32/pgtable.h | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 5b39c11e884a..7549393c4c43 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -366,10 +366,8 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, addr) \ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr)) -#define pte_offset_map(dir, addr) \ - ((pte_t *)(kmap_atomic(pmd_page(*(dir))) + \ - (pmd_page_vaddr(*(dir)) & ~PAGE_MASK)) + pte_index(addr)) -#define pte_unmap(pte) kunmap_atomic(pte) +#define pte_offset_map(dir, addr) pte_offset_kernel((dir), (addr)) +static inline void pte_unmap(pte_t *pte) { } /* * Encode and decode a swap entry. diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index 60c4d829152e..b04ba257fddb 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -372,10 +372,8 @@ static inline int pte_young(pte_t pte) #define pte_offset_kernel(dir, addr) \ (pmd_bad(*(dir)) ? NULL : (pte_t *)pmd_page_vaddr(*(dir)) + \ pte_index(addr)) -#define pte_offset_map(dir, addr) \ - ((pte_t *)(kmap_atomic(pmd_page(*(dir))) + \ - (pmd_page_vaddr(*(dir)) & ~PAGE_MASK)) + pte_index(addr)) -#define pte_unmap(pte) kunmap_atomic(pte) +#define pte_offset_map(dir, addr) pte_offset_kernel((dir), (addr)) +static inline void pte_unmap(pte_t *pte) { } /* * Encode and decode a swap entry. From d42c6d0f8d004c3661dde3c376ed637e9f292c22 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Feb 2020 11:04:34 +1100 Subject: [PATCH 153/809] powerpc/Makefile: Mark phony targets as PHONY Some of our phony targets are not marked as such. This can lead to confusing errors, eg: $ make clean $ touch install $ make install make: 'install' is up to date. $ Fix it by adding them to the PHONY variable which is marked phony in the top-level Makefile, or in scripts/Makefile.build for the boot Makefile. Suggested-by: Masahiro Yamada Signed-off-by: Michael Ellerman Reviewed-by: Masahiro Yamada Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200219000434.15872-1-mpe@ellerman.id.au --- arch/powerpc/Makefile | 6 ++++++ arch/powerpc/boot/Makefile | 2 ++ 2 files changed, 8 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index f35730548e42..cbe5ca4f0ee5 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -298,6 +298,7 @@ $(BOOT_TARGETS2): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) +PHONY += bootwrapper_install bootwrapper_install: $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) @@ -403,9 +404,11 @@ define archhelp @echo ' (minus the .dts extension).' endef +PHONY += install install: $(Q)$(MAKE) $(build)=$(boot) install +PHONY += vdso_install vdso_install: ifdef CONFIG_PPC64 $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ @@ -425,6 +428,7 @@ archheaders: ifdef CONFIG_STACKPROTECTOR prepare: stack_protector_prepare +PHONY += stack_protector_prepare stack_protector_prepare: prepare0 ifdef CONFIG_PPC64 $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h)) @@ -436,10 +440,12 @@ endif ifdef CONFIG_SMP prepare: task_cpu_prepare +PHONY += task_cpu_prepare task_cpu_prepare: prepare0 $(eval KBUILD_CFLAGS += -D_TASK_CPU=$(shell awk '{if ($$2 == "TASK_CPU") print $$3;}' include/generated/asm-offsets.h)) endif +PHONY += checkbin # Check toolchain versions: # - gcc-4.6 is the minimum kernel-wide version so nothing required. checkbin: diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 0556bf4fc9e9..c53a1b8bba8b 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -445,6 +445,8 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) zInstall: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $^ +PHONY += install zInstall + # anything not in $(targets) clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ From 16985f2d25095899685952296f128a71f0aff05c Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 17 Feb 2020 13:48:32 +1100 Subject: [PATCH 154/809] powerpc/powernv: Treat an empty reboot string as default Treat an empty reboot cmd string the same as a NULL string. This squashes a spurious unsupported reboot message that sometimes gets out when using xmon. Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200217024833.30580-1-oohall@gmail.com --- arch/powerpc/platforms/powernv/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 11fdae81b5dd..a8fe630cf7cc 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -229,7 +229,7 @@ static void __noreturn pnv_restart(char *cmd) pnv_prepare_going_down(); do { - if (!cmd) + if (!cmd || !strlen(cmd)) rc = opal_cec_reboot(); else if (strcmp(cmd, "full") == 0) rc = opal_cec_reboot2(OPAL_REBOOT_FULL_IPL, NULL); From 672e480aa21023fc8e4b6ab8635d8898822b97e7 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 17 Feb 2020 13:48:33 +1100 Subject: [PATCH 155/809] powerpc/powernv: Add explicit fast-reboot support Add a way to manually invoke a fast-reboot rather than setting the NVRAM flag. The idea is to allow userspace to invoke a fast-reboot using the optional string argument to the reboot() system call, or using the xmon zr command so we don't need to leave around a persistent changes on a system to use the feature. Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200217024833.30580-2-oohall@gmail.com --- arch/powerpc/include/asm/opal-api.h | 1 + arch/powerpc/platforms/powernv/setup.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index c1f25a760eb1..1dffa3cb16ba 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -1067,6 +1067,7 @@ enum { OPAL_REBOOT_PLATFORM_ERROR = 1, OPAL_REBOOT_FULL_IPL = 2, OPAL_REBOOT_MPIPL = 3, + OPAL_REBOOT_FAST = 4, }; /* Argument to OPAL_PCI_TCE_KILL */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index a8fe630cf7cc..3bc188da82ba 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -237,6 +237,8 @@ static void __noreturn pnv_restart(char *cmd) rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, NULL); else if (strcmp(cmd, "error") == 0) rc = opal_cec_reboot2(OPAL_REBOOT_PLATFORM_ERROR, NULL); + else if (strcmp(cmd, "fast") == 0) + rc = opal_cec_reboot2(OPAL_REBOOT_FAST, NULL); else rc = OPAL_UNSUPPORTED; From fcdb524d440d6326c286006e16f252b40ba4fd6a Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Fri, 14 Feb 2020 13:36:05 +0530 Subject: [PATCH 156/809] powerpc/kernel/sysfs: Refactor current sysfs.c An attempt to refactor the current sysfs.c file. To start with a big chuck of macro #defines and dscr functions are moved to start of the file. Secondly, HAS_ #define macros are cleanup based on CONFIG_ options Finally new HAS_ macro added: 1. HAS_PPC_PA6T (for PA6T) to separate out non-PMU SPRs. 2. HAS_PPC_PMC56 to separate out PMC SPR's from HAS_PPC_PMC_CLASSIC which come under CONFIG_PPC64. Signed-off-by: Madhavan Srinivasan Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200214080606.26872-1-kjain@linux.ibm.com --- arch/powerpc/kernel/sysfs.c | 393 +++++++++++++++++++----------------- 1 file changed, 209 insertions(+), 184 deletions(-) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 80a676da11cb..74da5ebf088e 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -87,6 +87,155 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay); #endif /* CONFIG_PPC64 */ +#define __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, EXTRA) \ +static void read_##NAME(void *val) \ +{ \ + *(unsigned long *)val = mfspr(ADDRESS); \ +} \ +static void write_##NAME(void *val) \ +{ \ + EXTRA; \ + mtspr(ADDRESS, *(unsigned long *)val); \ +} + +#define __SYSFS_SPRSETUP_SHOW_STORE(NAME) \ +static ssize_t show_##NAME(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct cpu *cpu = container_of(dev, struct cpu, dev); \ + unsigned long val; \ + smp_call_function_single(cpu->dev.id, read_##NAME, &val, 1); \ + return sprintf(buf, "%lx\n", val); \ +} \ +static ssize_t __used \ + store_##NAME(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct cpu *cpu = container_of(dev, struct cpu, dev); \ + unsigned long val; \ + int ret = sscanf(buf, "%lx", &val); \ + if (ret != 1) \ + return -EINVAL; \ + smp_call_function_single(cpu->dev.id, write_##NAME, &val, 1); \ + return count; \ +} + +#define SYSFS_PMCSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ppc_enable_pmcs()) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) +#define SYSFS_SPRSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) + +#define SYSFS_SPRSETUP_SHOW_STORE(NAME) \ + __SYSFS_SPRSETUP_SHOW_STORE(NAME) + +#ifdef CONFIG_PPC64 + +/* + * This is the system wide DSCR register default value. Any + * change to this default value through the sysfs interface + * will update all per cpu DSCR default values across the + * system stored in their respective PACA structures. + */ +static unsigned long dscr_default; + +/** + * read_dscr() - Fetch the cpu specific DSCR default + * @val: Returned cpu specific DSCR default value + * + * This function returns the per cpu DSCR default value + * for any cpu which is contained in it's PACA structure. + */ +static void read_dscr(void *val) +{ + *(unsigned long *)val = get_paca()->dscr_default; +} + + +/** + * write_dscr() - Update the cpu specific DSCR default + * @val: New cpu specific DSCR default value to update + * + * This function updates the per cpu DSCR default value + * for any cpu which is contained in it's PACA structure. + */ +static void write_dscr(void *val) +{ + get_paca()->dscr_default = *(unsigned long *)val; + if (!current->thread.dscr_inherit) { + current->thread.dscr = *(unsigned long *)val; + mtspr(SPRN_DSCR, *(unsigned long *)val); + } +} + +SYSFS_SPRSETUP_SHOW_STORE(dscr); +static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr); + +static void add_write_permission_dev_attr(struct device_attribute *attr) +{ + attr->attr.mode |= 0200; +} + +/** + * show_dscr_default() - Fetch the system wide DSCR default + * @dev: Device structure + * @attr: Device attribute structure + * @buf: Interface buffer + * + * This function returns the system wide DSCR default value. + */ +static ssize_t show_dscr_default(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%lx\n", dscr_default); +} + +/** + * store_dscr_default() - Update the system wide DSCR default + * @dev: Device structure + * @attr: Device attribute structure + * @buf: Interface buffer + * @count: Size of the update + * + * This function updates the system wide DSCR default value. + */ +static ssize_t __used store_dscr_default(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long val; + int ret = 0; + + ret = sscanf(buf, "%lx", &val); + if (ret != 1) + return -EINVAL; + dscr_default = val; + + on_each_cpu(write_dscr, &val, 1); + + return count; +} + +static DEVICE_ATTR(dscr_default, 0600, + show_dscr_default, store_dscr_default); + +static void sysfs_create_dscr_default(void) +{ + if (cpu_has_feature(CPU_FTR_DSCR)) { + int err = 0; + int cpu; + + dscr_default = spr_default_dscr; + for_each_possible_cpu(cpu) + paca_ptrs[cpu]->dscr_default = dscr_default; + + err = device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default); + } +} +#endif /* CONFIG_PPC64 */ + #ifdef CONFIG_PPC_FSL_BOOK3E #define MAX_BIT 63 @@ -407,84 +556,33 @@ void ppc_enable_pmcs(void) } EXPORT_SYMBOL(ppc_enable_pmcs); -#define __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, EXTRA) \ -static void read_##NAME(void *val) \ -{ \ - *(unsigned long *)val = mfspr(ADDRESS); \ -} \ -static void write_##NAME(void *val) \ -{ \ - EXTRA; \ - mtspr(ADDRESS, *(unsigned long *)val); \ -} -#define __SYSFS_SPRSETUP_SHOW_STORE(NAME) \ -static ssize_t show_##NAME(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct cpu *cpu = container_of(dev, struct cpu, dev); \ - unsigned long val; \ - smp_call_function_single(cpu->dev.id, read_##NAME, &val, 1); \ - return sprintf(buf, "%lx\n", val); \ -} \ -static ssize_t __used \ - store_##NAME(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct cpu *cpu = container_of(dev, struct cpu, dev); \ - unsigned long val; \ - int ret = sscanf(buf, "%lx", &val); \ - if (ret != 1) \ - return -EINVAL; \ - smp_call_function_single(cpu->dev.id, write_##NAME, &val, 1); \ - return count; \ -} - -#define SYSFS_PMCSETUP(NAME, ADDRESS) \ - __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ppc_enable_pmcs()) \ - __SYSFS_SPRSETUP_SHOW_STORE(NAME) -#define SYSFS_SPRSETUP(NAME, ADDRESS) \ - __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ) \ - __SYSFS_SPRSETUP_SHOW_STORE(NAME) - -#define SYSFS_SPRSETUP_SHOW_STORE(NAME) \ - __SYSFS_SPRSETUP_SHOW_STORE(NAME) /* Let's define all possible registers, we'll only hook up the ones * that are implemented on the current processor */ -#if defined(CONFIG_PPC64) +#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_BOOK3S_32) #define HAS_PPC_PMC_CLASSIC 1 #define HAS_PPC_PMC_IBM 1 -#define HAS_PPC_PMC_PA6T 1 -#elif defined(CONFIG_PPC_BOOK3S_32) -#define HAS_PPC_PMC_CLASSIC 1 -#define HAS_PPC_PMC_IBM 1 -#define HAS_PPC_PMC_G4 1 -#endif - - -#ifdef HAS_PPC_PMC_CLASSIC -SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); -SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); -SYSFS_PMCSETUP(pmc1, SPRN_PMC1); -SYSFS_PMCSETUP(pmc2, SPRN_PMC2); -SYSFS_PMCSETUP(pmc3, SPRN_PMC3); -SYSFS_PMCSETUP(pmc4, SPRN_PMC4); -SYSFS_PMCSETUP(pmc5, SPRN_PMC5); -SYSFS_PMCSETUP(pmc6, SPRN_PMC6); - -#ifdef HAS_PPC_PMC_G4 -SYSFS_PMCSETUP(mmcr2, SPRN_MMCR2); #endif #ifdef CONFIG_PPC64 -SYSFS_PMCSETUP(pmc7, SPRN_PMC7); -SYSFS_PMCSETUP(pmc8, SPRN_PMC8); +#define HAS_PPC_PMC_PA6T 1 +#define HAS_PPC_PMC56 1 +#endif -SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); +#ifdef CONFIG_PPC_BOOK3S_32 +#define HAS_PPC_PMC_G4 1 +#endif + +#if defined(CONFIG_PPC64) && defined(CONFIG_DEBUG_MISC) +#define HAS_PPC_PA6T +#endif +/* + * SPRs which are not related to PMU. + */ +#ifdef CONFIG_PPC64 SYSFS_SPRSETUP(purr, SPRN_PURR); SYSFS_SPRSETUP(spurr, SPRN_SPURR); SYSFS_SPRSETUP(pir, SPRN_PIR); @@ -495,116 +593,39 @@ SYSFS_SPRSETUP(tscr, SPRN_TSCR); enable write when needed with a separate function. Lets be conservative and default to pseries. */ -static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static DEVICE_ATTR(spurr, 0400, show_spurr, NULL); static DEVICE_ATTR(purr, 0400, show_purr, store_purr); static DEVICE_ATTR(pir, 0400, show_pir, NULL); static DEVICE_ATTR(tscr, 0600, show_tscr, store_tscr); - -/* - * This is the system wide DSCR register default value. Any - * change to this default value through the sysfs interface - * will update all per cpu DSCR default values across the - * system stored in their respective PACA structures. - */ -static unsigned long dscr_default; - -/** - * read_dscr() - Fetch the cpu specific DSCR default - * @val: Returned cpu specific DSCR default value - * - * This function returns the per cpu DSCR default value - * for any cpu which is contained in it's PACA structure. - */ -static void read_dscr(void *val) -{ - *(unsigned long *)val = get_paca()->dscr_default; -} - - -/** - * write_dscr() - Update the cpu specific DSCR default - * @val: New cpu specific DSCR default value to update - * - * This function updates the per cpu DSCR default value - * for any cpu which is contained in it's PACA structure. - */ -static void write_dscr(void *val) -{ - get_paca()->dscr_default = *(unsigned long *)val; - if (!current->thread.dscr_inherit) { - current->thread.dscr = *(unsigned long *)val; - mtspr(SPRN_DSCR, *(unsigned long *)val); - } -} - -SYSFS_SPRSETUP_SHOW_STORE(dscr); -static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr); - -static void add_write_permission_dev_attr(struct device_attribute *attr) -{ - attr->attr.mode |= 0200; -} - -/** - * show_dscr_default() - Fetch the system wide DSCR default - * @dev: Device structure - * @attr: Device attribute structure - * @buf: Interface buffer - * - * This function returns the system wide DSCR default value. - */ -static ssize_t show_dscr_default(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%lx\n", dscr_default); -} - -/** - * store_dscr_default() - Update the system wide DSCR default - * @dev: Device structure - * @attr: Device attribute structure - * @buf: Interface buffer - * @count: Size of the update - * - * This function updates the system wide DSCR default value. - */ -static ssize_t __used store_dscr_default(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - unsigned long val; - int ret = 0; - - ret = sscanf(buf, "%lx", &val); - if (ret != 1) - return -EINVAL; - dscr_default = val; - - on_each_cpu(write_dscr, &val, 1); - - return count; -} - -static DEVICE_ATTR(dscr_default, 0600, - show_dscr_default, store_dscr_default); - -static void sysfs_create_dscr_default(void) -{ - if (cpu_has_feature(CPU_FTR_DSCR)) { - int err = 0; - int cpu; - - dscr_default = spr_default_dscr; - for_each_possible_cpu(cpu) - paca_ptrs[cpu]->dscr_default = dscr_default; - - err = device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default); - } -} - #endif /* CONFIG_PPC64 */ +#ifdef HAS_PPC_PMC_CLASSIC +SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); +SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); +SYSFS_PMCSETUP(pmc1, SPRN_PMC1); +SYSFS_PMCSETUP(pmc2, SPRN_PMC2); +SYSFS_PMCSETUP(pmc3, SPRN_PMC3); +SYSFS_PMCSETUP(pmc4, SPRN_PMC4); +SYSFS_PMCSETUP(pmc5, SPRN_PMC5); +SYSFS_PMCSETUP(pmc6, SPRN_PMC6); +#endif + +#ifdef HAS_PPC_PMC_G4 +SYSFS_PMCSETUP(mmcr2, SPRN_MMCR2); +#endif + +#ifdef HAS_PPC_PMC56 +SYSFS_PMCSETUP(pmc7, SPRN_PMC7); +SYSFS_PMCSETUP(pmc8, SPRN_PMC8); + +SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); + +static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra); +#endif /* HAS_PPC_PMC56 */ + + + + #ifdef HAS_PPC_PMC_PA6T SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0); SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1); @@ -612,7 +633,9 @@ SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2); SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); -#ifdef CONFIG_DEBUG_MISC +#endif + +#ifdef HAS_PPC_PA6T SYSFS_SPRSETUP(hid0, SPRN_HID0); SYSFS_SPRSETUP(hid1, SPRN_HID1); SYSFS_SPRSETUP(hid4, SPRN_HID4); @@ -641,15 +664,14 @@ SYSFS_SPRSETUP(tsr0, SPRN_PA6T_TSR0); SYSFS_SPRSETUP(tsr1, SPRN_PA6T_TSR1); SYSFS_SPRSETUP(tsr2, SPRN_PA6T_TSR2); SYSFS_SPRSETUP(tsr3, SPRN_PA6T_TSR3); -#endif /* CONFIG_DEBUG_MISC */ -#endif /* HAS_PPC_PMC_PA6T */ +#endif /* HAS_PPC_PA6T */ #ifdef HAS_PPC_PMC_IBM static struct device_attribute ibm_common_attrs[] = { __ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), __ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), }; -#endif /* HAS_PPC_PMC_G4 */ +#endif /* HAS_PPC_PMC_IBM */ #ifdef HAS_PPC_PMC_G4 static struct device_attribute g4_common_attrs[] = { @@ -659,6 +681,7 @@ static struct device_attribute g4_common_attrs[] = { }; #endif /* HAS_PPC_PMC_G4 */ +#ifdef HAS_PPC_PMC_CLASSIC static struct device_attribute classic_pmc_attrs[] = { __ATTR(pmc1, 0600, show_pmc1, store_pmc1), __ATTR(pmc2, 0600, show_pmc2, store_pmc2), @@ -666,14 +689,16 @@ static struct device_attribute classic_pmc_attrs[] = { __ATTR(pmc4, 0600, show_pmc4, store_pmc4), __ATTR(pmc5, 0600, show_pmc5, store_pmc5), __ATTR(pmc6, 0600, show_pmc6, store_pmc6), -#ifdef CONFIG_PPC64 +#ifdef HAS_PPC_PMC56 __ATTR(pmc7, 0600, show_pmc7, store_pmc7), __ATTR(pmc8, 0600, show_pmc8, store_pmc8), #endif }; +#endif -#ifdef HAS_PPC_PMC_PA6T +#if defined(HAS_PPC_PMC_PA6T) || defined(HAS_PPC_PA6T) static struct device_attribute pa6t_attrs[] = { +#ifdef HAS_PPC_PMC_PA6T __ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), __ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), __ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0), @@ -682,7 +707,8 @@ static struct device_attribute pa6t_attrs[] = { __ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3), __ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4), __ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5), -#ifdef CONFIG_DEBUG_MISC +#endif +#ifdef HAS_PPC_PA6T __ATTR(hid0, 0600, show_hid0, store_hid0), __ATTR(hid1, 0600, show_hid1, store_hid1), __ATTR(hid4, 0600, show_hid4, store_hid4), @@ -711,10 +737,9 @@ static struct device_attribute pa6t_attrs[] = { __ATTR(tsr1, 0600, show_tsr1, store_tsr1), __ATTR(tsr2, 0600, show_tsr2, store_tsr2), __ATTR(tsr3, 0600, show_tsr3, store_tsr3), -#endif /* CONFIG_DEBUG_MISC */ +#endif /* HAS_PPC_PA6T */ }; -#endif /* HAS_PPC_PMC_PA6T */ -#endif /* HAS_PPC_PMC_CLASSIC */ +#endif #ifdef CONFIG_PPC_SVM static ssize_t show_svm(struct device *dev, struct device_attribute *attr, char *buf) @@ -765,14 +790,14 @@ static int register_cpu_online(unsigned int cpu) pmc_attrs = classic_pmc_attrs; break; #endif /* HAS_PPC_PMC_G4 */ -#ifdef HAS_PPC_PMC_PA6T +#if defined(HAS_PPC_PMC_PA6T) || defined(HAS_PPC_PA6T) case PPC_PMC_PA6T: /* PA Semi starts counting at PMC0 */ attrs = pa6t_attrs; nattrs = sizeof(pa6t_attrs) / sizeof(struct device_attribute); pmc_attrs = NULL; break; -#endif /* HAS_PPC_PMC_PA6T */ +#endif default: attrs = NULL; nattrs = 0; @@ -854,14 +879,14 @@ static int unregister_cpu_online(unsigned int cpu) pmc_attrs = classic_pmc_attrs; break; #endif /* HAS_PPC_PMC_G4 */ -#ifdef HAS_PPC_PMC_PA6T +#if defined(HAS_PPC_PMC_PA6T) || defined(HAS_PPC_PA6T) case PPC_PMC_PA6T: /* PA Semi starts counting at PMC0 */ attrs = pa6t_attrs; nattrs = sizeof(pa6t_attrs) / sizeof(struct device_attribute); pmc_attrs = NULL; break; -#endif /* HAS_PPC_PMC_PA6T */ +#endif default: attrs = NULL; nattrs = 0; From 22697da36d0cee57c2a5750ef7d84e4d88da17e7 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Fri, 14 Feb 2020 13:36:06 +0530 Subject: [PATCH 157/809] powerpc/kernel/sysfs: Add new config option PMU_SYSFS to enable PMU SPRs sysfs file creation Many of the performance monitoring unit (PMU) SPRs are exposed in the sysfs. This may not be a desirable since "perf" API is the primary interface to program PMU and collect counter data in the system. But that said, we cant remove these sysfs files since we dont whether anyone/anything is using them. So the patch adds a new CONFIG option 'CONFIG_PMU_SYSFS' (user selectable) to be used in sysfs file creation for PMU SPRs. New option by default is disabled, but can be enabled if user needs it. Tested this patch behaviour in powernv and pseries machines. Patch is also tested for pmac32_defconfig. Signed-off-by: Kajol Jain Tested-by: Nageswara R Sastry Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200214080606.26872-2-kjain@linux.ibm.com --- arch/powerpc/kernel/sysfs.c | 6 ++++++ arch/powerpc/platforms/Kconfig.cputype | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 74da5ebf088e..479c70680b76 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -562,6 +562,7 @@ EXPORT_SYMBOL(ppc_enable_pmcs); * that are implemented on the current processor */ +#ifdef CONFIG_PMU_SYSFS #if defined(CONFIG_PPC64) || defined(CONFIG_PPC_BOOK3S_32) #define HAS_PPC_PMC_CLASSIC 1 #define HAS_PPC_PMC_IBM 1 @@ -575,6 +576,7 @@ EXPORT_SYMBOL(ppc_enable_pmcs); #ifdef CONFIG_PPC_BOOK3S_32 #define HAS_PPC_PMC_G4 1 #endif +#endif /* CONFIG_PMU_SYSFS */ #if defined(CONFIG_PPC64) && defined(CONFIG_DEBUG_MISC) #define HAS_PPC_PA6T @@ -812,8 +814,10 @@ static int register_cpu_online(unsigned int cpu) device_create_file(s, &pmc_attrs[i]); #ifdef CONFIG_PPC64 +#ifdef CONFIG_PMU_SYSFS if (cpu_has_feature(CPU_FTR_MMCRA)) device_create_file(s, &dev_attr_mmcra); +#endif /* CONFIG_PMU_SYSFS */ if (cpu_has_feature(CPU_FTR_PURR)) { if (!firmware_has_feature(FW_FEATURE_LPAR)) @@ -901,8 +905,10 @@ static int unregister_cpu_online(unsigned int cpu) device_remove_file(s, &pmc_attrs[i]); #ifdef CONFIG_PPC64 +#ifdef CONFIG_PMU_SYSFS if (cpu_has_feature(CPU_FTR_MMCRA)) device_remove_file(s, &dev_attr_mmcra); +#endif /* CONFIG_PMU_SYSFS */ if (cpu_has_feature(CPU_FTR_PURR)) device_remove_file(s, &dev_attr_purr); diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 6caedc88474f..4208724e9f28 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -425,6 +425,12 @@ config PPC_MM_SLICES config PPC_HAVE_PMU_SUPPORT bool +config PMU_SYSFS + bool "Create PMU SPRs sysfs file" + default n + help + This option enables sysfs file creation for PMU SPRs like MMCR* and PMC*. + config PPC_PERF_CTRS def_bool y depends on PERF_EVENTS && PPC_HAVE_PMU_SUPPORT From 3d13e839e801e081bdece0127c2affa33d0f77cf Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Feb 2020 22:51:37 +1100 Subject: [PATCH 158/809] powerpc: Rename current_stack_pointer() to current_stack_frame() current_stack_pointer(), which was called __get_SP(), used to just return the value in r1. But that caused problems in some cases, so it was turned into a function in commit bfe9a2cfe91a ("powerpc: Reimplement __get_SP() as a function not a define"). Because it's a function in a separate compilation unit to all its callers, it has the effect of causing a stack frame to be created, and then returns the address of that frame. This is good in some cases like those described in the above commit, but in other cases it's overkill, we just need to know what stack page we're on. On some other arches current_stack_pointer is just a register global giving the stack pointer, and we'd like to do that too. So rename our current_stack_pointer() to current_stack_frame() to make that possible. Signed-off-by: Michael Ellerman Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20200220115141.2707-1-mpe@ellerman.id.au --- arch/powerpc/include/asm/perf_event.h | 2 +- arch/powerpc/include/asm/reg.h | 2 +- arch/powerpc/kernel/irq.c | 4 ++-- arch/powerpc/kernel/misc.S | 4 ++-- arch/powerpc/kernel/process.c | 2 +- arch/powerpc/kernel/stacktrace.c | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h index 7426d7a90e1e..eed3954082fa 100644 --- a/arch/powerpc/include/asm/perf_event.h +++ b/arch/powerpc/include/asm/perf_event.h @@ -32,7 +32,7 @@ do { \ (regs)->result = 0; \ (regs)->nip = __ip; \ - (regs)->gpr[1] = current_stack_pointer(); \ + (regs)->gpr[1] = current_stack_frame(); \ asm volatile("mfmsr %0" : "=r" ((regs)->msr)); \ } while (0) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1aa46dff0957..1b1ffdba6097 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1448,7 +1448,7 @@ static inline void mtsrin(u32 val, u32 idx) #define proc_trap() asm volatile("trap") -extern unsigned long current_stack_pointer(void); +extern unsigned long current_stack_frame(void); extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5c9b11878555..02118c18434d 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -602,7 +602,7 @@ static inline void check_stack_overflow(void) #ifdef CONFIG_DEBUG_STACKOVERFLOW long sp; - sp = current_stack_pointer() & (THREAD_SIZE-1); + sp = current_stack_frame() & (THREAD_SIZE-1); /* check for stack overflow: is there less than 2KB free? */ if (unlikely(sp < 2048)) { @@ -647,7 +647,7 @@ void do_IRQ(struct pt_regs *regs) void *cursp, *irqsp, *sirqsp; /* Switch to the irq stack to handle this */ - cursp = (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1)); + cursp = (void *)(current_stack_frame() & ~(THREAD_SIZE - 1)); irqsp = hardirq_ctx[raw_smp_processor_id()]; sirqsp = softirq_ctx[raw_smp_processor_id()]; diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 974f65f79a8e..65f9f731c229 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -110,7 +110,7 @@ _GLOBAL(longjmp) li r3, 1 blr -_GLOBAL(current_stack_pointer) +_GLOBAL(current_stack_frame) PPC_LL r3,0(r1) blr -EXPORT_SYMBOL(current_stack_pointer) +EXPORT_SYMBOL(current_stack_frame) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e730b8e522b0..110db94cdf3c 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -2051,7 +2051,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) sp = (unsigned long) stack; if (sp == 0) { if (tsk == current) - sp = current_stack_pointer(); + sp = current_stack_frame(); else sp = tsk->thread.ksp; } diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index e2a46cfed5fd..c477b8585a29 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c @@ -57,7 +57,7 @@ void save_stack_trace(struct stack_trace *trace) { unsigned long sp; - sp = current_stack_pointer(); + sp = current_stack_frame(); save_context_stack(trace, sp, current, 1); } @@ -71,7 +71,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) return; if (tsk == current) - sp = current_stack_pointer(); + sp = current_stack_frame(); else sp = tsk->thread.ksp; @@ -131,7 +131,7 @@ static int __save_stack_trace_tsk_reliable(struct task_struct *tsk, } if (tsk == current) - sp = current_stack_pointer(); + sp = current_stack_frame(); else sp = tsk->thread.ksp; From 0e63f0151719ee4cb90d85e60c98045099c995e2 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 20 Feb 2020 22:51:38 +1100 Subject: [PATCH 159/809] powerpc: Add current_stack_pointer as a register global current_stack_frame() doesn't return the stack pointer, but the caller's stack frame. See commit bfe9a2cfe91a ("powerpc: Reimplement __get_SP() as a function not a define") and commit acf620ecf56c ("powerpc: Rename __get_SP() to current_stack_pointer()") for details. In some cases this is overkill or incorrect, as it doesn't return the current value of r1. So add a current_stack_pointer register global to get the value of r1 directly. Signed-off-by: Christophe Leroy [mpe: Split out of other patch, tweak change log] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200220115141.2707-2-mpe@ellerman.id.au --- arch/powerpc/include/asm/reg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1b1ffdba6097..da5cab038e25 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1450,6 +1450,8 @@ static inline void mtsrin(u32 val, u32 idx) extern unsigned long current_stack_frame(void); +register unsigned long current_stack_pointer asm("r1"); + extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); From 84ab14893054751a2b3adba725834183b872a17f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 20 Feb 2020 22:51:39 +1100 Subject: [PATCH 160/809] powerpc/irq: Use current_stack_pointer in check_stack_overflow() The purpose of check_stack_overflow() is to verify that the stack has not overflowed. To really know whether the stack pointer is still within boundaries, the check must be done directly on the value of r1. So use current_stack_pointer, which returns the current value of r1, rather than current_stack_frame() which causes a frame to be created and then returns that value. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200220115141.2707-3-mpe@ellerman.id.au --- arch/powerpc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 02118c18434d..c7d6f5cdffdb 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -602,7 +602,7 @@ static inline void check_stack_overflow(void) #ifdef CONFIG_DEBUG_STACKOVERFLOW long sp; - sp = current_stack_frame() & (THREAD_SIZE-1); + sp = current_stack_pointer & (THREAD_SIZE - 1); /* check for stack overflow: is there less than 2KB free? */ if (unlikely(sp < 2048)) { From 0dec6e1cca7eee6d5616f982efab2ff3b3ea1f9f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 20 Feb 2020 22:51:40 +1100 Subject: [PATCH 161/809] powerpc/irq: use IS_ENABLED() in check_stack_overflow() Instead of #ifdef, use IS_ENABLED(CONFIG_DEBUG_STACKOVERFLOW). This enable GCC to check for code validity even when the option is not selected. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200220115141.2707-4-mpe@ellerman.id.au --- arch/powerpc/kernel/irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c7d6f5cdffdb..46d5852fb00a 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -599,9 +599,11 @@ u64 arch_irq_stat_cpu(unsigned int cpu) static inline void check_stack_overflow(void) { -#ifdef CONFIG_DEBUG_STACKOVERFLOW long sp; + if (!IS_ENABLED(CONFIG_DEBUG_STACKOVERFLOW)) + return; + sp = current_stack_pointer & (THREAD_SIZE - 1); /* check for stack overflow: is there less than 2KB free? */ @@ -609,7 +611,6 @@ static inline void check_stack_overflow(void) pr_err("do_IRQ: stack overflow: %ld\n", sp); dump_stack(); } -#endif } void __do_irq(struct pt_regs *regs) From 532d43a73cf191cf951d27e49d8d0a03e8cf2297 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 20 Feb 2020 22:51:41 +1100 Subject: [PATCH 162/809] powerpc/irq: Use current_stack_pointer in do_IRQ() Until commit 7306e83ccf5c ("powerpc: Don't use CURRENT_THREAD_INFO to find the stack"), the current stack base address was obtained by calling current_thread_info(). That inline function was simply masking out the value of r1. In that commit, it was changed to using current_stack_pointer() (since renamed current_stack_frame()), which is a heavier function as it is an outline assembly function which cannot be inlined and which reads the content of the stack at 0(r1). Convert to using current_stack_pointer for geting r1 and masking out its value to obtain the base address of the stack pointer as before. Fixes: 7306e83ccf5c ("powerpc: Don't use CURRENT_THREAD_INFO to find the stack") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200220115141.2707-5-mpe@ellerman.id.au --- arch/powerpc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 46d5852fb00a..1bed18b7229e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -648,7 +648,7 @@ void do_IRQ(struct pt_regs *regs) void *cursp, *irqsp, *sirqsp; /* Switch to the irq stack to handle this */ - cursp = (void *)(current_stack_frame() & ~(THREAD_SIZE - 1)); + cursp = (void *)(current_stack_pointer & ~(THREAD_SIZE - 1)); irqsp = hardirq_ctx[raw_smp_processor_id()]; sirqsp = softirq_ctx[raw_smp_processor_id()]; From a05f0e5be4e81e4977d3f92aaf7688ee0cb7d5db Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:21:21 +0530 Subject: [PATCH 163/809] powerpc/smp: Use nid as fallback for package_id package_id is to match cores that are part of the same chip. On PowerNV machines, package_id defaults to chip_id. However ibm,chip_id property is not present in device-tree of PowerVM LPARs. Hence lscpu output shows one core per socket and multiple cores. To overcome this, use nid as the package_id on PowerVM LPARs. Before the patch: Architecture: ppc64le Byte Order: Little Endian CPU(s): 128 On-line CPU(s) list: 0-127 Thread(s) per core: 8 Core(s) per socket: 1 <---------------------- Socket(s): 16 <---------------------- NUMA node(s): 2 Model: 2.2 (pvr 004e 0202) Model name: POWER9 (architected), altivec supported Hypervisor vendor: pHyp Virtualization type: para L1d cache: 32K L1i cache: 32K L2 cache: 512K L3 cache: 10240K NUMA node0 CPU(s): 0-63 NUMA node1 CPU(s): 64-127 # # cat /sys/devices/system/cpu/cpu0/topology/physical_package_id -1 After the patch: Architecture: ppc64le Byte Order: Little Endian CPU(s): 128 On-line CPU(s) list: 0-127 Thread(s) per core: 8 <--------------------- Core(s) per socket: 8 <--------------------- Socket(s): 2 NUMA node(s): 2 Model: 2.2 (pvr 004e 0202) Model name: POWER9 (architected), altivec supported Hypervisor vendor: pHyp Virtualization type: para L1d cache: 32K L1i cache: 32K L2 cache: 512K L3 cache: 10240K NUMA node0 CPU(s): 0-63 NUMA node1 CPU(s): 64-127 # # cat /sys/devices/system/cpu/cpu0/topology/physical_package_id 0 Now lscpu output is more in line with the system configuration. Signed-off-by: Srikar Dronamraju [mpe: Use pkg_id instead of ppid, tweak change log and comment] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135121.24617-1-srikar@linux.vnet.ibm.com --- arch/powerpc/include/asm/topology.h | 6 ++++++ arch/powerpc/kernel/smp.c | 30 ++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 2f7e1ea5089e..e2e1ccd4a18d 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -134,7 +134,13 @@ static inline void shared_proc_topology_init(void) {} #ifdef CONFIG_PPC64 #include +#ifdef CONFIG_PPC_SPLPAR +int get_physical_package_id(int cpu); +#define topology_physical_package_id(cpu) (get_physical_package_id(cpu)) +#else #define topology_physical_package_id(cpu) (cpu_to_chip_id(cpu)) +#endif + #define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu)) #define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu)) #define topology_core_id(cpu) (cpu_to_core_id(cpu)) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ea6adbf6a221..f68cde82bdf3 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1185,10 +1185,34 @@ static inline void add_cpu_to_smallcore_masks(int cpu) } } +int get_physical_package_id(int cpu) +{ + int pkg_id = cpu_to_chip_id(cpu); + +#ifdef CONFIG_PPC_SPLPAR + /* + * If the platform is PowerNV or Guest on KVM, ibm,chip-id is + * defined. Hence we would return the chip-id as the result of + * get_physical_package_id. + */ + if (pkg_id == -1 && firmware_has_feature(FW_FEATURE_LPAR)) { + struct device_node *np = of_get_cpu_node(cpu, NULL); + + if (np) { + pkg_id = of_node_to_nid(np); + of_node_put(np); + } + } +#endif /* CONFIG_PPC_SPLPAR */ + + return pkg_id; +} +EXPORT_SYMBOL_GPL(get_physical_package_id); + static void add_cpu_to_masks(int cpu) { int first_thread = cpu_first_thread_sibling(cpu); - int chipid = cpu_to_chip_id(cpu); + int pkg_id = get_physical_package_id(cpu); int i; /* @@ -1217,11 +1241,11 @@ static void add_cpu_to_masks(int cpu) for_each_cpu(i, cpu_l2_cache_mask(cpu)) set_cpus_related(cpu, i, cpu_core_mask); - if (chipid == -1) + if (pkg_id == -1) return; for_each_cpu(i, cpu_online_mask) - if (cpu_to_chip_id(i) == chipid) + if (get_physical_package_id(i) == pkg_id) set_cpus_related(cpu, i, cpu_core_mask); } From e7214ae9d85aa325c9f3cb34bf4fad7f112861d7 Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:22:57 +0530 Subject: [PATCH 164/809] powerpc/vphn: Check for error from hcall_vphn There is no value in unpacking associativity, if H_HOME_NODE_ASSOCIATIVITY hcall has returned an error. Signed-off-by: Srikar Dronamraju Reported-by: Abdul Haleem Reviewed-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135301.24739-2-srikar@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/vphn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/vphn.c b/arch/powerpc/platforms/pseries/vphn.c index 3f07bf6c670e..cca474a2c396 100644 --- a/arch/powerpc/platforms/pseries/vphn.c +++ b/arch/powerpc/platforms/pseries/vphn.c @@ -82,7 +82,8 @@ long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity) long retbuf[PLPAR_HCALL9_BUFSIZE] = {0}; rc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, retbuf, flags, cpu); - vphn_unpack_associativity(retbuf, associativity); + if (rc == H_SUCCESS) + vphn_unpack_associativity(retbuf, associativity); return rc; } From 76b7bfb1732d139dc20a2f0c19ec32e09c8891cf Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:22:58 +0530 Subject: [PATCH 165/809] powerpc/numa: Handle extra hcall_vphn error cases Currently code handles H_FUNCTION, H_SUCCESS, H_HARDWARE return codes. However hcall_vphn can return other return codes. Now it also handles H_PARAMETER return code. Also the rest return codes are handled under the default case. Signed-off-by: Srikar Dronamraju Reported-by: Abdul Haleem Reviewed-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135301.24739-3-srikar@linux.vnet.ibm.com --- arch/powerpc/mm/numa.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 3c7dec70cda0..2cb87c9a0544 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1191,23 +1191,30 @@ static long vphn_get_associativity(unsigned long cpu, VPHN_FLAG_VCPU, associativity); switch (rc) { - case H_FUNCTION: - printk_once(KERN_INFO - "VPHN is not supported. Disabling polling...\n"); - stop_topology_update(); - break; - case H_HARDWARE: - printk(KERN_ERR - "hcall_vphn() experienced a hardware fault " - "preventing VPHN. Disabling polling...\n"); - stop_topology_update(); - break; case H_SUCCESS: dbg("VPHN hcall succeeded. Reset polling...\n"); timed_topology_update(0); + goto out; + + case H_FUNCTION: + pr_err_ratelimited("VPHN unsupported. Disabling polling...\n"); + break; + case H_HARDWARE: + pr_err_ratelimited("hcall_vphn() experienced a hardware fault " + "preventing VPHN. Disabling polling...\n"); + break; + case H_PARAMETER: + pr_err_ratelimited("hcall_vphn() was passed an invalid parameter. " + "Disabling polling...\n"); + break; + default: + pr_err_ratelimited("hcall_vphn() returned %ld. Disabling polling...\n" + , rc); break; } + stop_topology_update(); +out: return rc; } From 413e40550c5cfdba7e062aa6350a0d2448014519 Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:22:59 +0530 Subject: [PATCH 166/809] powerpc/numa: Use cpu node map of first sibling thread All the sibling threads of a core have to be part of the same node. To ensure that all the sibling threads map to the same node, always lookup/update the cpu-to-node map of the first thread in the core. Signed-off-by: Srikar Dronamraju Reported-by: Abdul Haleem Reviewed-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135301.24739-4-srikar@linux.vnet.ibm.com --- arch/powerpc/mm/numa.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 2cb87c9a0544..518c6dbbccbe 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -467,15 +467,20 @@ static int of_drconf_to_nid_single(struct drmem_lmb *lmb) */ static int numa_setup_cpu(unsigned long lcpu) { - int nid = NUMA_NO_NODE; struct device_node *cpu; + int fcpu = cpu_first_thread_sibling(lcpu); + int nid = NUMA_NO_NODE; /* * If a valid cpu-to-node mapping is already available, use it * directly instead of querying the firmware, since it represents * the most recent mapping notified to us by the platform (eg: VPHN). + * Since cpu_to_node binding remains the same for all threads in the + * core. If a valid cpu-to-node mapping is already available, for + * the first thread in the core, use it. */ - if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) { + nid = numa_cpu_lookup_table[fcpu]; + if (nid >= 0) { map_cpu_to_node(lcpu, nid); return nid; } @@ -496,6 +501,19 @@ out_present: if (nid < 0 || !node_possible(nid)) nid = first_online_node; + /* + * Update for the first thread of the core. All threads of a core + * have to be part of the same node. This not only avoids querying + * for every other thread in the core, but always avoids a case + * where virtual node associativity change causes subsequent threads + * of a core to be associated with different nid. However if first + * thread is already online, expect it to have a valid mapping. + */ + if (fcpu != lcpu) { + WARN_ON(cpu_online(fcpu)); + map_cpu_to_node(fcpu, nid); + } + map_cpu_to_node(lcpu, nid); of_node_put(cpu); out: From dc909d8b0c9c0d2c42dc1cf34216c4830f639f7b Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:23:00 +0530 Subject: [PATCH 167/809] powerpc/numa: Early request for home node associativity Currently the kernel detects if its running on a shared lpar platform and requests home node associativity before the scheduler sched_domains are setup. However between the time NUMA setup is initialized and the request for home node associativity, workqueue initializes its per node cpumask. The per node workqueue possible cpumask may turn invalid after home node associativity resulting in weird situations like workqueue possible cpumask being a subset of workqueue online cpumask. This can be fixed by requesting home node associativity earlier just before NUMA setup. However at the NUMA setup time, kernel may not be in a position to detect if its running on a shared lpar platform. So request for home node associativity and if the request fails, fallback on the device tree property. Signed-off-by: Srikar Dronamraju Reported-by: Abdul Haleem Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135301.24739-5-srikar@linux.vnet.ibm.com --- arch/powerpc/mm/numa.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 518c6dbbccbe..5a8abf0165d7 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -461,6 +461,41 @@ static int of_drconf_to_nid_single(struct drmem_lmb *lmb) return nid; } +#ifdef CONFIG_PPC_SPLPAR +static int vphn_get_nid(long lcpu) +{ + __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0}; + long rc, hwid; + + /* + * On a shared lpar, device tree will not have node associativity. + * At this time lppaca, or its __old_status field may not be + * updated. Hence kernel cannot detect if its on a shared lpar. So + * request an explicit associativity irrespective of whether the + * lpar is shared or dedicated. Use the device tree property as a + * fallback. cpu_to_phys_id is only valid between + * smp_setup_cpu_maps() and smp_setup_pacas(). + */ + if (firmware_has_feature(FW_FEATURE_VPHN)) { + if (cpu_to_phys_id) + hwid = cpu_to_phys_id[lcpu]; + else + hwid = get_hard_smp_processor_id(lcpu); + + rc = hcall_vphn(hwid, VPHN_FLAG_VCPU, associativity); + if (rc == H_SUCCESS) + return associativity_to_nid(associativity); + } + + return NUMA_NO_NODE; +} +#else +static int vphn_get_nid(long unused) +{ + return NUMA_NO_NODE; +} +#endif /* CONFIG_PPC_SPLPAR */ + /* * Figure out to which domain a cpu belongs and stick it there. * Return the id of the domain used. @@ -485,6 +520,10 @@ static int numa_setup_cpu(unsigned long lcpu) return nid; } + nid = vphn_get_nid(lcpu); + if (nid != NUMA_NO_NODE) + goto out_present; + cpu = of_get_cpu_node(lcpu, NULL); if (!cpu) { @@ -496,6 +535,7 @@ static int numa_setup_cpu(unsigned long lcpu) } nid = of_node_to_nid_single(cpu); + of_node_put(cpu); out_present: if (nid < 0 || !node_possible(nid)) @@ -515,7 +555,6 @@ out_present: } map_cpu_to_node(lcpu, nid); - of_node_put(cpu); out: return nid; } From 247257b03b04398ca07da4bce3d17bee25d623cb Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 29 Jan 2020 19:23:01 +0530 Subject: [PATCH 168/809] powerpc/numa: Remove late request for home node associativity With commit ("powerpc/numa: Early request for home node associativity"), commit 2ea626306810 ("powerpc/topology: Get topology for shared processors at boot") which was requesting home node associativity becomes redundant. Hence remove the late request for home node associativity. Signed-off-by: Srikar Dronamraju Reported-by: Abdul Haleem Reviewed-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200129135301.24739-6-srikar@linux.vnet.ibm.com --- arch/powerpc/include/asm/topology.h | 4 ---- arch/powerpc/kernel/smp.c | 5 ----- arch/powerpc/mm/numa.c | 9 --------- 3 files changed, 18 deletions(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index e2e1ccd4a18d..2db7ba789720 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -98,7 +98,6 @@ extern int stop_topology_update(void); extern int prrn_is_enabled(void); extern int find_and_online_cpu_nid(int cpu); extern int timed_topology_update(int nsecs); -extern void __init shared_proc_topology_init(void); #else static inline int start_topology_update(void) { @@ -121,9 +120,6 @@ static inline int timed_topology_update(int nsecs) return 0; } -#ifdef CONFIG_SMP -static inline void shared_proc_topology_init(void) {} -#endif #endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */ #include diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index f68cde82bdf3..37c12e3bab9e 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1383,11 +1383,6 @@ void __init smp_cpus_done(unsigned int max_cpus) if (smp_ops && smp_ops->bringup_done) smp_ops->bringup_done(); - /* - * On a shared LPAR, associativity needs to be requested. - * Hence, get numa topology before dumping cpu topology - */ - shared_proc_topology_init(); dump_numa_cpu_topology(); #ifdef CONFIG_SCHED_SMT diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5a8abf0165d7..9fcf2d195830 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1632,15 +1632,6 @@ int prrn_is_enabled(void) return prrn_enabled; } -void __init shared_proc_topology_init(void) -{ - if (lppaca_shared_proc(get_lppaca())) { - bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask), - nr_cpumask_bits); - numa_update_cpu_topology(false); - } -} - static int topology_read(struct seq_file *file, void *v) { if (vphn_enabled || prrn_enabled) From f2eeca099bbda45029da35abecb428a9084a5463 Mon Sep 17 00:00:00 2001 From: Harshad Shirwadkar Date: Tue, 24 Dec 2019 11:09:40 -0800 Subject: [PATCH 169/809] ext4: force buffer up-to-date while marking it dirty Writeback errors can leave buffer in not up-to-date state when there are errors during background writes. Force buffer up-to-date while marking it dirty. Signed-off-by: Harshad Shirwadkar Link: https://lore.kernel.org/r/20191224190940.157952-1-harshadshirwadkar@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/ext4_jbd2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 1f53d64e42a5..ee3755c3110a 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -332,6 +332,7 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, err); } } else { + set_buffer_uptodate(bh); if (inode) mark_buffer_dirty_inode(bh, inode); else From 72f9da1d5c8d03d6fb242d01aae66928b2b2e7a8 Mon Sep 17 00:00:00 2001 From: Xiaoguang Wang Date: Fri, 7 Feb 2020 20:07:58 +0800 Subject: [PATCH 170/809] ext4: start to support iopoll method Since commit "b1b4705d54ab ext4: introduce direct I/O read using iomap infrastructure", we can easily make ext4 support iopoll method, just use iomap_dio_iopoll(). Reviewed-by: Jan Kara Signed-off-by: Xiaoguang Wang Link: https://lore.kernel.org/r/20200207120758.2411-1-xiaoguang.wang@linux.alibaba.com Signed-off-by: Theodore Ts'o --- fs/ext4/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 5f225881176b..0d624250a62b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -872,6 +872,7 @@ const struct file_operations ext4_file_operations = { .llseek = ext4_llseek, .read_iter = ext4_file_read_iter, .write_iter = ext4_file_write_iter, + .iopoll = iomap_dio_iopoll, .unlocked_ioctl = ext4_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext4_compat_ioctl, From a08fe66e4a0e12a3df982b28059f3a90e0f1b31e Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 10 Feb 2020 16:24:45 +0800 Subject: [PATCH 171/809] ext4: code cleanup for ext4_statfs_project() Calling min_not_zero() to simplify complicated prjquota limit comparison in ext4_statfs_project(). Signed-off-by: Chengguang Xu Link: https://lore.kernel.org/r/20200210082445.2379-1-cgxu519@mykernel.net Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 0c7c4adb664e..de5398c07161 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5622,10 +5622,8 @@ static int ext4_statfs_project(struct super_block *sb, return PTR_ERR(dquot); spin_lock(&dquot->dq_dqb_lock); - limit = dquot->dq_dqb.dqb_bsoftlimit; - if (dquot->dq_dqb.dqb_bhardlimit && - (!limit || dquot->dq_dqb.dqb_bhardlimit < limit)) - limit = dquot->dq_dqb.dqb_bhardlimit; + limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit, + dquot->dq_dqb.dqb_bhardlimit); limit >>= sb->s_blocksize_bits; if (limit && buf->f_blocks > limit) { @@ -5637,11 +5635,8 @@ static int ext4_statfs_project(struct super_block *sb, (buf->f_blocks - curblock) : 0; } - limit = dquot->dq_dqb.dqb_isoftlimit; - if (dquot->dq_dqb.dqb_ihardlimit && - (!limit || dquot->dq_dqb.dqb_ihardlimit < limit)) - limit = dquot->dq_dqb.dqb_ihardlimit; - + limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit, + dquot->dq_dqb.dqb_ihardlimit); if (limit && buf->f_files > limit) { buf->f_files = limit; buf->f_ffree = From 4337ecd1fe997d2b2135b4434caaccdb47c10c06 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Tue, 11 Feb 2020 16:02:16 -0500 Subject: [PATCH 172/809] ext4: remove EXT4_EOFBLOCKS_FL and associated code The EXT4_EOFBLOCKS_FL inode flag is used to indicate whether a file contains unwritten blocks past i_size. It's set when ext4_fallocate is called with the KEEP_SIZE flag to extend a file with an unwritten extent. However, this flag hasn't been useful functionally since March, 2012, when a decision was made to remove it from ext4. All traces of EXT4_EOFBLOCKS_FL were removed from e2fsprogs version 1.42.2 by commit 010dc7b90d97 ("e2fsck: remove EXT4_EOFBLOCKS_FL flag handling") at that time. Now that enough time has passed to make e2fsprogs versions containing this modification common, this patch now removes the code associated with EXT4_EOFBLOCKS_FL from the kernel as well. This change has two implications. First, because pre-1.42.2 e2fsck versions only look for a problem if EXT4_EOFBLOCKS_FL is set, and because that bit will never be set by newer kernels containing this patch, old versions of e2fsck won't have a compatibility problem with files created by newer kernels. Second, newer kernels will not clear EXT4_EOFBLOCKS_FL inode flag bits belonging to a file written by an older kernel. If set, it will remain in that state until the file is deleted. Because e2fsck versions since 1.42.2 don't check the flag at all, no adverse effect is expected. However, pre-1.42.2 e2fsck versions that do check the flag may report that it is set when it ought not to be after a file has been truncated or had its unwritten blocks written. In this case, the old version of e2fsck will offer to clear the flag. No adverse effect would then occur whether the user chooses to clear the flag or not. Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200211210216.24960-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 5 ++- fs/ext4/extents.c | 92 ++++------------------------------------------- fs/ext4/inode.c | 2 -- fs/ext4/ioctl.c | 12 ------- 4 files changed, 9 insertions(+), 102 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 61b37a052052..54f0a003053b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -414,7 +414,7 @@ struct flex_groups { #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_VERITY_FL 0x00100000 /* Verity protected inode */ #define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ -#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ +/* 0x00400000 was formerly EXT4_EOFBLOCKS_FL */ #define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */ #define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ #define EXT4_CASEFOLD_FL 0x40000000 /* Casefolded file */ @@ -487,7 +487,7 @@ enum { EXT4_INODE_EXTENTS = 19, /* Inode uses extents */ EXT4_INODE_VERITY = 20, /* Verity protected inode */ EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */ - EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */ +/* 22 was formerly EXT4_INODE_EOFBLOCKS */ EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */ EXT4_INODE_PROJINHERIT = 29, /* Create with parents projid */ EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */ @@ -533,7 +533,6 @@ static inline void ext4_check_flag_values(void) CHECK_FLAG_VALUE(EXTENTS); CHECK_FLAG_VALUE(VERITY); CHECK_FLAG_VALUE(EA_INODE); - CHECK_FLAG_VALUE(EOFBLOCKS); CHECK_FLAG_VALUE(INLINE_DATA); CHECK_FLAG_VALUE(PROJINHERIT); CHECK_FLAG_VALUE(RESERVED); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 954013d6076b..89aa9c7ae293 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3874,59 +3874,6 @@ out: return err; } -/* - * Handle EOFBLOCKS_FL flag, clearing it if necessary - */ -static int check_eofblocks_fl(handle_t *handle, struct inode *inode, - ext4_lblk_t lblk, - struct ext4_ext_path *path, - unsigned int len) -{ - int i, depth; - struct ext4_extent_header *eh; - struct ext4_extent *last_ex; - - if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)) - return 0; - - depth = ext_depth(inode); - eh = path[depth].p_hdr; - - /* - * We're going to remove EOFBLOCKS_FL entirely in future so we - * do not care for this case anymore. Simply remove the flag - * if there are no extents. - */ - if (unlikely(!eh->eh_entries)) - goto out; - last_ex = EXT_LAST_EXTENT(eh); - /* - * We should clear the EOFBLOCKS_FL flag if we are writing the - * last block in the last extent in the file. We test this by - * first checking to see if the caller to - * ext4_ext_get_blocks() was interested in the last block (or - * a block beyond the last block) in the current extent. If - * this turns out to be false, we can bail out from this - * function immediately. - */ - if (lblk + len < le32_to_cpu(last_ex->ee_block) + - ext4_ext_get_actual_len(last_ex)) - return 0; - /* - * If the caller does appear to be planning to write at or - * beyond the end of the current extent, we then test to see - * if the current extent is the last extent in the file, by - * checking to make sure it was reached via the rightmost node - * at each level of the tree. - */ - for (i = depth-1; i >= 0; i--) - if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) - return 0; -out: - ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - return ext4_mark_inode_dirty(handle, inode); -} - static int convert_initialized_extent(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, @@ -3991,9 +3938,7 @@ convert_initialized_extent(handle_t *handle, struct inode *inode, ext4_ext_show_leaf(inode, path); ext4_update_inode_fsync_trans(handle, inode, 1); - err = check_eofblocks_fl(handle, inode, map->m_lblk, path, map->m_len); - if (err) - return err; + map->m_flags |= EXT4_MAP_UNWRITTEN; if (allocated > map->m_len) allocated = map->m_len; @@ -4007,7 +3952,9 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, struct ext4_ext_path **ppath, int flags, unsigned int allocated, ext4_fsblk_t newblock) { +#ifdef EXT_DEBUG struct ext4_ext_path *path = *ppath; +#endif int ret = 0; int err = 0; @@ -4047,11 +3994,9 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, } ret = ext4_convert_unwritten_extents_endio(handle, inode, map, ppath); - if (ret >= 0) { + if (ret >= 0) ext4_update_inode_fsync_trans(handle, inode, 1); - err = check_eofblocks_fl(handle, inode, map->m_lblk, - path, map->m_len); - } else + else err = ret; map->m_flags |= EXT4_MAP_MAPPED; map->m_pblk = newblock; @@ -4100,12 +4045,6 @@ out: map_out: map->m_flags |= EXT4_MAP_MAPPED; - if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) { - err = check_eofblocks_fl(handle, inode, map->m_lblk, path, - map->m_len); - if (err < 0) - goto out2; - } out1: if (allocated > map->m_len) allocated = map->m_len; @@ -4459,12 +4398,7 @@ got_allocated_blocks: } err = 0; - if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) - err = check_eofblocks_fl(handle, inode, map->m_lblk, - path, ar.len); - if (!err) - err = ext4_ext_insert_extent(handle, inode, &path, - &newex, flags); + err = ext4_ext_insert_extent(handle, inode, &path, &newex, flags); if (err && free_on_err) { int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? @@ -4645,10 +4579,6 @@ retry: epos = new_size; if (ext4_update_inode_size(inode, epos) & 0x1) inode->i_mtime = inode->i_ctime; - } else { - if (epos > inode->i_size) - ext4_set_inode_flag(inode, - EXT4_INODE_EOFBLOCKS); } ext4_mark_inode_dirty(handle, inode); ext4_update_inode_fsync_trans(handle, inode, 1); @@ -4802,16 +4732,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, } inode->i_mtime = inode->i_ctime = current_time(inode); - if (new_size) { + if (new_size) ext4_update_inode_size(inode, new_size); - } else { - /* - * Mark that we allocate beyond EOF so the subsequent truncate - * can proceed even if the new size is the same as i_size. - */ - if (offset + len > inode->i_size) - ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - } ext4_mark_inode_dirty(handle, inode); /* Zero out partial block at the edges of the range */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index fa0ff78dc033..416aec6d6c65 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4144,8 +4144,6 @@ int ext4_truncate(struct inode *inode) if (!ext4_can_truncate(inode)) return 0; - ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a0ec750018dd..d0b00fab0531 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -327,18 +327,6 @@ static int ext4_ioctl_setflags(struct inode *inode, if ((flags ^ oldflags) & EXT4_EXTENTS_FL) migrate = 1; - if (flags & EXT4_EOFBLOCKS_FL) { - /* we don't support adding EOFBLOCKS flag */ - if (!(oldflags & EXT4_EOFBLOCKS_FL)) { - err = -EOPNOTSUPP; - goto flags_out; - } - } else if (oldflags & EXT4_EOFBLOCKS_FL) { - err = ext4_truncate(inode); - if (err) - goto flags_out; - } - if ((flags ^ oldflags) & EXT4_CASEFOLD_FL) { if (!ext4_has_feature_casefold(sb)) { err = -EOPNOTSUPP; From 765bfcd59a1ff799b1c71cb3be0c43b0775ec166 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Wed, 12 Feb 2020 11:21:41 -0500 Subject: [PATCH 173/809] ext4: delete declaration for ext4_split_extent() There are no forward references for ext4_split_extent() in extents.c, so delete its unnecessary declaration. Reviewed-by: Darrick J. Wong Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200212162141.22381-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 89aa9c7ae293..a5338a8da2ab 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -83,13 +83,6 @@ static void ext4_extent_block_csum_set(struct inode *inode, et->et_checksum = ext4_extent_block_csum(inode, eh); } -static int ext4_split_extent(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - struct ext4_map_blocks *map, - int split_flag, - int flags); - static int ext4_split_extent_at(handle_t *handle, struct inode *inode, struct ext4_ext_path **ppath, From 92e9c58c5629762001e7294afbdf1283d5c7d2ed Mon Sep 17 00:00:00 2001 From: Madhuparna Bhowmik Date: Thu, 13 Feb 2020 20:55:58 +0530 Subject: [PATCH 174/809] ext4: use built-in RCU list checking in mballoc list_for_each_entry_rcu() has built-in RCU and lock checking. Pass cond argument to list_for_each_entry_rcu() to silence false lockdep warning when CONFIG_PROVE_RCU_LIST is enabled by default. Signed-off-by: Madhuparna Bhowmik Link: https://lore.kernel.org/r/20200213152558.7070-1-madhuparnabhowmik10@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/mballoc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 51a78eb65f3c..1027e01c9011 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4302,7 +4302,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, spin_lock(&lg->lg_prealloc_lock); list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], - pa_inode_list) { + pa_inode_list, + lockdep_is_held(&lg->lg_prealloc_lock)) { spin_lock(&pa->pa_lock); if (atomic_read(&pa->pa_count)) { /* @@ -4386,7 +4387,8 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac) /* Add the prealloc space to lg */ spin_lock(&lg->lg_prealloc_lock); list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order], - pa_inode_list) { + pa_inode_list, + lockdep_is_held(&lg->lg_prealloc_lock)) { spin_lock(&tmp_pa->pa_lock); if (tmp_pa->pa_deleted) { spin_unlock(&tmp_pa->pa_lock); From 6cfb061fe9e901dd0b6cfa3ed50bc39c81523532 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Feb 2020 10:06:48 -0600 Subject: [PATCH 175/809] ext4: use flexible-array members in struct dx_node and struct dx_root The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200213160648.GA7054@embeddedor Signed-off-by: Theodore Ts'o --- fs/ext4/namei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index b05ea72f38fd..5f0a758956f6 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -233,13 +233,13 @@ struct dx_root u8 unused_flags; } info; - struct dx_entry entries[0]; + struct dx_entry entries[]; }; struct dx_node { struct fake_dirent fake; - struct dx_entry entries[0]; + struct dx_entry entries[]; }; From 780f66e59231fcf882f36c63f287252ee47cc75a Mon Sep 17 00:00:00 2001 From: "zhangyi (F)" Date: Mon, 17 Feb 2020 19:27:06 +0800 Subject: [PATCH 176/809] jbd2: improve comments about freeing data buffers whose page mapping is NULL Improve comments in jbd2_journal_commit_transaction() to describe why we don't need to clear the buffer_mapped bit for freeing file mapping buffers whose page mapping is NULL. Link: https://lore.kernel.org/r/20200217112706.20085-1-yi.zhang@huawei.com Fixes: c96dceeabf76 ("jbd2: do not clear the BH_Mapped flag when forgetting a metadata buffer") Suggested-by: Jan Kara Reviewed-by: Jan Kara Signed-off-by: zhangyi (F) Signed-off-by: Theodore Ts'o --- fs/jbd2/commit.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 27373f5792a4..e855d8260433 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -997,9 +997,10 @@ restart_loop: * journalled data) we need to unmap buffer and clear * more bits. We also need to be careful about the check * because the data page mapping can get cleared under - * out hands, which alse need not to clear more bits - * because the page and buffers will be freed and can - * never be reused once we are done with them. + * our hands. Note that if mapping == NULL, we don't + * need to make buffer unmapped because the page is + * already detached from the mapping and buffers cannot + * get reused. */ mapping = READ_ONCE(bh->b_page->mapping); if (mapping && !sb_is_blkdev_sb(mapping->host->i_sb)) { From f064a9d6e7dbd3473e9da0ffa1a91c08a032d747 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Tue, 18 Feb 2020 15:26:56 -0500 Subject: [PATCH 177/809] ext4: clean up error return for convert_initialized_extent() Although convert_initialized_extent() can potentially return an error code with a negative value, its returned value is assigned to an unsigned variable containing a block count in ext4_ext_map_blocks() and then returned to that function's caller. The code currently works, though the way this happens is obscure. The code would be more readable if it followed the error handling convention used elsewhere in ext4_ext_map_blocks(). This patch does not address any known test failure or bug report - it's simply a cleanup. It also addresses a nearby coding standard issue. Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200218202656.21561-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a5338a8da2ab..bc96529d1509 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3871,7 +3871,7 @@ static int convert_initialized_extent(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, struct ext4_ext_path **ppath, - unsigned int allocated) + unsigned int *allocated) { struct ext4_ext_path *path = *ppath; struct ext4_extent *ex; @@ -3933,10 +3933,10 @@ convert_initialized_extent(handle_t *handle, struct inode *inode, ext4_update_inode_fsync_trans(handle, inode, 1); map->m_flags |= EXT4_MAP_UNWRITTEN; - if (allocated > map->m_len) - allocated = map->m_len; - map->m_len = allocated; - return allocated; + if (*allocated > map->m_len) + *allocated = map->m_len; + map->m_len = *allocated; + return 0; } static int @@ -4240,12 +4240,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, */ if ((!ext4_ext_is_unwritten(ex)) && (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { - allocated = convert_initialized_extent( - handle, inode, map, &path, - allocated); + err = convert_initialized_extent(handle, + inode, map, &path, &allocated); goto out2; - } else if (!ext4_ext_is_unwritten(ex)) + } else if (!ext4_ext_is_unwritten(ex)) { goto out; + } ret = ext4_ext_handle_unwritten_extents( handle, inode, map, &path, flags, From 1acf1a564b6034b5af1e7fb23cb98cb3bb4f6003 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:32 +0900 Subject: [PATCH 178/809] exfat: add in-memory and on-disk structures and headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds in-memory and on-disk structures and headers. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/exfat_fs.h | 519 +++++++++++++++++++++++++++++++++++++++++++ fs/exfat/exfat_raw.h | 184 +++++++++++++++ 2 files changed, 703 insertions(+) create mode 100644 fs/exfat/exfat_fs.h create mode 100644 fs/exfat/exfat_raw.h diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h new file mode 100644 index 000000000000..67d4e46fb810 --- /dev/null +++ b/fs/exfat/exfat_fs.h @@ -0,0 +1,519 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#ifndef _EXFAT_FS_H +#define _EXFAT_FS_H + +#include +#include +#include + +#define EXFAT_SUPER_MAGIC 0x2011BAB0UL +#define EXFAT_ROOT_INO 1 + +#define EXFAT_SB_DIRTY 0 + +#define EXFAT_CLUSTERS_UNTRACKED (~0u) + +/* + * exfat error flags + */ +enum exfat_error_mode { + EXFAT_ERRORS_CONT, /* ignore error and continue */ + EXFAT_ERRORS_PANIC, /* panic on error */ + EXFAT_ERRORS_RO, /* remount r/o on error */ +}; + +/* + * exfat nls lossy flag + */ +enum { + NLS_NAME_NO_LOSSY, /* no lossy */ + NLS_NAME_LOSSY, /* just detected incorrect filename(s) */ + NLS_NAME_OVERLEN, /* the length is over than its limit */ +}; + +#define EXFAT_HASH_BITS 8 +#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) + +/* + * Type Definitions + */ +#define ES_2_ENTRIES 2 +#define ES_ALL_ENTRIES 0 + +#define DIR_DELETED 0xFFFF0321 + +/* type values */ +#define TYPE_UNUSED 0x0000 +#define TYPE_DELETED 0x0001 +#define TYPE_INVALID 0x0002 +#define TYPE_CRITICAL_PRI 0x0100 +#define TYPE_BITMAP 0x0101 +#define TYPE_UPCASE 0x0102 +#define TYPE_VOLUME 0x0103 +#define TYPE_DIR 0x0104 +#define TYPE_FILE 0x011F +#define TYPE_CRITICAL_SEC 0x0200 +#define TYPE_STREAM 0x0201 +#define TYPE_EXTEND 0x0202 +#define TYPE_ACL 0x0203 +#define TYPE_BENIGN_PRI 0x0400 +#define TYPE_GUID 0x0401 +#define TYPE_PADDING 0x0402 +#define TYPE_ACLTAB 0x0403 +#define TYPE_BENIGN_SEC 0x0800 +#define TYPE_ALL 0x0FFF + +#define MAX_CHARSET_SIZE 6 /* max size of multi-byte character */ +#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */ +#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE) + +#define FAT_CACHE_SIZE 128 +#define FAT_CACHE_HASH_SIZE 64 +#define BUF_CACHE_SIZE 256 +#define BUF_CACHE_HASH_SIZE 64 + +#define EXFAT_HINT_NONE -1 +#define EXFAT_MIN_SUBDIR 2 + +/* + * helpers for cluster size to byte conversion. + */ +#define EXFAT_CLU_TO_B(b, sbi) ((b) << (sbi)->cluster_size_bits) +#define EXFAT_B_TO_CLU(b, sbi) ((b) >> (sbi)->cluster_size_bits) +#define EXFAT_B_TO_CLU_ROUND_UP(b, sbi) \ + (((b - 1) >> (sbi)->cluster_size_bits) + 1) +#define EXFAT_CLU_OFFSET(off, sbi) ((off) & ((sbi)->cluster_size - 1)) + +/* + * helpers for block size to byte conversion. + */ +#define EXFAT_BLK_TO_B(b, sb) ((b) << (sb)->s_blocksize_bits) +#define EXFAT_B_TO_BLK(b, sb) ((b) >> (sb)->s_blocksize_bits) +#define EXFAT_B_TO_BLK_ROUND_UP(b, sb) \ + (((b - 1) >> (sb)->s_blocksize_bits) + 1) +#define EXFAT_BLK_OFFSET(off, sb) ((off) & ((sb)->s_blocksize - 1)) + +/* + * helpers for block size to dentry size conversion. + */ +#define EXFAT_B_TO_DEN_IDX(b, sbi) \ + ((b) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS)) +#define EXFAT_B_TO_DEN(b) ((b) >> DENTRY_SIZE_BITS) +#define EXFAT_DEN_TO_B(b) ((b) << DENTRY_SIZE_BITS) + +/* + * helpers for fat entry. + */ +#define FAT_ENT_SIZE (4) +#define FAT_ENT_SIZE_BITS (2) +#define FAT_ENT_OFFSET_SECTOR(sb, loc) (EXFAT_SB(sb)->FAT1_start_sector + \ + (((u64)loc << FAT_ENT_SIZE_BITS) >> sb->s_blocksize_bits)) +#define FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc) \ + ((loc << FAT_ENT_SIZE_BITS) & (sb->s_blocksize - 1)) + +/* + * helpers for bitmap. + */ +#define CLUSTER_TO_BITMAP_ENT(clu) ((clu) - EXFAT_RESERVED_CLUSTERS) +#define BITMAP_ENT_TO_CLUSTER(ent) ((ent) + EXFAT_RESERVED_CLUSTERS) +#define BITS_PER_SECTOR(sb) ((sb)->s_blocksize * BITS_PER_BYTE) +#define BITS_PER_SECTOR_MASK(sb) (BITS_PER_SECTOR(sb) - 1) +#define BITMAP_OFFSET_SECTOR_INDEX(sb, ent) \ + ((ent / BITS_PER_BYTE) >> (sb)->s_blocksize_bits) +#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb)) +#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \ + ((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1)) +#define BITS_PER_BYTE_MASK 0x7 +#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1) + +struct exfat_dentry_namebuf { + char *lfn; + int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ +}; + +/* unicode name structure */ +struct exfat_uni_name { + /* +3 for null and for converting */ + unsigned short name[MAX_NAME_LENGTH + 3]; + unsigned short name_hash; + unsigned char name_len; +}; + +/* directory structure */ +struct exfat_chain { + unsigned int dir; + unsigned int size; + unsigned char flags; +}; + +/* first empty entry hint information */ +struct exfat_hint_femp { + /* entry index of a directory */ + int eidx; + /* count of continuous empty entry */ + int count; + /* the cluster that first empty slot exists in */ + struct exfat_chain cur; +}; + +/* hint structure */ +struct exfat_hint { + unsigned int clu; + union { + unsigned int off; /* cluster offset */ + int eidx; /* entry index */ + }; +}; + +struct exfat_entry_set_cache { + /* sector number that contains file_entry */ + sector_t sector; + /* byte offset in the sector */ + unsigned int offset; + /* flag in stream entry. 01 for cluster chain, 03 for contig. */ + int alloc_flag; + unsigned int num_entries; + struct exfat_dentry entries[]; +}; + +struct exfat_dir_entry { + struct exfat_chain dir; + int entry; + unsigned int type; + unsigned int start_clu; + unsigned char flags; + unsigned short attr; + loff_t size; + unsigned int num_subdirs; + struct timespec64 atime; + struct timespec64 mtime; + struct timespec64 crtime; + struct exfat_dentry_namebuf namebuf; +}; + +/* + * exfat mount in-memory data + */ +struct exfat_mount_options { + kuid_t fs_uid; + kgid_t fs_gid; + unsigned short fs_fmask; + unsigned short fs_dmask; + /* permission for setting the [am]time */ + unsigned short allow_utime; + /* charset for filename input/display */ + char *iocharset; + /* on error: continue, panic, remount-ro */ + enum exfat_error_mode errors; + unsigned utf8:1, /* Use of UTF-8 character set */ + discard:1; /* Issue discard requests on deletions */ + int time_offset; /* Offset of timestamps from UTC (in minutes) */ +}; + +/* + * EXFAT file system superblock in-memory data + */ +struct exfat_sb_info { + unsigned long long num_sectors; /* num of sectors in volume */ + unsigned int num_clusters; /* num of clusters in volume */ + unsigned int cluster_size; /* cluster size in bytes */ + unsigned int cluster_size_bits; + unsigned int sect_per_clus; /* cluster size in sectors */ + unsigned int sect_per_clus_bits; + unsigned long long FAT1_start_sector; /* FAT1 start sector */ + unsigned long long FAT2_start_sector; /* FAT2 start sector */ + unsigned long long data_start_sector; /* data area start sector */ + unsigned int num_FAT_sectors; /* num of FAT sectors */ + unsigned int root_dir; /* root dir cluster */ + unsigned int dentries_per_clu; /* num of dentries per cluster */ + unsigned int vol_flag; /* volume dirty flag */ + struct buffer_head *pbr_bh; /* buffer_head of PBR sector */ + + unsigned int map_clu; /* allocation bitmap start cluster */ + unsigned int map_sectors; /* num of allocation bitmap sectors */ + struct buffer_head **vol_amap; /* allocation bitmap */ + + unsigned short *vol_utbl; /* upcase table */ + + unsigned int clu_srch_ptr; /* cluster search pointer */ + unsigned int used_clusters; /* number of used clusters */ + + unsigned long s_state; + struct mutex s_lock; /* superblock lock */ + struct exfat_mount_options options; + struct nls_table *nls_io; /* Charset used for input and display */ + struct ratelimit_state ratelimit; + + spinlock_t inode_hash_lock; + struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; + + struct rcu_head rcu; +}; + +/* + * EXFAT file system inode in-memory data + */ +struct exfat_inode_info { + struct exfat_chain dir; + int entry; + unsigned int type; + unsigned short attr; + unsigned int start_clu; + unsigned char flags; + /* + * the copy of low 32bit of i_version to check + * the validation of hint_stat. + */ + unsigned int version; + /* file offset or dentry index for readdir */ + loff_t rwoffset; + + /* hint for cluster last accessed */ + struct exfat_hint hint_bmap; + /* hint for entry index we try to lookup next time */ + struct exfat_hint hint_stat; + /* hint for first empty entry */ + struct exfat_hint_femp hint_femp; + + spinlock_t cache_lru_lock; + struct list_head cache_lru; + int nr_caches; + /* for avoiding the race between alloc and free */ + unsigned int cache_valid_id; + + /* + * NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access. + * physically allocated size. + */ + loff_t i_size_ondisk; + /* block-aligned i_size (used in cont_write_begin) */ + loff_t i_size_aligned; + /* on-disk position of directory entry or 0 */ + loff_t i_pos; + /* hash by i_location */ + struct hlist_node i_hash_fat; + /* protect bmap against truncate */ + struct rw_semaphore truncate_lock; + struct inode vfs_inode; + /* File creation time */ + struct timespec64 i_crtime; +}; + +static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) +{ + return container_of(inode, struct exfat_inode_info, vfs_inode); +} + +/* + * If ->i_mode can't hold 0222 (i.e. ATTR_RO), we use ->i_attrs to + * save ATTR_RO instead of ->i_mode. + * + * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only + * bit, it's just used as flag for app. + */ +static inline int exfat_mode_can_hold_ro(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + if (S_ISDIR(inode->i_mode)) + return 0; + + if ((~sbi->options.fs_fmask) & 0222) + return 1; + return 0; +} + +/* Convert attribute bits and a mask to the UNIX mode. */ +static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, + unsigned short attr, mode_t mode) +{ + if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) + mode &= ~0222; + + if (attr & ATTR_SUBDIR) + return (mode & ~sbi->options.fs_dmask) | S_IFDIR; + + return (mode & ~sbi->options.fs_fmask) | S_IFREG; +} + +/* Return the FAT attribute byte for this inode */ +static inline unsigned short exfat_make_attr(struct inode *inode) +{ + unsigned short attr = EXFAT_I(inode)->attr; + + if (S_ISDIR(inode->i_mode)) + attr |= ATTR_SUBDIR; + if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) + attr |= ATTR_READONLY; + return attr; +} + +static inline void exfat_save_attr(struct inode *inode, unsigned short attr) +{ + if (exfat_mode_can_hold_ro(inode)) + EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY); + else + EXFAT_I(inode)->attr = attr & ATTR_RWMASK; +} + +static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi, + sector_t sec) +{ + return ((sec - sbi->data_start_sector + 1) & + ((1 << sbi->sect_per_clus_bits) - 1)) == 0; +} + +static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi, + unsigned int clus) +{ + return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + + sbi->data_start_sector; +} + +static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, + sector_t sec) +{ + return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) + + EXFAT_RESERVED_CLUSTERS; +} + +/* super.c */ +int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag); + +/* fatent.c */ +#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) + +int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, + struct exfat_chain *p_chain); +int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain); +int exfat_ent_get(struct super_block *sb, unsigned int loc, + unsigned int *content); +int exfat_ent_set(struct super_block *sb, unsigned int loc, + unsigned int content); +int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, + int entry, struct exfat_dentry *p_entry); +int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, + unsigned int len); +int exfat_zeroed_cluster(struct inode *dir, unsigned int clu); +int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, + unsigned int *ret_clu); +int exfat_count_num_clusters(struct super_block *sb, + struct exfat_chain *p_chain, unsigned int *ret_count); + +/* balloc.c */ +int exfat_load_bitmap(struct super_block *sb); +void exfat_free_bitmap(struct exfat_sb_info *sbi); +int exfat_set_bitmap(struct inode *inode, unsigned int clu); +void exfat_clear_bitmap(struct inode *inode, unsigned int clu); +unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); +int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); + +/* file.c */ +extern const struct file_operations exfat_file_operations; +int __exfat_truncate(struct inode *inode, loff_t new_size); +void exfat_truncate(struct inode *inode, loff_t size); +int exfat_setattr(struct dentry *dentry, struct iattr *attr); +int exfat_getattr(const struct path *path, struct kstat *stat, + unsigned int request_mask, unsigned int query_flags); + +/* namei.c */ +extern const struct dentry_operations exfat_dentry_ops; +extern const struct dentry_operations exfat_utf8_dentry_ops; + +/* cache.c */ +int exfat_cache_init(void); +void exfat_cache_shutdown(void); +void exfat_cache_init_inode(struct inode *inode); +void exfat_cache_inval_inode(struct inode *inode); +int exfat_get_cluster(struct inode *inode, unsigned int cluster, + unsigned int *fclus, unsigned int *dclus, + unsigned int *last_dclus, int allow_eof); + +/* dir.c */ +extern const struct inode_operations exfat_dir_inode_operations; +extern const struct file_operations exfat_dir_operations; +unsigned int exfat_get_entry_type(struct exfat_dentry *p_entry); +int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, + int entry, unsigned int type, unsigned int start_clu, + unsigned long long size); +int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, + int entry, int num_entries, struct exfat_uni_name *p_uniname); +int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, + int entry, int order, int num_entries); +int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, + int entry); +int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, + struct exfat_entry_set_cache *es, int sync); +int exfat_calc_num_entries(struct exfat_uni_name *p_uniname); +int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, + struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, + int num_entries, unsigned int type); +int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu); +int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, + int entry, sector_t *sector, int *offset); +struct exfat_dentry *exfat_get_dentry(struct super_block *sb, + struct exfat_chain *p_dir, int entry, struct buffer_head **bh, + sector_t *sector); +struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, + struct exfat_chain *p_dir, int entry, unsigned int type, + struct exfat_dentry **file_ep); +int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir); + +/* inode.c */ +extern const struct inode_operations exfat_file_inode_operations; +void exfat_sync_inode(struct inode *inode); +struct inode *exfat_build_inode(struct super_block *sb, + struct exfat_dir_entry *info, loff_t i_pos); +void exfat_hash_inode(struct inode *inode, loff_t i_pos); +void exfat_unhash_inode(struct inode *inode); +struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); +int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); +void exfat_evict_inode(struct inode *inode); +int exfat_block_truncate_page(struct inode *inode, loff_t from); + +/* exfat/nls.c */ +unsigned short exfat_toupper(struct super_block *sb, unsigned short a); +int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, + unsigned short *b, unsigned int len); +int exfat_utf16_to_nls(struct super_block *sb, + struct exfat_uni_name *uniname, unsigned char *p_cstring, + int len); +int exfat_nls_to_utf16(struct super_block *sb, + const unsigned char *p_cstring, const int len, + struct exfat_uni_name *uniname, int *p_lossy); +int exfat_create_upcase_table(struct super_block *sb); +void exfat_free_upcase_table(struct exfat_sb_info *sbi); +unsigned short exfat_high_surrogate(unicode_t u); +unsigned short exfat_low_surrogate(unicode_t u); + +/* exfat/misc.c */ +void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) + __printf(3, 4) __cold; +#define exfat_fs_error(sb, fmt, args...) \ + __exfat_fs_error(sb, 1, fmt, ## args) +#define exfat_fs_error_ratelimit(sb, fmt, args...) \ + __exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), \ + fmt, ## args) +void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) + __printf(3, 4) __cold; +void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, + u8 tz, __le16 time, __le16 date, u8 time_ms); +void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, + u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); +unsigned short exfat_calc_chksum_2byte(void *data, int len, + unsigned short chksum, int type); +void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); +void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, + unsigned int size, unsigned char flags); +void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); + +#endif /* !_EXFAT_FS_H */ diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h new file mode 100644 index 000000000000..2a841010e649 --- /dev/null +++ b/fs/exfat/exfat_raw.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#ifndef _EXFAT_RAW_H +#define _EXFAT_RAW_H + +#include + +#define PBR_SIGNATURE 0xAA55 + +#define EXFAT_MAX_FILE_LEN 255 + +#define VOL_CLEAN 0x0000 +#define VOL_DIRTY 0x0002 + +#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu +#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u +#define EXFAT_FREE_CLUSTER 0 +/* Cluster 0, 1 are reserved, the first cluster is 2 in the cluster heap. */ +#define EXFAT_RESERVED_CLUSTERS 2 +#define EXFAT_FIRST_CLUSTER 2 +#define EXFAT_DATA_CLUSTER_COUNT(sbi) \ + ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) + +/* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ +#define ALLOC_FAT_CHAIN 0x01 +#define ALLOC_NO_FAT_CHAIN 0x03 + +#define DENTRY_SIZE 32 /* directory entry size */ +#define DENTRY_SIZE_BITS 5 +/* exFAT allows 8388608(256MB) directory entries */ +#define MAX_EXFAT_DENTRIES 8388608 + +/* dentry types */ +#define EXFAT_UNUSED 0x00 /* end of directory */ +#define EXFAT_DELETE (~0x80) +#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */ +#define EXFAT_INVAL 0x80 /* invalid value */ +#define EXFAT_BITMAP 0x81 /* allocation bitmap */ +#define EXFAT_UPCASE 0x82 /* upcase table */ +#define EXFAT_VOLUME 0x83 /* volume label */ +#define EXFAT_FILE 0x85 /* file or dir */ +#define EXFAT_GUID 0xA0 +#define EXFAT_PADDING 0xA1 +#define EXFAT_ACLTAB 0xA2 +#define EXFAT_STREAM 0xC0 /* stream entry */ +#define EXFAT_NAME 0xC1 /* file name entry */ +#define EXFAT_ACL 0xC2 /* stream entry */ + +#define IS_EXFAT_CRITICAL_PRI(x) (x < 0xA0) +#define IS_EXFAT_BENIGN_PRI(x) (x < 0xC0) +#define IS_EXFAT_CRITICAL_SEC(x) (x < 0xE0) + +/* checksum types */ +#define CS_DIR_ENTRY 0 +#define CS_PBR_SECTOR 1 +#define CS_DEFAULT 2 + +/* file attributes */ +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_SUBDIR 0x0010 +#define ATTR_ARCHIVE 0x0020 + +#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \ + ATTR_SUBDIR | ATTR_ARCHIVE) + +#define PBR64_JUMP_BOOT_LEN 3 +#define PBR64_OEM_NAME_LEN 8 +#define PBR64_RESERVED_LEN 53 + +#define EXFAT_FILE_NAME_LEN 15 + +/* EXFAT BIOS parameter block (64 bytes) */ +struct bpb64 { + __u8 jmp_boot[PBR64_JUMP_BOOT_LEN]; + __u8 oem_name[PBR64_OEM_NAME_LEN]; + __u8 res_zero[PBR64_RESERVED_LEN]; +} __packed; + +/* EXFAT EXTEND BIOS parameter block (56 bytes) */ +struct bsx64 { + __le64 vol_offset; + __le64 vol_length; + __le32 fat_offset; + __le32 fat_length; + __le32 clu_offset; + __le32 clu_count; + __le32 root_cluster; + __le32 vol_serial; + __u8 fs_version[2]; + __le16 vol_flags; + __u8 sect_size_bits; + __u8 sect_per_clus_bits; + __u8 num_fats; + __u8 phy_drv_no; + __u8 perc_in_use; + __u8 reserved2[7]; +} __packed; + +/* EXFAT PBR[BPB+BSX] (120 bytes) */ +struct pbr64 { + struct bpb64 bpb; + struct bsx64 bsx; +} __packed; + +/* Common PBR[Partition Boot Record] (512 bytes) */ +struct pbr { + union { + __u8 raw[64]; + struct bpb64 f64; + } bpb; + union { + __u8 raw[56]; + struct bsx64 f64; + } bsx; + __u8 boot_code[390]; + __le16 signature; +} __packed; + +struct exfat_dentry { + __u8 type; + union { + struct { + __u8 num_ext; + __le16 checksum; + __le16 attr; + __le16 reserved1; + __le16 create_time; + __le16 create_date; + __le16 modify_time; + __le16 modify_date; + __le16 access_time; + __le16 access_date; + __u8 create_time_ms; + __u8 modify_time_ms; + __u8 create_tz; + __u8 modify_tz; + __u8 access_tz; + __u8 reserved2[7]; + } __packed file; /* file directory entry */ + struct { + __u8 flags; + __u8 reserved1; + __u8 name_len; + __le16 name_hash; + __le16 reserved2; + __le64 valid_size; + __le32 reserved3; + __le32 start_clu; + __le64 size; + } __packed stream; /* stream extension directory entry */ + struct { + __u8 flags; + __le16 unicode_0_14[EXFAT_FILE_NAME_LEN]; + } __packed name; /* file name directory entry */ + struct { + __u8 flags; + __u8 reserved[18]; + __le32 start_clu; + __le64 size; + } __packed bitmap; /* allocation bitmap directory entry */ + struct { + __u8 reserved1[3]; + __le32 checksum; + __u8 reserved2[12]; + __le32 start_clu; + __le64 size; + } __packed upcase; /* up-case table directory entry */ + } __packed dentry; +} __packed; + +#define EXFAT_TZ_VALID (1 << 7) + +/* Jan 1 GMT 00:00:00 1980 */ +#define EXFAT_MIN_TIMESTAMP_SECS 315532800LL +/* Dec 31 GMT 23:59:59 2107 */ +#define EXFAT_MAX_TIMESTAMP_SECS 4354819199LL + +#endif /* !_EXFAT_RAW_H */ From 719c1e1829166da399903b13da6dcc5344e73449 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:33 +0900 Subject: [PATCH 179/809] exfat: add super block operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of superblock operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Reviewed-by: Arnd Bergmann Signed-off-by: Al Viro --- fs/exfat/super.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 728 insertions(+) create mode 100644 fs/exfat/super.c diff --git a/fs/exfat/super.c b/fs/exfat/super.c new file mode 100644 index 000000000000..f06e0b53e393 --- /dev/null +++ b/fs/exfat/super.c @@ -0,0 +1,728 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; +static struct kmem_cache *exfat_inode_cachep; + +static void exfat_free_iocharset(struct exfat_sb_info *sbi) +{ + if (sbi->options.iocharset != exfat_default_iocharset) + kfree(sbi->options.iocharset); +} + +static void exfat_delayed_free(struct rcu_head *p) +{ + struct exfat_sb_info *sbi = container_of(p, struct exfat_sb_info, rcu); + + unload_nls(sbi->nls_io); + exfat_free_iocharset(sbi); + exfat_free_upcase_table(sbi); + kfree(sbi); +} + +static void exfat_put_super(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + mutex_lock(&sbi->s_lock); + if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) + sync_blockdev(sb->s_bdev); + exfat_set_vol_flags(sb, VOL_CLEAN); + exfat_free_bitmap(sbi); + mutex_unlock(&sbi->s_lock); + + call_rcu(&sbi->rcu, exfat_delayed_free); +} + +static int exfat_sync_fs(struct super_block *sb, int wait) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int err = 0; + + /* If there are some dirty buffers in the bdev inode */ + mutex_lock(&sbi->s_lock); + if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) { + sync_blockdev(sb->s_bdev); + if (exfat_set_vol_flags(sb, VOL_CLEAN)) + err = -EIO; + } + mutex_unlock(&sbi->s_lock); + return err; +} + +static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned long long id = huge_encode_dev(sb->s_bdev->bd_dev); + + if (sbi->used_clusters == EXFAT_CLUSTERS_UNTRACKED) { + mutex_lock(&sbi->s_lock); + if (exfat_count_used_clusters(sb, &sbi->used_clusters)) { + mutex_unlock(&sbi->s_lock); + return -EIO; + } + mutex_unlock(&sbi->s_lock); + } + + buf->f_type = sb->s_magic; + buf->f_bsize = sbi->cluster_size; + buf->f_blocks = sbi->num_clusters - 2; /* clu 0 & 1 */ + buf->f_bfree = buf->f_blocks - sbi->used_clusters; + buf->f_bavail = buf->f_bfree; + buf->f_fsid.val[0] = (unsigned int)id; + buf->f_fsid.val[1] = (unsigned int)(id >> 32); + /* Unicode utf16 255 characters */ + buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE; + return 0; +} + +int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct pbr64 *bpb; + bool sync = 0; + + /* flags are not changed */ + if (sbi->vol_flag == new_flag) + return 0; + + sbi->vol_flag = new_flag; + + /* skip updating volume dirty flag, + * if this volume has been mounted with read-only + */ + if (sb_rdonly(sb)) + return 0; + + if (!sbi->pbr_bh) { + sbi->pbr_bh = sb_bread(sb, 0); + if (!sbi->pbr_bh) { + exfat_msg(sb, KERN_ERR, "failed to read boot sector"); + return -ENOMEM; + } + } + + bpb = (struct pbr64 *)sbi->pbr_bh->b_data; + bpb->bsx.vol_flags = cpu_to_le16(new_flag); + + if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh)) + sync = true; + else + sync = false; + + set_buffer_uptodate(sbi->pbr_bh); + mark_buffer_dirty(sbi->pbr_bh); + + if (sync) + sync_dirty_buffer(sbi->pbr_bh); + return 0; +} + +static int exfat_show_options(struct seq_file *m, struct dentry *root) +{ + struct super_block *sb = root->d_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_mount_options *opts = &sbi->options; + + /* Show partition info */ + if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, opts->fs_uid)); + if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, opts->fs_gid)); + seq_printf(m, ",fmask=%04o,dmask=%04o", opts->fs_fmask, opts->fs_dmask); + if (opts->allow_utime) + seq_printf(m, ",allow_utime=%04o", opts->allow_utime); + if (opts->utf8) + seq_puts(m, ",iocharset=utf8"); + else if (sbi->nls_io) + seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); + seq_printf(m, ",bps=%ld", sb->s_blocksize); + if (opts->errors == EXFAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == EXFAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); + if (opts->discard) + seq_puts(m, ",discard"); + if (opts->time_offset) + seq_printf(m, ",time_offset=%d", opts->time_offset); + return 0; +} + +static struct inode *exfat_alloc_inode(struct super_block *sb) +{ + struct exfat_inode_info *ei; + + ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); + if (!ei) + return NULL; + + init_rwsem(&ei->truncate_lock); + return &ei->vfs_inode; +} + +static void exfat_free_inode(struct inode *inode) +{ + kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); +} + +static const struct super_operations exfat_sops = { + .alloc_inode = exfat_alloc_inode, + .free_inode = exfat_free_inode, + .write_inode = exfat_write_inode, + .evict_inode = exfat_evict_inode, + .put_super = exfat_put_super, + .sync_fs = exfat_sync_fs, + .statfs = exfat_statfs, + .show_options = exfat_show_options, +}; + +enum { + Opt_uid, + Opt_gid, + Opt_umask, + Opt_dmask, + Opt_fmask, + Opt_allow_utime, + Opt_charset, + Opt_errors, + Opt_discard, + Opt_time_offset, +}; + +static const struct fs_parameter_spec exfat_param_specs[] = { + fsparam_u32("uid", Opt_uid), + fsparam_u32("gid", Opt_gid), + fsparam_u32oct("umask", Opt_umask), + fsparam_u32oct("dmask", Opt_dmask), + fsparam_u32oct("fmask", Opt_fmask), + fsparam_u32oct("allow_utime", Opt_allow_utime), + fsparam_string("iocharset", Opt_charset), + fsparam_enum("errors", Opt_errors), + fsparam_flag("discard", Opt_discard), + fsparam_s32("time_offset", Opt_time_offset), + {} +}; + +static const struct fs_parameter_enum exfat_param_enums[] = { + { Opt_errors, "continue", EXFAT_ERRORS_CONT }, + { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, + { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, + {} +}; + +static const struct fs_parameter_description exfat_parameters = { + .name = "exfat", + .specs = exfat_param_specs, + .enums = exfat_param_enums, +}; + +static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) +{ + struct exfat_sb_info *sbi = fc->s_fs_info; + struct exfat_mount_options *opts = &sbi->options; + struct fs_parse_result result; + int opt; + + opt = fs_parse(fc, &exfat_parameters, param, &result); + if (opt < 0) + return opt; + + switch (opt) { + case Opt_uid: + opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); + break; + case Opt_gid: + opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); + break; + case Opt_umask: + opts->fs_fmask = result.uint_32; + opts->fs_dmask = result.uint_32; + break; + case Opt_dmask: + opts->fs_dmask = result.uint_32; + break; + case Opt_fmask: + opts->fs_fmask = result.uint_32; + break; + case Opt_allow_utime: + opts->allow_utime = result.uint_32 & 0022; + break; + case Opt_charset: + exfat_free_iocharset(sbi); + opts->iocharset = kstrdup(param->string, GFP_KERNEL); + if (!opts->iocharset) + return -ENOMEM; + break; + case Opt_errors: + opts->errors = result.uint_32; + break; + case Opt_discard: + opts->discard = 1; + break; + case Opt_time_offset: + /* + * Make the limit 24 just in case someone invents something + * unusual. + */ + if (result.int_32 < -24 * 60 || result.int_32 > 24 * 60) + return -EINVAL; + opts->time_offset = result.int_32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void exfat_hash_init(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int i; + + spin_lock_init(&sbi->inode_hash_lock); + for (i = 0; i < EXFAT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); +} + +static int exfat_read_root(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_chain cdir; + int num_subdirs, num_clu = 0; + + exfat_chain_set(&ei->dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + ei->entry = -1; + ei->start_clu = sbi->root_dir; + ei->flags = ALLOC_FAT_CHAIN; + ei->type = TYPE_DIR; + ei->version = 0; + ei->rwoffset = 0; + ei->hint_bmap.off = EXFAT_EOF_CLUSTER; + ei->hint_stat.eidx = 0; + ei->hint_stat.clu = sbi->root_dir; + ei->hint_femp.eidx = EXFAT_HINT_NONE; + + exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + if (exfat_count_num_clusters(sb, &cdir, &num_clu)) + return -EIO; + i_size_write(inode, num_clu << sbi->cluster_size_bits); + + num_subdirs = exfat_count_dir_entries(sb, &cdir); + if (num_subdirs < 0) + return -EIO; + set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR); + + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + inode_inc_iversion(inode); + inode->i_generation = 0; + inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) + & ~(sbi->cluster_size - 1)) >> inode->i_blkbits; + EXFAT_I(inode)->i_pos = ((loff_t)sbi->root_dir << 32) | 0xffffffff; + EXFAT_I(inode)->i_size_aligned = i_size_read(inode); + EXFAT_I(inode)->i_size_ondisk = i_size_read(inode); + + exfat_save_attr(inode, ATTR_SUBDIR); + inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = + current_time(inode); + exfat_cache_init_inode(inode); + return 0; +} + +static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb, + struct buffer_head **prev_bh) +{ + struct pbr *p_pbr = (struct pbr *) (*prev_bh)->b_data; + unsigned short logical_sect = 0; + + logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; + + if (!is_power_of_2(logical_sect) || + logical_sect < 512 || logical_sect > 4096) { + exfat_msg(sb, KERN_ERR, "bogus logical sector size %u", + logical_sect); + return NULL; + } + + if (logical_sect < sb->s_blocksize) { + exfat_msg(sb, KERN_ERR, + "logical sector size too small for device (logical sector size = %u)", + logical_sect); + return NULL; + } + + if (logical_sect > sb->s_blocksize) { + struct buffer_head *bh = NULL; + + __brelse(*prev_bh); + *prev_bh = NULL; + + if (!sb_set_blocksize(sb, logical_sect)) { + exfat_msg(sb, KERN_ERR, + "unable to set blocksize %u", logical_sect); + return NULL; + } + bh = sb_bread(sb, 0); + if (!bh) { + exfat_msg(sb, KERN_ERR, + "unable to read boot sector (logical sector size = %lu)", + sb->s_blocksize); + return NULL; + } + + *prev_bh = bh; + p_pbr = (struct pbr *) bh->b_data; + } + return p_pbr; +} + +/* mount the file system volume */ +static int __exfat_fill_super(struct super_block *sb) +{ + int ret; + struct pbr *p_pbr; + struct pbr64 *p_bpb; + struct buffer_head *bh; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + /* set block size to read super block */ + sb_min_blocksize(sb, 512); + + /* read boot sector */ + bh = sb_bread(sb, 0); + if (!bh) { + exfat_msg(sb, KERN_ERR, "unable to read boot sector"); + return -EIO; + } + + /* PRB is read */ + p_pbr = (struct pbr *)bh->b_data; + + /* check the validity of PBR */ + if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) { + exfat_msg(sb, KERN_ERR, "invalid boot record signature"); + ret = -EINVAL; + goto free_bh; + } + + + /* check logical sector size */ + p_pbr = exfat_read_pbr_with_logical_sector(sb, &bh); + if (!p_pbr) { + ret = -EIO; + goto free_bh; + } + + /* + * res_zero field must be filled with zero to prevent mounting + * from FAT volume. + */ + if (memchr_inv(p_pbr->bpb.f64.res_zero, 0, + sizeof(p_pbr->bpb.f64.res_zero))) { + ret = -EINVAL; + goto free_bh; + } + + p_bpb = (struct pbr64 *)p_pbr; + if (!p_bpb->bsx.num_fats) { + exfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); + ret = -EINVAL; + goto free_bh; + } + + sbi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; + sbi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; + sbi->cluster_size_bits = sbi->sect_per_clus_bits + sb->s_blocksize_bits; + sbi->cluster_size = 1 << sbi->cluster_size_bits; + sbi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length); + sbi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset); + sbi->FAT2_start_sector = p_bpb->bsx.num_fats == 1 ? + sbi->FAT1_start_sector : + sbi->FAT1_start_sector + sbi->num_FAT_sectors; + sbi->data_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset); + sbi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length); + /* because the cluster index starts with 2 */ + sbi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + + EXFAT_RESERVED_CLUSTERS; + + sbi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster); + sbi->dentries_per_clu = 1 << + (sbi->cluster_size_bits - DENTRY_SIZE_BITS); + + sbi->vol_flag = le16_to_cpu(p_bpb->bsx.vol_flags); + sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; + sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED; + + if (le16_to_cpu(p_bpb->bsx.vol_flags) & VOL_DIRTY) { + sbi->vol_flag |= VOL_DIRTY; + exfat_msg(sb, KERN_WARNING, + "Volume was not properly unmounted. Some data may be corrupt. Please run fsck."); + } + + /* exFAT file size is limited by a disk volume size */ + sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << + sbi->cluster_size_bits; + + ret = exfat_create_upcase_table(sb); + if (ret) { + exfat_msg(sb, KERN_ERR, "failed to load upcase table"); + goto free_bh; + } + + ret = exfat_load_bitmap(sb); + if (ret) { + exfat_msg(sb, KERN_ERR, "failed to load alloc-bitmap"); + goto free_upcase_table; + } + + ret = exfat_count_used_clusters(sb, &sbi->used_clusters); + if (ret) { + exfat_msg(sb, KERN_ERR, "failed to scan clusters"); + goto free_alloc_bitmap; + } + + return 0; + +free_alloc_bitmap: + exfat_free_bitmap(sbi); +free_upcase_table: + exfat_free_upcase_table(sbi); +free_bh: + brelse(bh); + return ret; +} + +static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) +{ + struct exfat_sb_info *sbi = sb->s_fs_info; + struct exfat_mount_options *opts = &sbi->options; + struct inode *root_inode; + int err; + + if (opts->allow_utime == (unsigned short)-1) + opts->allow_utime = ~opts->fs_dmask & 0022; + + if (opts->discard) { + struct request_queue *q = bdev_get_queue(sb->s_bdev); + + if (!blk_queue_discard(q)) + exfat_msg(sb, KERN_WARNING, + "mounting with \"discard\" option, but the device does not support discard"); + opts->discard = 0; + } + + sb->s_flags |= SB_NODIRATIME; + sb->s_magic = EXFAT_SUPER_MAGIC; + sb->s_op = &exfat_sops; + + sb->s_time_gran = 1; + sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; + sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; + + err = __exfat_fill_super(sb); + if (err) { + exfat_msg(sb, KERN_ERR, "failed to recognize exfat type"); + goto check_nls_io; + } + + /* set up enough so that it can read an inode */ + exfat_hash_init(sb); + + if (!strcmp(sbi->options.iocharset, "utf8")) + opts->utf8 = 1; + else { + sbi->nls_io = load_nls(sbi->options.iocharset); + if (!sbi->nls_io) { + exfat_msg(sb, KERN_ERR, "IO charset %s not found", + sbi->options.iocharset); + err = -EINVAL; + goto free_table; + } + } + + if (sbi->options.utf8) + sb->s_d_op = &exfat_utf8_dentry_ops; + else + sb->s_d_op = &exfat_dentry_ops; + + root_inode = new_inode(sb); + if (!root_inode) { + exfat_msg(sb, KERN_ERR, "failed to allocate root inode."); + err = -ENOMEM; + goto free_table; + } + + root_inode->i_ino = EXFAT_ROOT_INO; + inode_set_iversion(root_inode, 1); + err = exfat_read_root(root_inode); + if (err) { + exfat_msg(sb, KERN_ERR, "failed to initialize root inode."); + goto put_inode; + } + + exfat_hash_inode(root_inode, EXFAT_I(root_inode)->i_pos); + insert_inode_hash(root_inode); + + sb->s_root = d_make_root(root_inode); + if (!sb->s_root) { + exfat_msg(sb, KERN_ERR, "failed to get the root dentry"); + err = -ENOMEM; + goto put_inode; + } + + return 0; + +put_inode: + iput(root_inode); + sb->s_root = NULL; + +free_table: + exfat_free_upcase_table(sbi); + exfat_free_bitmap(sbi); + +check_nls_io: + unload_nls(sbi->nls_io); + exfat_free_iocharset(sbi); + sb->s_fs_info = NULL; + kfree(sbi); + return err; +} + +static int exfat_get_tree(struct fs_context *fc) +{ + return get_tree_bdev(fc, exfat_fill_super); +} + +static void exfat_free(struct fs_context *fc) +{ + kfree(fc->s_fs_info); +} + +static const struct fs_context_operations exfat_context_ops = { + .parse_param = exfat_parse_param, + .get_tree = exfat_get_tree, + .free = exfat_free, +}; + +static int exfat_init_fs_context(struct fs_context *fc) +{ + struct exfat_sb_info *sbi; + + sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + + mutex_init(&sbi->s_lock); + ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + + sbi->options.fs_uid = current_uid(); + sbi->options.fs_gid = current_gid(); + sbi->options.fs_fmask = current->fs->umask; + sbi->options.fs_dmask = current->fs->umask; + sbi->options.allow_utime = -1; + sbi->options.iocharset = exfat_default_iocharset; + sbi->options.errors = EXFAT_ERRORS_RO; + + fc->s_fs_info = sbi; + fc->ops = &exfat_context_ops; + return 0; +} + +static struct file_system_type exfat_fs_type = { + .owner = THIS_MODULE, + .name = "exfat", + .init_fs_context = exfat_init_fs_context, + .parameters = &exfat_parameters, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; + +static void exfat_inode_init_once(void *foo) +{ + struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; + + INIT_HLIST_NODE(&ei->i_hash_fat); + inode_init_once(&ei->vfs_inode); +} + +static int __init init_exfat_fs(void) +{ + int err; + + err = exfat_cache_init(); + if (err) + return err; + + exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", + sizeof(struct exfat_inode_info), + 0, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, + exfat_inode_init_once); + if (!exfat_inode_cachep) { + err = -ENOMEM; + goto shutdown_cache; + } + + err = register_filesystem(&exfat_fs_type); + if (err) + goto destroy_cache; + + return 0; + +destroy_cache: + kmem_cache_destroy(exfat_inode_cachep); +shutdown_cache: + exfat_cache_shutdown(); + return err; +} + +static void __exit exit_exfat_fs(void) +{ + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); + kmem_cache_destroy(exfat_inode_cachep); + unregister_filesystem(&exfat_fs_type); + exfat_cache_shutdown(); +} + +module_init(init_exfat_fs); +module_exit(exit_exfat_fs); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("exFAT filesystem support"); +MODULE_AUTHOR("Samsung Electronics Co., Ltd."); From 5f2aa075070cf5b2e6aae011d5a3390408d7d913 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:34 +0900 Subject: [PATCH 180/809] exfat: add inode operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of inode operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/inode.c | 671 +++++++++++++++++++++ fs/exfat/namei.c | 1448 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2119 insertions(+) create mode 100644 fs/exfat/inode.c create mode 100644 fs/exfat/namei.c diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c new file mode 100644 index 000000000000..06887492f54b --- /dev/null +++ b/fs/exfat/inode.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static int __exfat_write_inode(struct inode *inode, int sync) +{ + int ret = -EIO; + unsigned long long on_disk_size; + struct exfat_dentry *ep, *ep2; + struct exfat_entry_set_cache *es = NULL; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + bool is_dir = (ei->type == TYPE_DIR) ? true : false; + + if (inode->i_ino == EXFAT_ROOT_INO) + return 0; + + /* + * If the indode is already unlinked, there is no need for updating it. + */ + if (ei->dir.dir == DIR_DELETED) + return 0; + + if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1) + return 0; + + exfat_set_vol_flags(sb, VOL_DIRTY); + + /* get the directory entry of given file or directory */ + es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES, + &ep); + if (!es) + return -EIO; + ep2 = ep + 1; + + ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode)); + + /* set FILE_INFO structure using the acquired struct exfat_dentry */ + exfat_set_entry_time(sbi, &ei->i_crtime, + &ep->dentry.file.create_tz, + &ep->dentry.file.create_time, + &ep->dentry.file.create_date, + &ep->dentry.file.create_time_ms); + exfat_set_entry_time(sbi, &inode->i_mtime, + &ep->dentry.file.modify_tz, + &ep->dentry.file.modify_time, + &ep->dentry.file.modify_date, + &ep->dentry.file.modify_time_ms); + exfat_set_entry_time(sbi, &inode->i_atime, + &ep->dentry.file.access_tz, + &ep->dentry.file.access_time, + &ep->dentry.file.access_date, + NULL); + + /* File size should be zero if there is no cluster allocated */ + on_disk_size = i_size_read(inode); + + if (ei->start_clu == EXFAT_EOF_CLUSTER) + on_disk_size = 0; + + ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); + ep2->dentry.stream.size = ep2->dentry.stream.valid_size; + + ret = exfat_update_dir_chksum_with_entry_set(sb, es, sync); + kfree(es); + return ret; +} + +int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) +{ + int ret; + + mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); + mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + + return ret; +} + +void exfat_sync_inode(struct inode *inode) +{ + lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock); + __exfat_write_inode(inode, 1); +} + +/* + * Input: inode, (logical) clu_offset, target allocation area + * Output: errcode, cluster number + * *clu = (~0), if it's unable to allocate a new cluster + */ +static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, + unsigned int *clu, int create) +{ + int ret, modified = false; + unsigned int last_clu; + struct exfat_chain new_clu; + struct exfat_dentry *ep; + struct exfat_entry_set_cache *es = NULL; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + unsigned int local_clu_offset = clu_offset; + unsigned int num_to_be_allocated = 0, num_clusters = 0; + + ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi); + + if (EXFAT_I(inode)->i_size_ondisk > 0) + num_clusters = + EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, + sbi); + + if (clu_offset >= num_clusters) + num_to_be_allocated = clu_offset - num_clusters + 1; + + if (!create && (num_to_be_allocated > 0)) { + *clu = EXFAT_EOF_CLUSTER; + return 0; + } + + *clu = last_clu = ei->start_clu; + + if (ei->flags == ALLOC_NO_FAT_CHAIN) { + if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + *clu = EXFAT_EOF_CLUSTER; + else + *clu += clu_offset; + } + } else if (ei->type == TYPE_FILE) { + unsigned int fclus = 0; + int err = exfat_get_cluster(inode, clu_offset, + &fclus, clu, &last_clu, 1); + if (err) + return -EIO; + + clu_offset -= fclus; + } else { + /* hint information */ + if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && + ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { + clu_offset -= ei->hint_bmap.off; + /* hint_bmap.clu should be valid */ + WARN_ON(ei->hint_bmap.clu < 2); + *clu = ei->hint_bmap.clu; + } + + while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { + last_clu = *clu; + if (exfat_get_next_cluster(sb, clu)) + return -EIO; + clu_offset--; + } + } + + if (*clu == EXFAT_EOF_CLUSTER) { + exfat_set_vol_flags(sb, VOL_DIRTY); + + new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ? + EXFAT_EOF_CLUSTER : last_clu + 1; + new_clu.size = 0; + new_clu.flags = ei->flags; + + /* allocate a cluster */ + if (num_to_be_allocated < 1) { + /* Broken FAT (i_sze > allocated FAT) */ + exfat_fs_error(sb, "broken FAT chain."); + return -EIO; + } + + ret = exfat_alloc_cluster(inode, num_to_be_allocated, &new_clu); + if (ret) + return ret; + + if (new_clu.dir == EXFAT_EOF_CLUSTER || + new_clu.dir == EXFAT_FREE_CLUSTER) { + exfat_fs_error(sb, + "bogus cluster new allocated (last_clu : %u, new_clu : %u)", + last_clu, new_clu.dir); + return -EIO; + } + + /* append to the FAT chain */ + if (last_clu == EXFAT_EOF_CLUSTER) { + if (new_clu.flags == ALLOC_FAT_CHAIN) + ei->flags = ALLOC_FAT_CHAIN; + ei->start_clu = new_clu.dir; + modified = true; + } else { + if (new_clu.flags != ei->flags) { + /* no-fat-chain bit is disabled, + * so fat-chain should be synced with + * alloc-bitmap + */ + exfat_chain_cont_cluster(sb, ei->start_clu, + num_clusters); + ei->flags = ALLOC_FAT_CHAIN; + modified = true; + } + if (new_clu.flags == ALLOC_FAT_CHAIN) + if (exfat_ent_set(sb, last_clu, new_clu.dir)) + return -EIO; + } + + num_clusters += num_to_be_allocated; + *clu = new_clu.dir; + + if (ei->dir.dir != DIR_DELETED) { + es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, + ES_ALL_ENTRIES, &ep); + if (!es) + return -EIO; + /* get stream entry */ + ep++; + + /* update directory entry */ + if (modified) { + if (ep->dentry.stream.flags != ei->flags) + ep->dentry.stream.flags = ei->flags; + + if (le32_to_cpu(ep->dentry.stream.start_clu) != + ei->start_clu) + ep->dentry.stream.start_clu = + cpu_to_le32(ei->start_clu); + + ep->dentry.stream.valid_size = + cpu_to_le64(i_size_read(inode)); + ep->dentry.stream.size = + ep->dentry.stream.valid_size; + } + + if (exfat_update_dir_chksum_with_entry_set(sb, es, + inode_needs_sync(inode))) + return -EIO; + kfree(es); + + } /* end of if != DIR_DELETED */ + + inode->i_blocks += + num_to_be_allocated << sbi->sect_per_clus_bits; + + /* + * Move *clu pointer along FAT chains (hole care) because the + * caller of this function expect *clu to be the last cluster. + * This only works when num_to_be_allocated >= 2, + * *clu = (the first cluster of the allocated chain) => + * (the last cluster of ...) + */ + if (ei->flags == ALLOC_NO_FAT_CHAIN) { + *clu += num_to_be_allocated - 1; + } else { + while (num_to_be_allocated > 1) { + if (exfat_get_next_cluster(sb, clu)) + return -EIO; + num_to_be_allocated--; + } + } + + } + + /* hint information */ + ei->hint_bmap.off = local_clu_offset; + ei->hint_bmap.clu = *clu; + + return 0; +} + +static int exfat_map_new_buffer(struct exfat_inode_info *ei, + struct buffer_head *bh, loff_t pos) +{ + if (buffer_delay(bh) && pos > ei->i_size_aligned) + return -EIO; + set_buffer_new(bh); + + /* + * Adjust i_size_aligned if i_size_ondisk is bigger than it. + */ + if (ei->i_size_ondisk > ei->i_size_aligned) + ei->i_size_aligned = ei->i_size_ondisk; + return 0; +} + +static int exfat_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; + int err = 0; + unsigned long mapped_blocks = 0; + unsigned int cluster, sec_offset; + sector_t last_block; + sector_t phys = 0; + loff_t pos; + + mutex_lock(&sbi->s_lock); + last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb); + if (iblock >= last_block && !create) + goto done; + + /* Is this block already allocated? */ + err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits, + &cluster, create); + if (err) { + if (err != -ENOSPC) + exfat_fs_error_ratelimit(sb, + "failed to bmap (inode : %p iblock : %llu, err : %d)", + inode, (unsigned long long)iblock, err); + goto unlock_ret; + } + + if (cluster == EXFAT_EOF_CLUSTER) + goto done; + + /* sector offset in cluster */ + sec_offset = iblock & (sbi->sect_per_clus - 1); + + phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset; + mapped_blocks = sbi->sect_per_clus - sec_offset; + max_blocks = min(mapped_blocks, max_blocks); + + /* Treat newly added block / cluster */ + if (iblock < last_block) + create = 0; + + if (create || buffer_delay(bh_result)) { + pos = EXFAT_BLK_TO_B((iblock + 1), sb); + if (ei->i_size_ondisk < pos) + ei->i_size_ondisk = pos; + } + + if (create) { + err = exfat_map_new_buffer(ei, bh_result, pos); + if (err) { + exfat_fs_error(sb, + "requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n", + pos, ei->i_size_aligned); + goto unlock_ret; + } + } + + if (buffer_delay(bh_result)) + clear_buffer_delay(bh_result); + map_bh(bh_result, sb, phys); +done: + bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); +unlock_ret: + mutex_unlock(&sbi->s_lock); + return err; +} + +static int exfat_readpage(struct file *file, struct page *page) +{ + return mpage_readpage(page, exfat_get_block); +} + +static int exfat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned int nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); +} + +static int exfat_writepage(struct page *page, struct writeback_control *wbc) +{ + return block_write_full_page(page, exfat_get_block, wbc); +} + +static int exfat_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + return mpage_writepages(mapping, wbc, exfat_get_block); +} + +static void exfat_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + + if (to > i_size_read(inode)) { + truncate_pagecache(inode, i_size_read(inode)); + exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned); + } +} + +static int exfat_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned int len, unsigned int flags, + struct page **pagep, void **fsdata) +{ + int ret; + + *pagep = NULL; + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + exfat_get_block, + &EXFAT_I(mapping->host)->i_size_ondisk); + + if (ret < 0) + exfat_write_failed(mapping, pos+len); + + return ret; +} + +static int exfat_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned int len, unsigned int copied, + struct page *pagep, void *fsdata) +{ + struct inode *inode = mapping->host; + struct exfat_inode_info *ei = EXFAT_I(inode); + int err; + + err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); + + if (EXFAT_I(inode)->i_size_aligned < i_size_read(inode)) { + exfat_fs_error(inode->i_sb, + "invalid size(size(%llu) > aligned(%llu)\n", + i_size_read(inode), EXFAT_I(inode)->i_size_aligned); + return -EIO; + } + + if (err < len) + exfat_write_failed(mapping, pos+len); + + if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) { + inode->i_mtime = inode->i_ctime = current_time(inode); + ei->attr |= ATTR_ARCHIVE; + mark_inode_dirty(inode); + } + + return err; +} + +static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +{ + struct address_space *mapping = iocb->ki_filp->f_mapping; + struct inode *inode = mapping->host; + loff_t size = iocb->ki_pos + iov_iter_count(iter); + int rw = iov_iter_rw(iter); + ssize_t ret; + + if (rw == WRITE) { + /* + * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), + * so we need to update the ->i_size_aligned to block boundary. + * + * But we must fill the remaining area or hole by nul for + * updating ->i_size_aligned + * + * Return 0, and fallback to normal buffered write. + */ + if (EXFAT_I(inode)->i_size_aligned < size) + return 0; + } + + /* + * Need to use the DIO_LOCKING for avoiding the race + * condition of exfat_get_block() and ->truncate(). + */ + ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); + if (ret < 0 && (rw & WRITE)) + exfat_write_failed(mapping, size); + return ret; +} + +static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block) +{ + sector_t blocknr; + + /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ + down_read(&EXFAT_I(mapping->host)->truncate_lock); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->truncate_lock); + return blocknr; +} + +/* + * exfat_block_truncate_page() zeroes out a mapping from file offset `from' + * up to the end of the block which corresponds to `from'. + * This is required during truncate to physically zeroout the tail end + * of that block so it doesn't yield old data if the file is later grown. + * Also, avoid causing failure from fsx for cases of "data past EOF" + */ +int exfat_block_truncate_page(struct inode *inode, loff_t from) +{ + return block_truncate_page(inode->i_mapping, from, exfat_get_block); +} + +static const struct address_space_operations exfat_aops = { + .readpage = exfat_readpage, + .readpages = exfat_readpages, + .writepage = exfat_writepage, + .writepages = exfat_writepages, + .write_begin = exfat_write_begin, + .write_end = exfat_write_end, + .direct_IO = exfat_direct_IO, + .bmap = exfat_aop_bmap +}; + +static inline unsigned long exfat_hash(loff_t i_pos) +{ + return hash_32(i_pos, EXFAT_HASH_BITS); +} + +void exfat_hash_inode(struct inode *inode, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + + spin_lock(&sbi->inode_hash_lock); + EXFAT_I(inode)->i_pos = i_pos; + hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); + spin_unlock(&sbi->inode_hash_lock); +} + +void exfat_unhash_inode(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + spin_lock(&sbi->inode_hash_lock); + hlist_del_init(&EXFAT_I(inode)->i_hash_fat); + EXFAT_I(inode)->i_pos = 0; + spin_unlock(&sbi->inode_hash_lock); +} + +struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *info; + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + struct inode *inode = NULL; + + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, head, i_hash_fat) { + WARN_ON(info->vfs_inode.i_sb != sb); + + if (i_pos != info->i_pos) + continue; + inode = igrab(&info->vfs_inode); + if (inode) + break; + } + spin_unlock(&sbi->inode_hash_lock); + return inode; +} + +/* doesn't deal with root inode */ +static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + loff_t size = info->size; + + memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain)); + ei->entry = info->entry; + ei->attr = info->attr; + ei->start_clu = info->start_clu; + ei->flags = info->flags; + ei->type = info->type; + + ei->version = 0; + ei->hint_stat.eidx = 0; + ei->hint_stat.clu = info->start_clu; + ei->hint_femp.eidx = EXFAT_HINT_NONE; + ei->rwoffset = 0; + ei->hint_bmap.off = EXFAT_EOF_CLUSTER; + ei->i_pos = 0; + + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + inode_inc_iversion(inode); + inode->i_generation = prandom_u32(); + + if (info->attr & ATTR_SUBDIR) { /* directory */ + inode->i_generation &= ~1; + inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + set_nlink(inode, info->num_subdirs); + } else { /* regular file */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); + inode->i_op = &exfat_file_inode_operations; + inode->i_fop = &exfat_file_operations; + inode->i_mapping->a_ops = &exfat_aops; + inode->i_mapping->nrpages = 0; + } + + i_size_write(inode, size); + + /* ondisk and aligned size should be aligned with block size */ + if (size & (inode->i_sb->s_blocksize - 1)) { + size |= (inode->i_sb->s_blocksize - 1); + size++; + } + + ei->i_size_aligned = size; + ei->i_size_ondisk = size; + + exfat_save_attr(inode, info->attr); + + inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & + ~(sbi->cluster_size - 1)) >> inode->i_blkbits; + inode->i_mtime = info->mtime; + inode->i_ctime = info->mtime; + ei->i_crtime = info->crtime; + inode->i_atime = info->atime; + + exfat_cache_init_inode(inode); + + return 0; +} + +struct inode *exfat_build_inode(struct super_block *sb, + struct exfat_dir_entry *info, loff_t i_pos) +{ + struct inode *inode; + int err; + + inode = exfat_iget(sb, i_pos); + if (inode) + goto out; + inode = new_inode(sb); + if (!inode) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + inode->i_ino = iunique(sb, EXFAT_ROOT_INO); + inode_set_iversion(inode, 1); + err = exfat_fill_inode(inode, info); + if (err) { + iput(inode); + inode = ERR_PTR(err); + goto out; + } + exfat_hash_inode(inode, i_pos); + insert_inode_hash(inode); +out: + return inode; +} + +void exfat_evict_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + + if (!inode->i_nlink) { + i_size_write(inode, 0); + mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + __exfat_truncate(inode, 0); + mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + } + + invalidate_inode_buffers(inode); + clear_inode(inode); + exfat_cache_inval_inode(inode); + exfat_unhash_inode(inode); +} diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c new file mode 100644 index 000000000000..a8681d91f569 --- /dev/null +++ b/fs/exfat/namei.c @@ -0,0 +1,1448 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static inline unsigned long exfat_d_version(struct dentry *dentry) +{ + return (unsigned long) dentry->d_fsdata; +} + +static inline void exfat_d_version_set(struct dentry *dentry, + unsigned long version) +{ + dentry->d_fsdata = (void *) version; +} + +/* + * If new entry was created in the parent, it could create the 8.3 alias (the + * shortname of logname). So, the parent may have the negative-dentry which + * matches the created 8.3 alias. + * + * If it happened, the negative dentry isn't actually negative anymore. So, + * drop it. + */ +static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + int ret; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + /* + * This is not negative dentry. Always valid. + * + * Note, rename() to existing directory entry will have ->d_inode, and + * will use existing name which isn't specified name by user. + * + * We may be able to drop this positive dentry here. But dropping + * positive dentry isn't good idea. So it's unsupported like + * rename("filename", "FILENAME") for now. + */ + if (d_really_is_positive(dentry)) + return 1; + + /* + * Drop the negative dentry, in order to make sure to use the case + * sensitive name which is specified by user if this is for creation. + */ + if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + + spin_lock(&dentry->d_lock); + ret = inode_eq_iversion(d_inode(dentry->d_parent), + exfat_d_version(dentry)); + spin_unlock(&dentry->d_lock); + return ret; +} + +/* returns the length of a struct qstr, ignoring trailing dots */ +static unsigned int exfat_striptail_len(unsigned int len, const char *name) +{ + while (len && name[len - 1] == '.') + len--; + return len; +} + +/* + * Compute the hash for the exfat name corresponding to the dentry. If the name + * is invalid, we leave the hash code unchanged so that the existing dentry can + * be used. The exfat fs routines will return ENOENT or EINVAL as appropriate. + */ +static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) +{ + struct super_block *sb = dentry->d_sb; + struct nls_table *t = EXFAT_SB(sb)->nls_io; + const unsigned char *name = qstr->name; + unsigned int len = exfat_striptail_len(qstr->len, qstr->name); + unsigned long hash = init_name_hash(dentry); + int i, charlen; + wchar_t c; + + for (i = 0; i < len; i += charlen) { + charlen = t->char2uni(&name[i], len - i, &c); + if (charlen < 0) + return charlen; + hash = partial_name_hash(exfat_toupper(sb, c), hash); + } + + qstr->hash = end_name_hash(hash); + return 0; +} + +static int exfat_d_cmp(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) +{ + struct super_block *sb = dentry->d_sb; + struct nls_table *t = EXFAT_SB(sb)->nls_io; + unsigned int alen = exfat_striptail_len(name->len, name->name); + unsigned int blen = exfat_striptail_len(len, str); + wchar_t c1, c2; + int charlen, i; + + if (alen != blen) + return 1; + + for (i = 0; i < len; i += charlen) { + charlen = t->char2uni(&name->name[i], alen - i, &c1); + if (charlen < 0) + return 1; + if (charlen != t->char2uni(&str[i], blen - i, &c2)) + return 1; + + if (exfat_toupper(sb, c1) != exfat_toupper(sb, c2)) + return 1; + } + + return 0; +} + +const struct dentry_operations exfat_dentry_ops = { + .d_revalidate = exfat_d_revalidate, + .d_hash = exfat_d_hash, + .d_compare = exfat_d_cmp, +}; + +static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) +{ + struct super_block *sb = dentry->d_sb; + const unsigned char *name = qstr->name; + unsigned int len = exfat_striptail_len(qstr->len, qstr->name); + unsigned long hash = init_name_hash(dentry); + int i, charlen; + unicode_t u; + + for (i = 0; i < len; i += charlen) { + charlen = utf8_to_utf32(&name[i], len - i, &u); + if (charlen < 0) + return charlen; + + /* + * Convert to UTF-16: code points above U+FFFF are encoded as + * surrogate pairs. + * exfat_toupper() works only for code points up to the U+FFFF. + */ + if (u > 0xFFFF) { + hash = partial_name_hash(exfat_high_surrogate(u), hash); + hash = partial_name_hash(exfat_low_surrogate(u), hash); + } else { + hash = partial_name_hash(exfat_toupper(sb, u), hash); + } + } + + qstr->hash = end_name_hash(hash); + return 0; +} + +static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) +{ + struct super_block *sb = dentry->d_sb; + unsigned int alen = exfat_striptail_len(name->len, name->name); + unsigned int blen = exfat_striptail_len(len, str); + unicode_t u_a, u_b; + int charlen, i; + + if (alen != blen) + return 1; + + for (i = 0; i < alen; i += charlen) { + charlen = utf8_to_utf32(&name->name[i], alen - i, &u_a); + if (charlen < 0) + return 1; + if (charlen != utf8_to_utf32(&str[i], blen - i, &u_b)) + return 1; + + if (u_a <= 0xFFFF && u_b <= 0xFFFF) { + if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b)) + return 1; + } else if (u_a > 0xFFFF && u_b > 0xFFFF) { + if (exfat_low_surrogate(u_a) != + exfat_low_surrogate(u_b) || + exfat_high_surrogate(u_a) != + exfat_high_surrogate(u_b)) + return 1; + } else { + return 1; + } + } + + return 0; +} + +const struct dentry_operations exfat_utf8_dentry_ops = { + .d_revalidate = exfat_d_revalidate, + .d_hash = exfat_utf8_d_hash, + .d_compare = exfat_utf8_d_cmp, +}; + +/* used only in search empty_slot() */ +#define CNT_UNUSED_NOHIT (-1) +#define CNT_UNUSED_HIT (-2) +/* search EMPTY CONTINUOUS "num_entries" entries */ +static int exfat_search_empty_slot(struct super_block *sb, + struct exfat_hint_femp *hint_femp, struct exfat_chain *p_dir, + int num_entries) +{ + int i, dentry, num_empty = 0; + int dentries_per_clu; + unsigned int type; + struct exfat_chain clu; + struct exfat_dentry *ep; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + dentries_per_clu = sbi->dentries_per_clu; + + if (hint_femp->eidx != EXFAT_HINT_NONE) { + dentry = hint_femp->eidx; + if (num_entries <= hint_femp->count) { + hint_femp->eidx = EXFAT_HINT_NONE; + return dentry; + } + + exfat_chain_dup(&clu, &hint_femp->cur); + } else { + exfat_chain_dup(&clu, p_dir); + dentry = 0; + } + + while (clu.dir != EXFAT_EOF_CLUSTER) { + i = dentry & (dentries_per_clu - 1); + + for (; i < dentries_per_clu; i++, dentry++) { + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + type = exfat_get_entry_type(ep); + brelse(bh); + + if (type == TYPE_UNUSED || type == TYPE_DELETED) { + num_empty++; + if (hint_femp->eidx == EXFAT_HINT_NONE) { + hint_femp->eidx = dentry; + hint_femp->count = CNT_UNUSED_NOHIT; + exfat_chain_set(&hint_femp->cur, + clu.dir, clu.size, clu.flags); + } + + if (type == TYPE_UNUSED && + hint_femp->count != CNT_UNUSED_HIT) + hint_femp->count = CNT_UNUSED_HIT; + } else { + if (hint_femp->eidx != EXFAT_HINT_NONE && + hint_femp->count == CNT_UNUSED_HIT) { + /* unused empty group means + * an empty group which includes + * unused dentry + */ + exfat_fs_error(sb, + "found bogus dentry(%d) beyond unused empty group(%d) (start_clu : %u, cur_clu : %u)", + dentry, hint_femp->eidx, + p_dir->dir, clu.dir); + return -EIO; + } + + num_empty = 0; + hint_femp->eidx = EXFAT_HINT_NONE; + } + + if (num_empty >= num_entries) { + /* found and invalidate hint_femp */ + hint_femp->eidx = EXFAT_HINT_NONE; + return (dentry - (num_entries - 1)); + } + } + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + if (exfat_get_next_cluster(sb, &clu.dir)) + return -EIO; + } + } + + return -ENOSPC; +} + +static int exfat_check_max_dentries(struct inode *inode) +{ + if (EXFAT_B_TO_DEN(i_size_read(inode)) >= MAX_EXFAT_DENTRIES) { + /* + * exFAT spec allows a dir to grow upto 8388608(256MB) + * dentries + */ + return -ENOSPC; + } + return 0; +} + +/* find empty directory entry. + * if there isn't any empty slot, expand cluster chain. + */ +static int exfat_find_empty_entry(struct inode *inode, + struct exfat_chain *p_dir, int num_entries) +{ + int dentry; + unsigned int ret, last_clu; + sector_t sector; + loff_t size = 0; + struct exfat_chain clu; + struct exfat_dentry *ep = NULL; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_hint_femp hint_femp; + + hint_femp.eidx = EXFAT_HINT_NONE; + + if (ei->hint_femp.eidx != EXFAT_HINT_NONE) { + memcpy(&hint_femp, &ei->hint_femp, + sizeof(struct exfat_hint_femp)); + ei->hint_femp.eidx = EXFAT_HINT_NONE; + } + + while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir, + num_entries)) < 0) { + if (dentry == -EIO) + break; + + if (exfat_check_max_dentries(inode)) + return -ENOSPC; + + /* we trust p_dir->size regardless of FAT type */ + if (exfat_find_last_cluster(sb, p_dir, &last_clu)) + return -EIO; + + /* + * Allocate new cluster to this directory + */ + exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags); + + /* allocate a cluster */ + ret = exfat_alloc_cluster(inode, 1, &clu); + if (ret) + return ret; + + if (exfat_zeroed_cluster(inode, clu.dir)) + return -EIO; + + /* append to the FAT chain */ + if (clu.flags != p_dir->flags) { + /* no-fat-chain bit is disabled, + * so fat-chain should be synced with alloc-bitmap + */ + exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); + p_dir->flags = ALLOC_FAT_CHAIN; + hint_femp.cur.flags = ALLOC_FAT_CHAIN; + } + + if (clu.flags == ALLOC_FAT_CHAIN) + if (exfat_ent_set(sb, last_clu, clu.dir)) + return -EIO; + + if (hint_femp.eidx == EXFAT_HINT_NONE) { + /* the special case that new dentry + * should be allocated from the start of new cluster + */ + hint_femp.eidx = EXFAT_B_TO_DEN_IDX(p_dir->size, sbi); + hint_femp.count = sbi->dentries_per_clu; + + exfat_chain_set(&hint_femp.cur, clu.dir, 0, clu.flags); + } + hint_femp.cur.size++; + p_dir->size++; + size = EXFAT_CLU_TO_B(p_dir->size, sbi); + + /* update the directory entry */ + if (p_dir->dir != sbi->root_dir) { + struct buffer_head *bh; + + ep = exfat_get_dentry(sb, + &(ei->dir), ei->entry + 1, &bh, §or); + if (!ep) + return -EIO; + + ep->dentry.stream.valid_size = cpu_to_le64(size); + ep->dentry.stream.size = ep->dentry.stream.valid_size; + ep->dentry.stream.flags = p_dir->flags; + exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); + brelse(bh); + if (exfat_update_dir_chksum(inode, &(ei->dir), + ei->entry)) + return -EIO; + } + + /* directory inode should be updated in here */ + i_size_write(inode, size); + EXFAT_I(inode)->i_size_ondisk += sbi->cluster_size; + EXFAT_I(inode)->i_size_aligned += sbi->cluster_size; + EXFAT_I(inode)->flags = p_dir->flags; + inode->i_blocks += 1 << sbi->sect_per_clus_bits; + } + + return dentry; +} + +/* + * Name Resolution Functions : + * Zero if it was successful; otherwise nonzero. + */ +static int __exfat_resolve_path(struct inode *inode, const unsigned char *path, + struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, + int lookup) +{ + int namelen; + int lossy = NLS_NAME_NO_LOSSY; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + + /* strip all trailing periods */ + namelen = exfat_striptail_len(strlen(path), path); + if (!namelen) + return -ENOENT; + + if (strlen(path) > (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) + return -ENAMETOOLONG; + + /* + * strip all leading spaces : + * "MS windows 7" supports leading spaces. + * So we should skip this preprocessing for compatibility. + */ + + /* file name conversion : + * If lookup case, we allow bad-name for compatibility. + */ + namelen = exfat_nls_to_utf16(sb, path, namelen, p_uniname, + &lossy); + if (namelen < 0) + return namelen; /* return error value */ + + if ((lossy && !lookup) || !namelen) + return -EINVAL; + + exfat_chain_set(p_dir, ei->start_clu, + EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); + + return 0; +} + +static inline int exfat_resolve_path(struct inode *inode, + const unsigned char *path, struct exfat_chain *dir, + struct exfat_uni_name *uni) +{ + return __exfat_resolve_path(inode, path, dir, uni, 0); +} + +static inline int exfat_resolve_path_for_lookup(struct inode *inode, + const unsigned char *path, struct exfat_chain *dir, + struct exfat_uni_name *uni) +{ + return __exfat_resolve_path(inode, path, dir, uni, 1); +} + +static inline loff_t exfat_make_i_pos(struct exfat_dir_entry *info) +{ + return ((loff_t) info->dir.dir << 32) | (info->entry & 0xffffffff); +} + +static int exfat_add_entry(struct inode *inode, const char *path, + struct exfat_chain *p_dir, unsigned int type, + struct exfat_dir_entry *info) +{ + int ret, dentry, num_entries; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_uni_name uniname; + struct exfat_chain clu; + int clu_size = 0; + unsigned int start_clu = EXFAT_FREE_CLUSTER; + + ret = exfat_resolve_path(inode, path, p_dir, &uniname); + if (ret) + goto out; + + num_entries = exfat_calc_num_entries(&uniname); + if (num_entries < 0) { + ret = num_entries; + goto out; + } + + /* exfat_find_empty_entry must be called before alloc_cluster() */ + dentry = exfat_find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) { + ret = dentry; /* -EIO or -ENOSPC */ + goto out; + } + + if (type == TYPE_DIR) { + ret = exfat_alloc_new_dir(inode, &clu); + if (ret) + goto out; + start_clu = clu.dir; + clu_size = sbi->cluster_size; + } + + /* update the directory entry */ + /* fill the dos name directory entry information of the created file. + * the first cluster is not determined yet. (0) + */ + ret = exfat_init_dir_entry(inode, p_dir, dentry, type, + start_clu, clu_size); + if (ret) + goto out; + + ret = exfat_init_ext_entry(inode, p_dir, dentry, num_entries, &uniname); + if (ret) + goto out; + + memcpy(&info->dir, p_dir, sizeof(struct exfat_chain)); + info->entry = dentry; + info->flags = ALLOC_NO_FAT_CHAIN; + info->type = type; + + if (type == TYPE_FILE) { + info->attr = ATTR_ARCHIVE; + info->start_clu = EXFAT_EOF_CLUSTER; + info->size = 0; + info->num_subdirs = 0; + } else { + int count; + struct exfat_chain cdir; + + info->attr = ATTR_SUBDIR; + info->start_clu = start_clu; + info->size = clu_size; + + exfat_chain_set(&cdir, info->start_clu, + EXFAT_B_TO_CLU(info->size, sbi), info->flags); + count = exfat_count_dir_entries(sb, &cdir); + if (count < 0) + return -EIO; + info->num_subdirs = count + EXFAT_MIN_SUBDIR; + } + memset(&info->crtime, 0, sizeof(info->crtime)); + memset(&info->mtime, 0, sizeof(info->mtime)); + memset(&info->atime, 0, sizeof(info->atime)); +out: + return ret; +} + +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct exfat_chain cdir; + struct exfat_dir_entry info; + loff_t i_pos; + int err; + + mutex_lock(&EXFAT_SB(sb)->s_lock); + exfat_set_vol_flags(sb, VOL_DIRTY); + err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE, + &info); + exfat_set_vol_flags(sb, VOL_CLEAN); + if (err) + goto unlock; + + inode_inc_iversion(dir); + dir->i_ctime = dir->i_mtime = current_time(dir); + if (IS_DIRSYNC(dir)) + exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = exfat_make_i_pos(&info); + inode = exfat_build_inode(sb, &info, i_pos); + if (IS_ERR(inode)) + goto unlock; + + inode_inc_iversion(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = + EXFAT_I(inode)->i_crtime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + d_instantiate(dentry, inode); +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return err; +} + +/* lookup a file */ +static int exfat_find(struct inode *dir, struct qstr *qname, + struct exfat_dir_entry *info) +{ + int ret, dentry, num_entries, count; + struct exfat_chain cdir; + struct exfat_uni_name uni_name; + struct exfat_dentry *ep, *ep2; + struct exfat_entry_set_cache *es = NULL; + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(dir); + + if (qname->len == 0) + return -ENOENT; + + /* check the validity of directory name in the given pathname */ + ret = exfat_resolve_path_for_lookup(dir, qname->name, &cdir, &uni_name); + if (ret) + return ret; + + num_entries = exfat_calc_num_entries(&uni_name); + if (num_entries < 0) + return num_entries; + + /* check the validation of hint_stat and initialize it if required */ + if (ei->version != (inode_peek_iversion_raw(dir) & 0xffffffff)) { + ei->hint_stat.clu = cdir.dir; + ei->hint_stat.eidx = 0; + ei->version = (inode_peek_iversion_raw(dir) & 0xffffffff); + ei->hint_femp.eidx = EXFAT_HINT_NONE; + } + + /* search the file name for directories */ + dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name, + num_entries, TYPE_ALL); + + if ((dentry < 0) && (dentry != -EEXIST)) + return dentry; /* -error value */ + + memcpy(&info->dir, &cdir.dir, sizeof(struct exfat_chain)); + info->entry = dentry; + info->num_subdirs = 0; + + /* root directory itself */ + if (unlikely(dentry == -EEXIST)) { + int num_clu = 0; + + info->type = TYPE_DIR; + info->attr = ATTR_SUBDIR; + info->flags = ALLOC_FAT_CHAIN; + info->start_clu = sbi->root_dir; + memset(&info->crtime, 0, sizeof(info->crtime)); + memset(&info->mtime, 0, sizeof(info->mtime)); + memset(&info->atime, 0, sizeof(info->atime)); + + exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + if (exfat_count_num_clusters(sb, &cdir, &num_clu)) + return -EIO; + info->size = num_clu << sbi->cluster_size_bits; + + count = exfat_count_dir_entries(sb, &cdir); + if (count < 0) + return -EIO; + + info->num_subdirs = count; + } else { + es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES, &ep); + if (!es) + return -EIO; + ep2 = ep + 1; + + info->type = exfat_get_entry_type(ep); + info->attr = le16_to_cpu(ep->dentry.file.attr); + info->size = le64_to_cpu(ep2->dentry.stream.valid_size); + if ((info->type == TYPE_FILE) && (info->size == 0)) { + info->flags = ALLOC_NO_FAT_CHAIN; + info->start_clu = EXFAT_EOF_CLUSTER; + } else { + info->flags = ep2->dentry.stream.flags; + info->start_clu = + le32_to_cpu(ep2->dentry.stream.start_clu); + } + + if (ei->start_clu == EXFAT_FREE_CLUSTER) { + exfat_fs_error(sb, + "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", + i_size_read(dir), ei->dir.dir, ei->entry); + return -EIO; + } + + exfat_get_entry_time(sbi, &info->crtime, + ep->dentry.file.create_tz, + ep->dentry.file.create_time, + ep->dentry.file.create_date, + ep->dentry.file.create_time_ms); + exfat_get_entry_time(sbi, &info->mtime, + ep->dentry.file.modify_tz, + ep->dentry.file.modify_time, + ep->dentry.file.modify_date, + ep->dentry.file.modify_time_ms); + exfat_get_entry_time(sbi, &info->atime, + ep->dentry.file.access_tz, + ep->dentry.file.access_time, + ep->dentry.file.access_date, + 0); + kfree(es); + + if (info->type == TYPE_DIR) { + exfat_chain_set(&cdir, info->start_clu, + EXFAT_B_TO_CLU(info->size, sbi), info->flags); + count = exfat_count_dir_entries(sb, &cdir); + if (count < 0) + return -EIO; + + info->num_subdirs = count + EXFAT_MIN_SUBDIR; + } + } + return 0; +} + +static int exfat_d_anon_disconn(struct dentry *dentry) +{ + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); +} + +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct dentry *alias; + struct exfat_dir_entry info; + int err; + loff_t i_pos; + mode_t i_mode; + + mutex_lock(&EXFAT_SB(sb)->s_lock); + err = exfat_find(dir, &dentry->d_name, &info); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto unlock; + } + + i_pos = exfat_make_i_pos(&info); + inode = exfat_build_inode(sb, &info, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto unlock; + } + + i_mode = inode->i_mode; + alias = d_find_alias(inode); + + /* + * Checking "alias->d_parent == dentry->d_parent" to make sure + * FS is not corrupted (especially double linked dir). + */ + if (alias && alias->d_parent == dentry->d_parent && + !exfat_d_anon_disconn(alias)) { + + /* + * Unhashed alias is able to exist because of revalidate() + * called by lookup_fast. You can easily make this status + * by calling create and lookup concurrently + * In such case, we reuse an alias instead of new dentry + */ + if (d_unhashed(alias)) { + WARN_ON(alias->d_name.hash_len != + dentry->d_name.hash_len); + exfat_msg(sb, KERN_INFO, + "rehashed a dentry(%p) in read lookup", alias); + d_drop(dentry); + d_rehash(alias); + } else if (!S_ISDIR(i_mode)) { + /* + * This inode has non anonymous-DCACHE_DISCONNECTED + * dentry. This means, the user did ->lookup() by an + * another name (longname vs 8.3 alias of it) in past. + * + * Switch to new one for reason of locality if possible. + */ + d_move(alias, dentry); + } + iput(inode); + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return alias; + } + dput(alias); +out: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + if (!inode) + exfat_d_version_set(dentry, inode_query_iversion(dir)); + + return d_splice_alias(inode, dentry); +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return ERR_PTR(err); +} + +/* remove an entry, BUT don't truncate */ +static int exfat_unlink(struct inode *dir, struct dentry *dentry) +{ + struct exfat_chain cdir; + struct exfat_dentry *ep; + struct super_block *sb = dir->i_sb; + struct inode *inode = dentry->d_inode; + struct exfat_inode_info *ei = EXFAT_I(inode); + struct buffer_head *bh; + sector_t sector; + int num_entries, entry, err = 0; + + mutex_lock(&EXFAT_SB(sb)->s_lock); + exfat_chain_dup(&cdir, &ei->dir); + entry = ei->entry; + if (ei->dir.dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); + err = -ENOENT; + goto unlock; + } + + ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); + if (!ep) { + err = -EIO; + goto unlock; + } + num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); + if (num_entries < 0) { + err = -EIO; + brelse(bh); + goto unlock; + } + num_entries++; + brelse(bh); + + exfat_set_vol_flags(sb, VOL_DIRTY); + /* update the directory entry */ + if (exfat_remove_entries(dir, &cdir, entry, 0, num_entries)) { + err = -EIO; + goto unlock; + } + + /* This doesn't modify ei */ + ei->dir.dir = DIR_DELETED; + exfat_set_vol_flags(sb, VOL_CLEAN); + + inode_inc_iversion(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_unhash_inode(inode); + exfat_d_version_set(dentry, inode_query_iversion(dir)); +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return err; +} + +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct exfat_dir_entry info; + struct exfat_chain cdir; + loff_t i_pos; + int err; + + mutex_lock(&EXFAT_SB(sb)->s_lock); + exfat_set_vol_flags(sb, VOL_DIRTY); + err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR, + &info); + exfat_set_vol_flags(sb, VOL_CLEAN); + if (err) + goto unlock; + + inode_inc_iversion(dir); + dir->i_ctime = dir->i_mtime = current_time(dir); + if (IS_DIRSYNC(dir)) + exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + inc_nlink(dir); + + i_pos = exfat_make_i_pos(&info); + inode = exfat_build_inode(sb, &info, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto unlock; + } + + inode_inc_iversion(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = + EXFAT_I(inode)->i_crtime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + d_instantiate(dentry, inode); + +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return err; +} + +static int exfat_check_dir_empty(struct super_block *sb, + struct exfat_chain *p_dir) +{ + int i, dentries_per_clu; + unsigned int type; + struct exfat_chain clu; + struct exfat_dentry *ep; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + dentries_per_clu = sbi->dentries_per_clu; + + exfat_chain_dup(&clu, p_dir); + + while (clu.dir != EXFAT_EOF_CLUSTER) { + for (i = 0; i < dentries_per_clu; i++) { + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + type = exfat_get_entry_type(ep); + brelse(bh); + if (type == TYPE_UNUSED) + return 0; + + if (type != TYPE_FILE && type != TYPE_DIR) + continue; + + return -ENOTEMPTY; + } + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + } + } + + return 0; +} + +static int exfat_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct exfat_dentry *ep; + struct exfat_chain cdir, clu_to_free; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + struct buffer_head *bh; + sector_t sector; + int num_entries, entry, err; + + mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + + exfat_chain_dup(&cdir, &ei->dir); + entry = ei->entry; + + if (ei->dir.dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); + err = -ENOENT; + goto unlock; + } + + exfat_set_vol_flags(sb, VOL_DIRTY); + exfat_chain_set(&clu_to_free, ei->start_clu, + EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi), ei->flags); + + err = exfat_check_dir_empty(sb, &clu_to_free); + if (err) { + if (err == -EIO) + exfat_msg(sb, KERN_ERR, + "failed to exfat_check_dir_empty : err(%d)", + err); + goto unlock; + } + + ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); + if (!ep) { + err = -EIO; + goto unlock; + } + + num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); + if (num_entries < 0) { + err = -EIO; + brelse(bh); + goto unlock; + } + num_entries++; + brelse(bh); + + err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries); + if (err) { + exfat_msg(sb, KERN_ERR, + "failed to exfat_remove_entries : err(%d)", + err); + goto unlock; + } + ei->dir.dir = DIR_DELETED; + exfat_set_vol_flags(sb, VOL_CLEAN); + + inode_inc_iversion(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + drop_nlink(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_unhash_inode(inode); + exfat_d_version_set(dentry, inode_query_iversion(dir)); +unlock: + mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + return err; +} + +static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, + int oldentry, struct exfat_uni_name *p_uniname, + struct exfat_inode_info *ei) +{ + int ret, num_old_entries, num_new_entries; + sector_t sector_old, sector_new; + struct exfat_dentry *epold, *epnew; + struct super_block *sb = inode->i_sb; + struct buffer_head *new_bh, *old_bh; + int sync = IS_DIRSYNC(inode); + + epold = exfat_get_dentry(sb, p_dir, oldentry, &old_bh, §or_old); + if (!epold) + return -EIO; + + num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, epold); + if (num_old_entries < 0) + return -EIO; + num_old_entries++; + + num_new_entries = exfat_calc_num_entries(p_uniname); + if (num_new_entries < 0) + return num_new_entries; + + if (num_old_entries < num_new_entries) { + int newentry; + + newentry = + exfat_find_empty_entry(inode, p_dir, num_new_entries); + if (newentry < 0) + return newentry; /* -EIO or -ENOSPC */ + + epnew = exfat_get_dentry(sb, p_dir, newentry, &new_bh, + §or_new); + if (!epnew) + return -EIO; + + memcpy(epnew, epold, DENTRY_SIZE); + if (exfat_get_entry_type(epnew) == TYPE_FILE) { + epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); + ei->attr |= ATTR_ARCHIVE; + } + exfat_update_bh(sb, new_bh, sync); + brelse(old_bh); + brelse(new_bh); + + epold = exfat_get_dentry(sb, p_dir, oldentry + 1, &old_bh, + §or_old); + epnew = exfat_get_dentry(sb, p_dir, newentry + 1, &new_bh, + §or_new); + if (!epold || !epnew) + return -EIO; + + memcpy(epnew, epold, DENTRY_SIZE); + exfat_update_bh(sb, new_bh, sync); + brelse(old_bh); + brelse(new_bh); + + ret = exfat_init_ext_entry(inode, p_dir, newentry, + num_new_entries, p_uniname); + if (ret) + return ret; + + exfat_remove_entries(inode, p_dir, oldentry, 0, + num_old_entries); + ei->entry = newentry; + } else { + if (exfat_get_entry_type(epold) == TYPE_FILE) { + epold->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); + ei->attr |= ATTR_ARCHIVE; + } + exfat_update_bh(sb, old_bh, sync); + brelse(old_bh); + ret = exfat_init_ext_entry(inode, p_dir, oldentry, + num_new_entries, p_uniname); + if (ret) + return ret; + + exfat_remove_entries(inode, p_dir, oldentry, num_new_entries, + num_old_entries); + } + return 0; +} + +static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, + int oldentry, struct exfat_chain *p_newdir, + struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei) +{ + int ret, newentry, num_new_entries, num_old_entries; + sector_t sector_mov, sector_new; + struct exfat_dentry *epmov, *epnew; + struct super_block *sb = inode->i_sb; + struct buffer_head *mov_bh, *new_bh; + + epmov = exfat_get_dentry(sb, p_olddir, oldentry, &mov_bh, §or_mov); + if (!epmov) + return -EIO; + + /* check if the source and target directory is the same */ + if (exfat_get_entry_type(epmov) == TYPE_DIR && + le32_to_cpu(epmov->dentry.stream.start_clu) == p_newdir->dir) + return -EINVAL; + + num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, + epmov); + if (num_old_entries < 0) + return -EIO; + num_old_entries++; + + num_new_entries = exfat_calc_num_entries(p_uniname); + if (num_new_entries < 0) + return num_new_entries; + + newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries); + if (newentry < 0) + return newentry; /* -EIO or -ENOSPC */ + + epnew = exfat_get_dentry(sb, p_newdir, newentry, &new_bh, §or_new); + if (!epnew) + return -EIO; + + memcpy(epnew, epmov, DENTRY_SIZE); + if (exfat_get_entry_type(epnew) == TYPE_FILE) { + epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); + ei->attr |= ATTR_ARCHIVE; + } + exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); + brelse(mov_bh); + brelse(new_bh); + + epmov = exfat_get_dentry(sb, p_olddir, oldentry + 1, &mov_bh, + §or_mov); + epnew = exfat_get_dentry(sb, p_newdir, newentry + 1, &new_bh, + §or_new); + if (!epmov || !epnew) + return -EIO; + + memcpy(epnew, epmov, DENTRY_SIZE); + exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); + brelse(mov_bh); + brelse(new_bh); + + ret = exfat_init_ext_entry(inode, p_newdir, newentry, num_new_entries, + p_uniname); + if (ret) + return ret; + + exfat_remove_entries(inode, p_olddir, oldentry, 0, num_old_entries); + + exfat_chain_set(&ei->dir, p_newdir->dir, p_newdir->size, + p_newdir->flags); + + ei->entry = newentry; + return 0; +} + +static void exfat_update_parent_info(struct exfat_inode_info *ei, + struct inode *parent_inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(parent_inode->i_sb); + struct exfat_inode_info *parent_ei = EXFAT_I(parent_inode); + loff_t parent_isize = i_size_read(parent_inode); + + /* + * the problem that struct exfat_inode_info caches wrong parent info. + * + * because of flag-mismatch of ei->dir, + * there is abnormal traversing cluster chain. + */ + if (unlikely(parent_ei->flags != ei->dir.flags || + parent_isize != EXFAT_CLU_TO_B(ei->dir.size, sbi) || + parent_ei->start_clu != ei->dir.dir)) { + exfat_chain_set(&ei->dir, parent_ei->start_clu, + EXFAT_B_TO_CLU_ROUND_UP(parent_isize, sbi), + parent_ei->flags); + } +} + +/* rename or move a old file into a new file */ +static int __exfat_rename(struct inode *old_parent_inode, + struct exfat_inode_info *ei, struct inode *new_parent_inode, + struct dentry *new_dentry) +{ + int ret; + int dentry; + struct exfat_chain olddir, newdir; + struct exfat_chain *p_dir = NULL; + struct exfat_uni_name uni_name; + struct exfat_dentry *ep; + struct super_block *sb = old_parent_inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + const unsigned char *new_path = new_dentry->d_name.name; + struct inode *new_inode = new_dentry->d_inode; + int num_entries; + struct exfat_inode_info *new_ei = NULL; + unsigned int new_entry_type = TYPE_UNUSED; + int new_entry = 0; + struct buffer_head *old_bh, *new_bh = NULL; + + /* check the validity of pointer parameters */ + if (new_path == NULL || strlen(new_path) == 0) + return -EINVAL; + + if (ei->dir.dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, + "abnormal access to deleted source dentry"); + return -ENOENT; + } + + exfat_update_parent_info(ei, old_parent_inode); + + exfat_chain_dup(&olddir, &ei->dir); + dentry = ei->entry; + + ep = exfat_get_dentry(sb, &olddir, dentry, &old_bh, NULL); + if (!ep) { + ret = -EIO; + goto out; + } + brelse(old_bh); + + /* check whether new dir is existing directory and empty */ + if (new_inode) { + ret = -EIO; + new_ei = EXFAT_I(new_inode); + + if (new_ei->dir.dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, + "abnormal access to deleted target dentry"); + goto out; + } + + exfat_update_parent_info(new_ei, new_parent_inode); + + p_dir = &(new_ei->dir); + new_entry = new_ei->entry; + ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); + if (!ep) + goto out; + + new_entry_type = exfat_get_entry_type(ep); + brelse(new_bh); + + /* if new_inode exists, update ei */ + if (new_entry_type == TYPE_DIR) { + struct exfat_chain new_clu; + + new_clu.dir = new_ei->start_clu; + new_clu.size = + EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), + sbi); + new_clu.flags = new_ei->flags; + + ret = exfat_check_dir_empty(sb, &new_clu); + if (ret) + goto out; + } + } + + /* check the validity of directory name in the given new pathname */ + ret = exfat_resolve_path(new_parent_inode, new_path, &newdir, + &uni_name); + if (ret) + goto out; + + exfat_set_vol_flags(sb, VOL_DIRTY); + + if (olddir.dir == newdir.dir) + ret = exfat_rename_file(new_parent_inode, &olddir, dentry, + &uni_name, ei); + else + ret = exfat_move_file(new_parent_inode, &olddir, dentry, + &newdir, &uni_name, ei); + + if (!ret && new_inode) { + /* delete entries of new_dir */ + ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); + if (!ep) { + ret = -EIO; + goto del_out; + } + + num_entries = exfat_count_ext_entries(sb, p_dir, new_entry, ep); + if (num_entries < 0) { + ret = -EIO; + goto del_out; + } + brelse(new_bh); + + if (exfat_remove_entries(new_inode, p_dir, new_entry, 0, + num_entries + 1)) { + ret = -EIO; + goto del_out; + } + + /* Free the clusters if new_inode is a dir(as if exfat_rmdir) */ + if (new_entry_type == TYPE_DIR) { + /* new_ei, new_clu_to_free */ + struct exfat_chain new_clu_to_free; + + exfat_chain_set(&new_clu_to_free, new_ei->start_clu, + EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), + sbi), new_ei->flags); + + if (exfat_free_cluster(new_inode, &new_clu_to_free)) { + /* just set I/O error only */ + ret = -EIO; + } + + i_size_write(new_inode, 0); + new_ei->start_clu = EXFAT_EOF_CLUSTER; + new_ei->flags = ALLOC_NO_FAT_CHAIN; + } +del_out: + /* Update new_inode ei + * Prevent syncing removed new_inode + * (new_ei is already initialized above code ("if (new_inode)") + */ + new_ei->dir.dir = DIR_DELETED; + } + exfat_set_vol_flags(sb, VOL_CLEAN); +out: + return ret; +} + +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + struct inode *old_inode, *new_inode; + struct super_block *sb = old_dir->i_sb; + loff_t i_pos; + int err; + + /* + * The VFS already checks for existence, so for local filesystems + * the RENAME_NOREPLACE implementation is equivalent to plain rename. + * Don't support any other flags + */ + if (flags & ~RENAME_NOREPLACE) + return -EINVAL; + + mutex_lock(&EXFAT_SB(sb)->s_lock); + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; + + err = __exfat_rename(old_dir, EXFAT_I(old_inode), new_dir, new_dentry); + if (err) + goto unlock; + + inode_inc_iversion(new_dir); + new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = + EXFAT_I(new_dir)->i_crtime = current_time(new_dir); + if (IS_DIRSYNC(new_dir)) + exfat_sync_inode(new_dir); + else + mark_inode_dirty(new_dir); + + i_pos = ((loff_t)EXFAT_I(old_inode)->dir.dir << 32) | + (EXFAT_I(old_inode)->entry & 0xffffffff); + exfat_unhash_inode(old_inode); + exfat_hash_inode(old_inode, i_pos); + if (IS_DIRSYNC(new_dir)) + exfat_sync_inode(old_inode); + else + mark_inode_dirty(old_inode); + + if (S_ISDIR(old_inode->i_mode) && old_dir != new_dir) { + drop_nlink(old_dir); + if (!new_inode) + inc_nlink(new_dir); + } + + inode_inc_iversion(old_dir); + old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); + if (IS_DIRSYNC(old_dir)) + exfat_sync_inode(old_dir); + else + mark_inode_dirty(old_dir); + + if (new_inode) { + exfat_unhash_inode(new_inode); + + /* skip drop_nlink if new_inode already has been dropped */ + if (new_inode->i_nlink) { + drop_nlink(new_inode); + if (S_ISDIR(new_inode->i_mode)) + drop_nlink(new_inode); + } else { + exfat_msg(sb, KERN_WARNING, + "abnormal access to an inode dropped"); + WARN_ON(new_inode->i_nlink == 0); + } + new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime = + current_time(new_inode); + } + +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); + return err; +} + +const struct inode_operations exfat_dir_inode_operations = { + .create = exfat_create, + .lookup = exfat_lookup, + .unlink = exfat_unlink, + .mkdir = exfat_mkdir, + .rmdir = exfat_rmdir, + .rename = exfat_rename, + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; From ca06197382bde0a3bc20215595d1c9ce20c6e341 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:35 +0900 Subject: [PATCH 181/809] exfat: add directory operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of directory operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/dir.c | 1238 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1238 insertions(+) create mode 100644 fs/exfat/dir.c diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c new file mode 100644 index 000000000000..4b91afb0f051 --- /dev/null +++ b/fs/exfat/dir.c @@ -0,0 +1,1238 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static int exfat_extract_uni_name(struct exfat_dentry *ep, + unsigned short *uniname) +{ + int i, len = 0; + + for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { + *uniname = le16_to_cpu(ep->dentry.name.unicode_0_14[i]); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} + +static void exfat_get_uniname_from_ext_entry(struct super_block *sb, + struct exfat_chain *p_dir, int entry, unsigned short *uniname) +{ + int i; + struct exfat_dentry *ep; + struct exfat_entry_set_cache *es; + + es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); + if (!es) + return; + + if (es->num_entries < 3) + goto free_es; + + ep += 2; + + /* + * First entry : file entry + * Second entry : stream-extension entry + * Third entry : first file-name entry + * So, the index of first file-name dentry should start from 2. + */ + for (i = 2; i < es->num_entries; i++, ep++) { + /* end of name entry */ + if (exfat_get_entry_type(ep) != TYPE_EXTEND) + goto free_es; + + exfat_extract_uni_name(ep, uniname); + uniname += EXFAT_FILE_NAME_LEN; + } + +free_es: + kfree(es); +} + +/* read a directory entry from the opened directory */ +static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) +{ + int i, dentries_per_clu, dentries_per_clu_bits = 0; + unsigned int type, clu_offset; + sector_t sector; + struct exfat_chain dir, clu; + struct exfat_uni_name uni_name; + struct exfat_dentry *ep; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; + struct buffer_head *bh; + + /* check if the given file ID is opened */ + if (ei->type != TYPE_DIR) + return -EPERM; + + if (ei->entry == -1) + exfat_chain_set(&dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + else + exfat_chain_set(&dir, ei->start_clu, + EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); + + dentries_per_clu = sbi->dentries_per_clu; + dentries_per_clu_bits = ilog2(dentries_per_clu); + + clu_offset = dentry >> dentries_per_clu_bits; + exfat_chain_dup(&clu, &dir); + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + clu.dir += clu_offset; + clu.size -= clu_offset; + } else { + /* hint_information */ + if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && + ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { + clu_offset -= ei->hint_bmap.off; + clu.dir = ei->hint_bmap.clu; + } + + while (clu_offset > 0) { + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + + clu_offset--; + } + } + + while (clu.dir != EXFAT_EOF_CLUSTER) { + i = dentry & (dentries_per_clu - 1); + + for ( ; i < dentries_per_clu; i++, dentry++) { + ep = exfat_get_dentry(sb, &clu, i, &bh, §or); + if (!ep) + return -EIO; + + type = exfat_get_entry_type(ep); + if (type == TYPE_UNUSED) { + brelse(bh); + break; + } + + if (type != TYPE_FILE && type != TYPE_DIR) { + brelse(bh); + continue; + } + + dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); + exfat_get_entry_time(sbi, &dir_entry->crtime, + ep->dentry.file.create_tz, + ep->dentry.file.create_time, + ep->dentry.file.create_date, + ep->dentry.file.create_time_ms); + exfat_get_entry_time(sbi, &dir_entry->mtime, + ep->dentry.file.modify_tz, + ep->dentry.file.modify_time, + ep->dentry.file.modify_date, + ep->dentry.file.modify_time_ms); + exfat_get_entry_time(sbi, &dir_entry->atime, + ep->dentry.file.access_tz, + ep->dentry.file.access_time, + ep->dentry.file.access_date, + 0); + + *uni_name.name = 0x0; + exfat_get_uniname_from_ext_entry(sb, &dir, dentry, + uni_name.name); + exfat_utf16_to_nls(sb, &uni_name, + dir_entry->namebuf.lfn, + dir_entry->namebuf.lfnbuf_len); + brelse(bh); + + ep = exfat_get_dentry(sb, &clu, i + 1, &bh, NULL); + if (!ep) + return -EIO; + dir_entry->size = + le64_to_cpu(ep->dentry.stream.valid_size); + brelse(bh); + + ei->hint_bmap.off = dentry >> dentries_per_clu_bits; + ei->hint_bmap.clu = clu.dir; + + ei->rwoffset = ++dentry; + return 0; + } + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + } + } + + dir_entry->namebuf.lfn[0] = '\0'; + ei->rwoffset = dentry; + return 0; +} + +static void exfat_init_namebuf(struct exfat_dentry_namebuf *nb) +{ + nb->lfn = NULL; + nb->lfnbuf_len = 0; +} + +static int exfat_alloc_namebuf(struct exfat_dentry_namebuf *nb) +{ + nb->lfn = __getname(); + if (!nb->lfn) + return -ENOMEM; + nb->lfnbuf_len = MAX_VFSNAME_BUF_SIZE; + return 0; +} + +static void exfat_free_namebuf(struct exfat_dentry_namebuf *nb) +{ + if (!nb->lfn) + return; + + __putname(nb->lfn); + exfat_init_namebuf(nb); +} + +/* skip iterating emit_dots when dir is empty */ +#define ITER_POS_FILLED_DOTS (2) +static int exfat_iterate(struct file *filp, struct dir_context *ctx) +{ + struct inode *inode = filp->f_path.dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct inode *tmp; + struct exfat_dir_entry de; + struct exfat_dentry_namebuf *nb = &(de.namebuf); + struct exfat_inode_info *ei = EXFAT_I(inode); + unsigned long inum; + loff_t cpos, i_pos; + int err = 0, fake_offset = 0; + + exfat_init_namebuf(nb); + mutex_lock(&EXFAT_SB(sb)->s_lock); + + cpos = ctx->pos; + if (!dir_emit_dots(filp, ctx)) + goto unlock; + + if (ctx->pos == ITER_POS_FILLED_DOTS) { + cpos = 0; + fake_offset = 1; + } + + if (cpos & (DENTRY_SIZE - 1)) { + err = -ENOENT; + goto unlock; + } + + /* name buffer should be allocated before use */ + err = exfat_alloc_namebuf(nb); + if (err) + goto unlock; +get_new: + ei->rwoffset = EXFAT_B_TO_DEN(cpos); + + if (cpos >= i_size_read(inode)) + goto end_of_dir; + + err = exfat_readdir(inode, &de); + if (err) { + /* + * At least we tried to read a sector. Move cpos to next sector + * position (should be aligned). + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); + cpos &= ~(sb->s_blocksize - 1); + } + + err = -EIO; + goto end_of_dir; + } + + cpos = EXFAT_DEN_TO_B(ei->rwoffset); + + if (!nb->lfn[0]) + goto end_of_dir; + + i_pos = ((loff_t)ei->start_clu << 32) | + ((ei->rwoffset - 1) & 0xffffffff); + tmp = exfat_iget(sb, i_pos); + if (tmp) { + inum = tmp->i_ino; + iput(tmp); + } else { + inum = iunique(sb, EXFAT_ROOT_INO); + } + + /* + * Before calling dir_emit(), sb_lock should be released. + * Because page fault can occur in dir_emit() when the size + * of buffer given from user is larger than one page size. + */ + mutex_unlock(&EXFAT_SB(sb)->s_lock); + if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum, + (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) + goto out_unlocked; + mutex_lock(&EXFAT_SB(sb)->s_lock); + ctx->pos = cpos; + goto get_new; + +end_of_dir: + if (!cpos && fake_offset) + cpos = ITER_POS_FILLED_DOTS; + ctx->pos = cpos; +unlock: + mutex_unlock(&EXFAT_SB(sb)->s_lock); +out_unlocked: + /* + * To improve performance, free namebuf after unlock sb_lock. + * If namebuf is not allocated, this function do nothing + */ + exfat_free_namebuf(nb); + return err; +} + +const struct file_operations exfat_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate = exfat_iterate, + .fsync = generic_file_fsync, +}; + +int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) +{ + int ret; + + exfat_chain_set(clu, EXFAT_EOF_CLUSTER, 0, ALLOC_NO_FAT_CHAIN); + + ret = exfat_alloc_cluster(inode, 1, clu); + if (ret) + return ret; + + return exfat_zeroed_cluster(inode, clu->dir); +} + +int exfat_calc_num_entries(struct exfat_uni_name *p_uniname) +{ + int len; + + len = p_uniname->name_len; + if (len == 0) + return -EINVAL; + + /* 1 file entry + 1 stream entry + name entries */ + return ((len - 1) / EXFAT_FILE_NAME_LEN + 3); +} + +unsigned int exfat_get_entry_type(struct exfat_dentry *ep) +{ + if (ep->type == EXFAT_UNUSED) + return TYPE_UNUSED; + if (IS_EXFAT_DELETED(ep->type)) + return TYPE_DELETED; + if (ep->type == EXFAT_INVAL) + return TYPE_INVALID; + if (IS_EXFAT_CRITICAL_PRI(ep->type)) { + if (ep->type == EXFAT_BITMAP) + return TYPE_BITMAP; + if (ep->type == EXFAT_UPCASE) + return TYPE_UPCASE; + if (ep->type == EXFAT_VOLUME) + return TYPE_VOLUME; + if (ep->type == EXFAT_FILE) { + if (le16_to_cpu(ep->dentry.file.attr) & ATTR_SUBDIR) + return TYPE_DIR; + return TYPE_FILE; + } + return TYPE_CRITICAL_PRI; + } + if (IS_EXFAT_BENIGN_PRI(ep->type)) { + if (ep->type == EXFAT_GUID) + return TYPE_GUID; + if (ep->type == EXFAT_PADDING) + return TYPE_PADDING; + if (ep->type == EXFAT_ACLTAB) + return TYPE_ACLTAB; + return TYPE_BENIGN_PRI; + } + if (IS_EXFAT_CRITICAL_SEC(ep->type)) { + if (ep->type == EXFAT_STREAM) + return TYPE_STREAM; + if (ep->type == EXFAT_NAME) + return TYPE_EXTEND; + if (ep->type == EXFAT_ACL) + return TYPE_ACL; + return TYPE_CRITICAL_SEC; + } + return TYPE_BENIGN_SEC; +} + +static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type) +{ + if (type == TYPE_UNUSED) { + ep->type = EXFAT_UNUSED; + } else if (type == TYPE_DELETED) { + ep->type &= EXFAT_DELETE; + } else if (type == TYPE_STREAM) { + ep->type = EXFAT_STREAM; + } else if (type == TYPE_EXTEND) { + ep->type = EXFAT_NAME; + } else if (type == TYPE_BITMAP) { + ep->type = EXFAT_BITMAP; + } else if (type == TYPE_UPCASE) { + ep->type = EXFAT_UPCASE; + } else if (type == TYPE_VOLUME) { + ep->type = EXFAT_VOLUME; + } else if (type == TYPE_DIR) { + ep->type = EXFAT_FILE; + ep->dentry.file.attr = cpu_to_le16(ATTR_SUBDIR); + } else if (type == TYPE_FILE) { + ep->type = EXFAT_FILE; + ep->dentry.file.attr = cpu_to_le16(ATTR_ARCHIVE); + } +} + +static void exfat_init_stream_entry(struct exfat_dentry *ep, + unsigned char flags, unsigned int start_clu, + unsigned long long size) +{ + exfat_set_entry_type(ep, TYPE_STREAM); + ep->dentry.stream.flags = flags; + ep->dentry.stream.start_clu = cpu_to_le32(start_clu); + ep->dentry.stream.valid_size = cpu_to_le64(size); + ep->dentry.stream.size = cpu_to_le64(size); +} + +static void exfat_init_name_entry(struct exfat_dentry *ep, + unsigned short *uniname) +{ + int i; + + exfat_set_entry_type(ep, TYPE_EXTEND); + ep->dentry.name.flags = 0x0; + + for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { + ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); + if (*uniname == 0x0) + break; + uniname++; + } +} + +int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, + int entry, unsigned int type, unsigned int start_clu, + unsigned long long size) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct timespec64 ts = current_time(inode); + sector_t sector; + struct exfat_dentry *ep; + struct buffer_head *bh; + + /* + * We cannot use exfat_get_dentry_set here because file ep is not + * initialized yet. + */ + ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); + if (!ep) + return -EIO; + + exfat_set_entry_type(ep, type); + exfat_set_entry_time(sbi, &ts, + &ep->dentry.file.create_tz, + &ep->dentry.file.create_time, + &ep->dentry.file.create_date, + &ep->dentry.file.create_time_ms); + exfat_set_entry_time(sbi, &ts, + &ep->dentry.file.modify_tz, + &ep->dentry.file.modify_time, + &ep->dentry.file.modify_date, + &ep->dentry.file.modify_time_ms); + exfat_set_entry_time(sbi, &ts, + &ep->dentry.file.access_tz, + &ep->dentry.file.access_time, + &ep->dentry.file.access_date, + NULL); + + exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); + brelse(bh); + + ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); + if (!ep) + return -EIO; + + exfat_init_stream_entry(ep, + (type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN, + start_clu, size); + exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); + brelse(bh); + + return 0; +} + +int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, + int entry) +{ + struct super_block *sb = inode->i_sb; + int ret = 0; + int i, num_entries; + sector_t sector; + unsigned short chksum; + struct exfat_dentry *ep, *fep; + struct buffer_head *fbh, *bh; + + fep = exfat_get_dentry(sb, p_dir, entry, &fbh, §or); + if (!fep) + return -EIO; + + num_entries = fep->dentry.file.num_ext + 1; + chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); + + for (i = 1; i < num_entries; i++) { + ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL); + if (!ep) { + ret = -EIO; + goto release_fbh; + } + chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum, + CS_DEFAULT); + brelse(bh); + } + + fep->dentry.file.checksum = cpu_to_le16(chksum); + exfat_update_bh(sb, fbh, IS_DIRSYNC(inode)); +release_fbh: + brelse(fbh); + return ret; +} + +int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, + int entry, int num_entries, struct exfat_uni_name *p_uniname) +{ + struct super_block *sb = inode->i_sb; + int i; + sector_t sector; + unsigned short *uniname = p_uniname->name; + struct exfat_dentry *ep; + struct buffer_head *bh; + int sync = IS_DIRSYNC(inode); + + ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); + if (!ep) + return -EIO; + + ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); + exfat_update_bh(sb, bh, sync); + brelse(bh); + + ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); + if (!ep) + return -EIO; + + ep->dentry.stream.name_len = p_uniname->name_len; + ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash); + exfat_update_bh(sb, bh, sync); + brelse(bh); + + for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) { + ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); + if (!ep) + return -EIO; + + exfat_init_name_entry(ep, uniname); + exfat_update_bh(sb, bh, sync); + brelse(bh); + uniname += EXFAT_FILE_NAME_LEN; + } + + exfat_update_dir_chksum(inode, p_dir, entry); + return 0; +} + +int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, + int entry, int order, int num_entries) +{ + struct super_block *sb = inode->i_sb; + int i; + sector_t sector; + struct exfat_dentry *ep; + struct buffer_head *bh; + + for (i = order; i < num_entries; i++) { + ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); + if (!ep) + return -EIO; + + exfat_set_entry_type(ep, TYPE_DELETED); + exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); + brelse(bh); + } + + return 0; +} + +int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, + struct exfat_entry_set_cache *es, int sync) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + sector_t sec = es->sector; + unsigned int off = es->offset; + int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries; + unsigned int buf_off = (off - es->offset); + unsigned int remaining_byte_in_sector, copy_entries, clu; + unsigned short chksum = 0; + + for (i = 0; i < num_entries; i++) { + chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE, + chksum, chksum_type); + chksum_type = CS_DEFAULT; + } + + es->entries[0].dentry.file.checksum = cpu_to_le16(chksum); + + while (num_entries) { + /* write per sector base */ + remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off; + copy_entries = min_t(int, + EXFAT_B_TO_DEN(remaining_byte_in_sector), + num_entries); + bh = sb_bread(sb, sec); + if (!bh) + goto err_out; + memcpy(bh->b_data + off, + (unsigned char *)&es->entries[0] + buf_off, + EXFAT_DEN_TO_B(copy_entries)); + exfat_update_bh(sb, bh, sync); + brelse(bh); + num_entries -= copy_entries; + + if (num_entries) { + /* get next sector */ + if (exfat_is_last_sector_in_cluster(sbi, sec)) { + clu = exfat_sector_to_cluster(sbi, sec); + if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) + clu++; + else if (exfat_get_next_cluster(sb, &clu)) + goto err_out; + sec = exfat_cluster_to_sector(sbi, clu); + } else { + sec++; + } + off = 0; + buf_off += EXFAT_DEN_TO_B(copy_entries); + } + } + + return 0; +err_out: + return -EIO; +} + +static int exfat_walk_fat_chain(struct super_block *sb, + struct exfat_chain *p_dir, unsigned int byte_offset, + unsigned int *clu) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned int clu_offset; + unsigned int cur_clu; + + clu_offset = EXFAT_B_TO_CLU(byte_offset, sbi); + cur_clu = p_dir->dir; + + if (p_dir->flags == ALLOC_NO_FAT_CHAIN) { + cur_clu += clu_offset; + } else { + while (clu_offset > 0) { + if (exfat_get_next_cluster(sb, &cur_clu)) + return -EIO; + if (cur_clu == EXFAT_EOF_CLUSTER) { + exfat_fs_error(sb, + "invalid dentry access beyond EOF (clu : %u, eidx : %d)", + p_dir->dir, + EXFAT_B_TO_DEN(byte_offset)); + return -EIO; + } + clu_offset--; + } + } + + *clu = cur_clu; + return 0; +} + +int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, + int entry, sector_t *sector, int *offset) +{ + int ret; + unsigned int off, clu = 0; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + off = EXFAT_DEN_TO_B(entry); + + ret = exfat_walk_fat_chain(sb, p_dir, off, &clu); + if (ret) + return ret; + + /* byte offset in cluster */ + off = EXFAT_CLU_OFFSET(off, sbi); + + /* byte offset in sector */ + *offset = EXFAT_BLK_OFFSET(off, sb); + + /* sector offset in cluster */ + *sector = EXFAT_B_TO_BLK(off, sb); + *sector += exfat_cluster_to_sector(sbi, clu); + return 0; +} + +#define EXFAT_MAX_RA_SIZE (128*1024) +static int exfat_dir_readahead(struct super_block *sb, sector_t sec) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + unsigned int max_ra_count = EXFAT_MAX_RA_SIZE >> sb->s_blocksize_bits; + unsigned int page_ra_count = PAGE_SIZE >> sb->s_blocksize_bits; + unsigned int adj_ra_count = max(sbi->sect_per_clus, page_ra_count); + unsigned int ra_count = min(adj_ra_count, max_ra_count); + + /* Read-ahead is not required */ + if (sbi->sect_per_clus == 1) + return 0; + + if (sec < sbi->data_start_sector) { + exfat_msg(sb, KERN_ERR, + "requested sector is invalid(sect:%llu, root:%llu)", + (unsigned long long)sec, sbi->data_start_sector); + return -EIO; + } + + /* Not sector aligned with ra_count, resize ra_count to page size */ + if ((sec - sbi->data_start_sector) & (ra_count - 1)) + ra_count = page_ra_count; + + bh = sb_find_get_block(sb, sec); + if (!bh || !buffer_uptodate(bh)) { + unsigned int i; + + for (i = 0; i < ra_count; i++) + sb_breadahead(sb, (sector_t)(sec + i)); + } + brelse(bh); + return 0; +} + +struct exfat_dentry *exfat_get_dentry(struct super_block *sb, + struct exfat_chain *p_dir, int entry, struct buffer_head **bh, + sector_t *sector) +{ + unsigned int dentries_per_page = EXFAT_B_TO_DEN(PAGE_SIZE); + int off; + sector_t sec; + + if (p_dir->dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n"); + return NULL; + } + + if (exfat_find_location(sb, p_dir, entry, &sec, &off)) + return NULL; + + if (p_dir->dir != EXFAT_FREE_CLUSTER && + !(entry & (dentries_per_page - 1))) + exfat_dir_readahead(sb, sec); + + *bh = sb_bread(sb, sec); + if (!*bh) + return NULL; + + if (sector) + *sector = sec; + return (struct exfat_dentry *)((*bh)->b_data + off); +} + +enum exfat_validate_dentry_mode { + ES_MODE_STARTED, + ES_MODE_GET_FILE_ENTRY, + ES_MODE_GET_STRM_ENTRY, + ES_MODE_GET_NAME_ENTRY, + ES_MODE_GET_CRITICAL_SEC_ENTRY, +}; + +static bool exfat_validate_entry(unsigned int type, + enum exfat_validate_dentry_mode *mode) +{ + if (type == TYPE_UNUSED || type == TYPE_DELETED) + return false; + + switch (*mode) { + case ES_MODE_STARTED: + if (type != TYPE_FILE && type != TYPE_DIR) + return false; + *mode = ES_MODE_GET_FILE_ENTRY; + return true; + case ES_MODE_GET_FILE_ENTRY: + if (type != TYPE_STREAM) + return false; + *mode = ES_MODE_GET_STRM_ENTRY; + return true; + case ES_MODE_GET_STRM_ENTRY: + if (type != TYPE_EXTEND) + return false; + *mode = ES_MODE_GET_NAME_ENTRY; + return true; + case ES_MODE_GET_NAME_ENTRY: + if (type == TYPE_STREAM) + return false; + if (type != TYPE_EXTEND) { + if (!(type & TYPE_CRITICAL_SEC)) + return false; + *mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; + } + return true; + case ES_MODE_GET_CRITICAL_SEC_ENTRY: + if (type == TYPE_EXTEND || type == TYPE_STREAM) + return false; + if ((type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) + return false; + return true; + default: + WARN_ON_ONCE(1); + return false; + } +} + +/* + * Returns a set of dentries for a file or dir. + * + * Note that this is a copy (dump) of dentries so that user should + * call write_entry_set() to apply changes made in this entry set + * to the real device. + * + * in: + * sb+p_dir+entry: indicates a file/dir + * type: specifies how many dentries should be included. + * out: + * file_ep: will point the first dentry(= file dentry) on success + * return: + * pointer of entry set on success, + * NULL on failure. + */ +struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, + struct exfat_chain *p_dir, int entry, unsigned int type, + struct exfat_dentry **file_ep) +{ + int ret; + unsigned int off, byte_offset, clu = 0; + unsigned int entry_type; + sector_t sec; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_entry_set_cache *es; + struct exfat_dentry *ep, *pos; + unsigned char num_entries; + enum exfat_validate_dentry_mode mode = ES_MODE_STARTED; + struct buffer_head *bh; + + if (p_dir->dir == DIR_DELETED) { + exfat_msg(sb, KERN_ERR, "access to deleted dentry\n"); + return NULL; + } + + byte_offset = EXFAT_DEN_TO_B(entry); + ret = exfat_walk_fat_chain(sb, p_dir, byte_offset, &clu); + if (ret) + return NULL; + + /* byte offset in cluster */ + byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi); + + /* byte offset in sector */ + off = EXFAT_BLK_OFFSET(byte_offset, sb); + + /* sector offset in cluster */ + sec = EXFAT_B_TO_BLK(byte_offset, sb); + sec += exfat_cluster_to_sector(sbi, clu); + + bh = sb_bread(sb, sec); + if (!bh) + return NULL; + + ep = (struct exfat_dentry *)(bh->b_data + off); + entry_type = exfat_get_entry_type(ep); + + if (entry_type != TYPE_FILE && entry_type != TYPE_DIR) + goto release_bh; + + num_entries = type == ES_ALL_ENTRIES ? + ep->dentry.file.num_ext + 1 : type; + es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL); + if (!es) + goto release_bh; + + es->num_entries = num_entries; + es->sector = sec; + es->offset = off; + es->alloc_flag = p_dir->flags; + + pos = &es->entries[0]; + + while (num_entries) { + if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) + goto free_es; + + /* copy dentry */ + memcpy(pos, ep, sizeof(struct exfat_dentry)); + + if (--num_entries == 0) + break; + + if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) < + (off & (sb->s_blocksize - 1))) { + /* get the next sector */ + if (exfat_is_last_sector_in_cluster(sbi, sec)) { + if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) + clu++; + else if (exfat_get_next_cluster(sb, &clu)) + goto free_es; + sec = exfat_cluster_to_sector(sbi, clu); + } else { + sec++; + } + + brelse(bh); + bh = sb_bread(sb, sec); + if (!bh) + goto free_es; + off = 0; + ep = (struct exfat_dentry *)bh->b_data; + } else { + ep++; + off += DENTRY_SIZE; + } + pos++; + } + + if (file_ep) + *file_ep = &es->entries[0]; + brelse(bh); + return es; + +free_es: + kfree(es); +release_bh: + brelse(bh); + return NULL; +} + +enum { + DIRENT_STEP_FILE, + DIRENT_STEP_STRM, + DIRENT_STEP_NAME, + DIRENT_STEP_SECD, +}; + +/* + * return values: + * >= 0 : return dir entiry position with the name in dir + * -EEXIST : (root dir, ".") it is the root dir itself + * -ENOENT : entry with the name does not exist + * -EIO : I/O error + */ +int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, + struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, + int num_entries, unsigned int type) +{ + int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len; + int order, step, name_len = 0; + int dentries_per_clu, num_empty = 0; + unsigned int entry_type; + unsigned short *uniname = NULL; + struct exfat_chain clu; + struct exfat_hint *hint_stat = &ei->hint_stat; + struct exfat_hint_femp candi_empty; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + dentries_per_clu = sbi->dentries_per_clu; + + exfat_chain_dup(&clu, p_dir); + + if (hint_stat->eidx) { + clu.dir = hint_stat->clu; + dentry = hint_stat->eidx; + end_eidx = dentry; + } + + candi_empty.eidx = EXFAT_HINT_NONE; +rewind: + order = 0; + step = DIRENT_STEP_FILE; + while (clu.dir != EXFAT_EOF_CLUSTER) { + i = dentry & (dentries_per_clu - 1); + for (; i < dentries_per_clu; i++, dentry++) { + struct exfat_dentry *ep; + struct buffer_head *bh; + + if (rewind && dentry == end_eidx) + goto not_found; + + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + + entry_type = exfat_get_entry_type(ep); + + if (entry_type == TYPE_UNUSED || + entry_type == TYPE_DELETED) { + step = DIRENT_STEP_FILE; + + num_empty++; + if (candi_empty.eidx == EXFAT_HINT_NONE && + num_empty == 1) { + exfat_chain_set(&candi_empty.cur, + clu.dir, clu.size, clu.flags); + } + + if (candi_empty.eidx == EXFAT_HINT_NONE && + num_empty >= num_entries) { + candi_empty.eidx = + dentry - (num_empty - 1); + WARN_ON(candi_empty.eidx < 0); + candi_empty.count = num_empty; + + if (ei->hint_femp.eidx == + EXFAT_HINT_NONE || + candi_empty.eidx <= + ei->hint_femp.eidx) { + memcpy(&ei->hint_femp, + &candi_empty, + sizeof(candi_empty)); + } + } + + brelse(bh); + if (entry_type == TYPE_UNUSED) + goto not_found; + continue; + } + + num_empty = 0; + candi_empty.eidx = EXFAT_HINT_NONE; + + if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) { + step = DIRENT_STEP_FILE; + if (type == TYPE_ALL || type == entry_type) { + num_ext = ep->dentry.file.num_ext; + step = DIRENT_STEP_STRM; + } + brelse(bh); + continue; + } + + if (entry_type == TYPE_STREAM) { + unsigned short name_hash; + + if (step != DIRENT_STEP_STRM) { + step = DIRENT_STEP_FILE; + brelse(bh); + continue; + } + step = DIRENT_STEP_FILE; + name_hash = le16_to_cpu( + ep->dentry.stream.name_hash); + if (p_uniname->name_hash == name_hash && + p_uniname->name_len == + ep->dentry.stream.name_len) { + step = DIRENT_STEP_NAME; + order = 1; + name_len = 0; + } + brelse(bh); + continue; + } + + brelse(bh); + if (entry_type == TYPE_EXTEND) { + unsigned short entry_uniname[16], unichar; + + if (step != DIRENT_STEP_NAME) { + step = DIRENT_STEP_FILE; + continue; + } + + if (++order == 2) + uniname = p_uniname->name; + else + uniname += EXFAT_FILE_NAME_LEN; + + len = exfat_extract_uni_name(ep, entry_uniname); + name_len += len; + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (exfat_uniname_ncmp(sb, uniname, + entry_uniname, len)) { + step = DIRENT_STEP_FILE; + } else if (p_uniname->name_len == name_len) { + if (order == num_ext) + goto found; + step = DIRENT_STEP_SECD; + } + + *(uniname+len) = unichar; + continue; + } + + if (entry_type & + (TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) { + if (step == DIRENT_STEP_SECD) { + if (++order == num_ext) + goto found; + continue; + } + } + step = DIRENT_STEP_FILE; + } + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + if (exfat_get_next_cluster(sb, &clu.dir)) + return -EIO; + } + } + +not_found: + /* + * We started at not 0 index,so we should try to find target + * from 0 index to the index we started at. + */ + if (!rewind && end_eidx) { + rewind = 1; + dentry = 0; + clu.dir = p_dir->dir; + /* reset empty hint */ + num_empty = 0; + candi_empty.eidx = EXFAT_HINT_NONE; + goto rewind; + } + + /* initialized hint_stat */ + hint_stat->clu = p_dir->dir; + hint_stat->eidx = 0; + return -ENOENT; + +found: + /* next dentry we'll find is out of this cluster */ + if (!((dentry + 1) & (dentries_per_clu - 1))) { + int ret = 0; + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + ret = exfat_get_next_cluster(sb, &clu.dir); + } + + if (ret || clu.dir != EXFAT_EOF_CLUSTER) { + /* just initialized hint_stat */ + hint_stat->clu = p_dir->dir; + hint_stat->eidx = 0; + return (dentry - num_ext); + } + } + + hint_stat->clu = clu.dir; + hint_stat->eidx = dentry + 1; + return dentry - num_ext; +} + +int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, + int entry, struct exfat_dentry *ep) +{ + int i, count = 0; + unsigned int type; + struct exfat_dentry *ext_ep; + struct buffer_head *bh; + + for (i = 0, entry++; i < ep->dentry.file.num_ext; i++, entry++) { + ext_ep = exfat_get_dentry(sb, p_dir, entry, &bh, NULL); + if (!ext_ep) + return -EIO; + + type = exfat_get_entry_type(ext_ep); + brelse(bh); + if (type == TYPE_EXTEND || type == TYPE_STREAM) + count++; + else + break; + } + return count; +} + +int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir) +{ + int i, count = 0; + int dentries_per_clu; + unsigned int entry_type; + struct exfat_chain clu; + struct exfat_dentry *ep; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + dentries_per_clu = sbi->dentries_per_clu; + + exfat_chain_dup(&clu, p_dir); + + while (clu.dir != EXFAT_EOF_CLUSTER) { + for (i = 0; i < dentries_per_clu; i++) { + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + entry_type = exfat_get_entry_type(ep); + brelse(bh); + + if (entry_type == TYPE_UNUSED) + return count; + if (entry_type != TYPE_DIR) + continue; + count++; + } + + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + if (--clu.size > 0) + clu.dir++; + else + clu.dir = EXFAT_EOF_CLUSTER; + } else { + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + } + } + + return count; +} From 98d917047e8b7f4bb2ff61d81b0ccd94a00444f9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:36 +0900 Subject: [PATCH 182/809] exfat: add file operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of file operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Reviewed-by: Arnd Bergmann Signed-off-by: Al Viro --- fs/exfat/file.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 fs/exfat/file.c diff --git a/fs/exfat/file.c b/fs/exfat/file.c new file mode 100644 index 000000000000..483f683757aa --- /dev/null +++ b/fs/exfat/file.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static int exfat_cont_expand(struct inode *inode, loff_t size) +{ + struct address_space *mapping = inode->i_mapping; + loff_t start = i_size_read(inode), count = size - i_size_read(inode); + int err, err2; + + err = generic_cont_expand_simple(inode, size); + if (err) + return err; + + inode->i_ctime = inode->i_mtime = current_time(inode); + mark_inode_dirty(inode); + + if (!IS_SYNC(inode)) + return 0; + + err = filemap_fdatawrite_range(mapping, start, start + count - 1); + err2 = sync_mapping_buffers(mapping); + if (!err) + err = err2; + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + if (err) + return err; + + return filemap_fdatawait_range(mapping, start, start + count - 1); +} + +static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) +{ + mode_t allow_utime = sbi->options.allow_utime; + + if (!uid_eq(current_fsuid(), inode->i_uid)) { + if (in_group_p(inode->i_gid)) + allow_utime >>= 3; + if (allow_utime & MAY_WRITE) + return true; + } + + /* use a default check */ + return false; +} + +static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) +{ + mode_t i_mode, mask, perm; + + i_mode = inode->i_mode; + + mask = (S_ISREG(i_mode) || S_ISLNK(i_mode)) ? + sbi->options.fs_fmask : sbi->options.fs_dmask; + perm = *mode_ptr & ~(S_IFMT | mask); + + /* Of the r and x bits, all (subject to umask) must be present.*/ + if ((perm & 0555) != (i_mode & 0555)) + return -EPERM; + + if (exfat_mode_can_hold_ro(inode)) { + /* + * Of the w bits, either all (subject to umask) or none must + * be present. + */ + if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) + return -EPERM; + } else { + /* + * If exfat_mode_can_hold_ro(inode) is false, can't change + * w bits. + */ + if ((perm & 0222) != (0222 & ~mask)) + return -EPERM; + } + + *mode_ptr &= S_IFMT | perm; + + return 0; +} + +/* resize the file length */ +int __exfat_truncate(struct inode *inode, loff_t new_size) +{ + unsigned int num_clusters_new, num_clusters_phys; + unsigned int last_clu = EXFAT_FREE_CLUSTER; + struct exfat_chain clu; + struct exfat_dentry *ep, *ep2; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_entry_set_cache *es = NULL; + int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0; + + /* check if the given file ID is opened */ + if (ei->type != TYPE_FILE && ei->type != TYPE_DIR) + return -EPERM; + + exfat_set_vol_flags(sb, VOL_DIRTY); + + num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi); + num_clusters_phys = + EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, sbi); + + exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags); + + if (new_size > 0) { + /* + * Truncate FAT chain num_clusters after the first cluster + * num_clusters = min(new, phys); + */ + unsigned int num_clusters = + min(num_clusters_new, num_clusters_phys); + + /* + * Follow FAT chain + * (defensive coding - works fine even with corrupted FAT table + */ + if (clu.flags == ALLOC_NO_FAT_CHAIN) { + clu.dir += num_clusters; + clu.size -= num_clusters; + } else { + while (num_clusters > 0) { + last_clu = clu.dir; + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + + num_clusters--; + clu.size--; + } + } + } else { + ei->flags = ALLOC_NO_FAT_CHAIN; + ei->start_clu = EXFAT_EOF_CLUSTER; + } + + i_size_write(inode, new_size); + + if (ei->type == TYPE_FILE) + ei->attr |= ATTR_ARCHIVE; + + /* update the directory entry */ + if (!evict) { + struct timespec64 ts; + + es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, + ES_ALL_ENTRIES, &ep); + if (!es) + return -EIO; + ep2 = ep + 1; + + ts = current_time(inode); + exfat_set_entry_time(sbi, &ts, + &ep->dentry.file.modify_tz, + &ep->dentry.file.modify_time, + &ep->dentry.file.modify_date, + &ep->dentry.file.modify_time_ms); + ep->dentry.file.attr = cpu_to_le16(ei->attr); + + /* File size should be zero if there is no cluster allocated */ + if (ei->start_clu == EXFAT_EOF_CLUSTER) { + ep->dentry.stream.valid_size = 0; + ep->dentry.stream.size = 0; + } else { + ep->dentry.stream.valid_size = cpu_to_le64(new_size); + ep->dentry.stream.size = ep->dentry.stream.valid_size; + } + + if (new_size == 0) { + /* Any directory can not be truncated to zero */ + WARN_ON(ei->type != TYPE_FILE); + + ep2->dentry.stream.flags = ALLOC_FAT_CHAIN; + ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER; + } + + if (exfat_update_dir_chksum_with_entry_set(sb, es, + inode_needs_sync(inode))) + return -EIO; + kfree(es); + } + + /* cut off from the FAT chain */ + if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER && + last_clu != EXFAT_EOF_CLUSTER) { + if (exfat_ent_set(sb, last_clu, EXFAT_EOF_CLUSTER)) + return -EIO; + } + + /* invalidate cache and free the clusters */ + /* clear exfat cache */ + exfat_cache_inval_inode(inode); + + /* hint information */ + ei->hint_bmap.off = EXFAT_EOF_CLUSTER; + ei->hint_bmap.clu = EXFAT_EOF_CLUSTER; + if (ei->rwoffset > new_size) + ei->rwoffset = new_size; + + /* hint_stat will be used if this is directory. */ + ei->hint_stat.eidx = 0; + ei->hint_stat.clu = ei->start_clu; + ei->hint_femp.eidx = EXFAT_HINT_NONE; + + /* free the clusters */ + if (exfat_free_cluster(inode, &clu)) + return -EIO; + + exfat_set_vol_flags(sb, VOL_CLEAN); + + return 0; +} + +void exfat_truncate(struct inode *inode, loff_t size) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned int blocksize = 1 << inode->i_blkbits; + loff_t aligned_size; + int err; + + mutex_lock(&sbi->s_lock); + if (EXFAT_I(inode)->start_clu == 0) { + /* + * Empty start_clu != ~0 (not allocated) + */ + exfat_fs_error(sb, "tried to truncate zeroed cluster."); + goto write_size; + } + + err = __exfat_truncate(inode, i_size_read(inode)); + if (err) + goto write_size; + + inode->i_ctime = inode->i_mtime = current_time(inode); + if (IS_DIRSYNC(inode)) + exfat_sync_inode(inode); + else + mark_inode_dirty(inode); + + inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & + ~(sbi->cluster_size - 1)) >> inode->i_blkbits; +write_size: + aligned_size = i_size_read(inode); + if (aligned_size & (blocksize - 1)) { + aligned_size |= (blocksize - 1); + aligned_size++; + } + + if (EXFAT_I(inode)->i_size_ondisk > i_size_read(inode)) + EXFAT_I(inode)->i_size_ondisk = aligned_size; + + if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode)) + EXFAT_I(inode)->i_size_aligned = aligned_size; + mutex_unlock(&sbi->s_lock); +} + +int exfat_getattr(const struct path *path, struct kstat *stat, + unsigned int request_mask, unsigned int query_flags) +{ + struct inode *inode = d_backing_inode(path->dentry); + struct exfat_inode_info *ei = EXFAT_I(inode); + + generic_fillattr(inode, stat); + stat->result_mask |= STATX_BTIME; + stat->btime.tv_sec = ei->i_crtime.tv_sec; + stat->btime.tv_nsec = ei->i_crtime.tv_nsec; + stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size; + return 0; +} + +int exfat_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); + struct inode *inode = dentry->d_inode; + unsigned int ia_valid; + int error; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size > i_size_read(inode)) { + error = exfat_cont_expand(inode, attr->ia_size); + if (error || attr->ia_valid == ATTR_SIZE) + return error; + attr->ia_valid &= ~ATTR_SIZE; + } + + /* Check for setting the inode time. */ + ia_valid = attr->ia_valid; + if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && + exfat_allow_set_time(sbi, inode)) { + attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | + ATTR_TIMES_SET); + } + + error = setattr_prepare(dentry, attr); + attr->ia_valid = ia_valid; + if (error) + goto out; + + if (((attr->ia_valid & ATTR_UID) && + !uid_eq(attr->ia_uid, sbi->options.fs_uid)) || + ((attr->ia_valid & ATTR_GID) && + !gid_eq(attr->ia_gid, sbi->options.fs_gid)) || + ((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { + error = -EPERM; + goto out; + } + + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } + + if (attr->ia_valid & ATTR_SIZE) { + error = exfat_block_truncate_page(inode, attr->ia_size); + if (error) + goto out; + + down_write(&EXFAT_I(inode)->truncate_lock); + truncate_setsize(inode, attr->ia_size); + exfat_truncate(inode, attr->ia_size); + up_write(&EXFAT_I(inode)->truncate_lock); + } + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + +out: + return error; +} + +const struct file_operations exfat_file_operations = { + .llseek = generic_file_llseek, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, + .mmap = generic_file_mmap, + .fsync = generic_file_fsync, + .splice_read = generic_file_splice_read, +}; + +const struct inode_operations exfat_file_inode_operations = { + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; From 31023864e67a5f390cefbe92f72343027dc3aa33 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:37 +0900 Subject: [PATCH 183/809] exfat: add fat entry operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of fat entry operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/fatent.c | 463 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100644 fs/exfat/fatent.c diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c new file mode 100644 index 000000000000..a855b1769a96 --- /dev/null +++ b/fs/exfat/fatent.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static int exfat_mirror_bh(struct super_block *sb, sector_t sec, + struct buffer_head *bh) +{ + struct buffer_head *c_bh; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sector_t sec2; + int err = 0; + + if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { + sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; + c_bh = sb_getblk(sb, sec2); + if (!c_bh) + return -ENOMEM; + memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); + set_buffer_uptodate(c_bh); + mark_buffer_dirty(c_bh); + if (sb->s_flags & SB_SYNCHRONOUS) + err = sync_dirty_buffer(c_bh); + brelse(c_bh); + } + + return err; +} + +static int __exfat_ent_get(struct super_block *sb, unsigned int loc, + unsigned int *content) +{ + unsigned int off; + sector_t sec; + struct buffer_head *bh; + + sec = FAT_ENT_OFFSET_SECTOR(sb, loc); + off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); + + bh = sb_bread(sb, sec); + if (!bh) + return -EIO; + + *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); + + /* remap reserved clusters to simplify code */ + if (*content > EXFAT_BAD_CLUSTER) + *content = EXFAT_EOF_CLUSTER; + + brelse(bh); + return 0; +} + +int exfat_ent_set(struct super_block *sb, unsigned int loc, + unsigned int content) +{ + unsigned int off; + sector_t sec; + __le32 *fat_entry; + struct buffer_head *bh; + + sec = FAT_ENT_OFFSET_SECTOR(sb, loc); + off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); + + bh = sb_bread(sb, sec); + if (!bh) + return -EIO; + + fat_entry = (__le32 *)&(bh->b_data[off]); + *fat_entry = cpu_to_le32(content); + exfat_update_bh(sb, bh, sb->s_flags & SB_SYNCHRONOUS); + exfat_mirror_bh(sb, sec, bh); + brelse(bh); + return 0; +} + +static inline bool is_valid_cluster(struct exfat_sb_info *sbi, + unsigned int clus) +{ + if (clus < EXFAT_FIRST_CLUSTER || sbi->num_clusters <= clus) + return false; + return true; +} + +int exfat_ent_get(struct super_block *sb, unsigned int loc, + unsigned int *content) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int err; + + if (!is_valid_cluster(sbi, loc)) { + exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", + loc); + return -EIO; + } + + err = __exfat_ent_get(sb, loc, content); + if (err) { + exfat_fs_error(sb, + "failed to access to FAT (entry 0x%08x, err:%d)", + loc, err); + return err; + } + + if (*content == EXFAT_FREE_CLUSTER) { + exfat_fs_error(sb, + "invalid access to FAT free cluster (entry 0x%08x)", + loc); + return -EIO; + } + + if (*content == EXFAT_BAD_CLUSTER) { + exfat_fs_error(sb, + "invalid access to FAT bad cluster (entry 0x%08x)", + loc); + return -EIO; + } + + if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { + exfat_fs_error(sb, + "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", + loc, *content); + return -EIO; + } + + return 0; +} + +int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, + unsigned int len) +{ + if (!len) + return 0; + + while (len > 1) { + if (exfat_ent_set(sb, chain, chain + 1)) + return -EIO; + chain++; + len--; + } + + if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) + return -EIO; + return 0; +} + +int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) +{ + unsigned int num_clusters = 0; + unsigned int clu; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + /* invalid cluster number */ + if (p_chain->dir == EXFAT_FREE_CLUSTER || + p_chain->dir == EXFAT_EOF_CLUSTER || + p_chain->dir < EXFAT_FIRST_CLUSTER) + return 0; + + /* no cluster to truncate */ + if (p_chain->size == 0) + return 0; + + /* check cluster validation */ + if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) { + exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)", + p_chain->dir); + return -EIO; + } + + set_bit(EXFAT_SB_DIRTY, &sbi->s_state); + clu = p_chain->dir; + + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + do { + exfat_clear_bitmap(inode, clu); + clu++; + + num_clusters++; + } while (num_clusters < p_chain->size); + } else { + do { + exfat_clear_bitmap(inode, clu); + + if (exfat_get_next_cluster(sb, &clu)) + goto dec_used_clus; + + num_clusters++; + } while (clu != EXFAT_EOF_CLUSTER); + } + +dec_used_clus: + sbi->used_clusters -= num_clusters; + return 0; +} + +int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, + unsigned int *ret_clu) +{ + unsigned int clu, next; + unsigned int count = 0; + + next = p_chain->dir; + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + *ret_clu = next + p_chain->size - 1; + return 0; + } + + do { + count++; + clu = next; + if (exfat_ent_get(sb, clu, &next)) + return -EIO; + } while (next != EXFAT_EOF_CLUSTER); + + if (p_chain->size != count) { + exfat_fs_error(sb, + "bogus directory size (clus : ondisk(%d) != counted(%d))", + p_chain->size, count); + return -EIO; + } + + *ret_clu = clu; + return 0; +} + +static inline int exfat_sync_bhs(struct buffer_head **bhs, int nr_bhs) +{ + int i, err = 0; + + for (i = 0; i < nr_bhs; i++) + write_dirty_buffer(bhs[i], 0); + + for (i = 0; i < nr_bhs; i++) { + wait_on_buffer(bhs[i]); + if (!err && !buffer_uptodate(bhs[i])) + err = -EIO; + } + return err; +} + +int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bhs[MAX_BUF_PER_PAGE]; + int nr_bhs = MAX_BUF_PER_PAGE; + sector_t blknr, last_blknr; + int err, i, n; + + blknr = exfat_cluster_to_sector(sbi, clu); + last_blknr = blknr + sbi->sect_per_clus; + + if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { + exfat_fs_error_ratelimit(sb, + "%s: out of range(sect:%llu len:%u)", + __func__, (unsigned long long)blknr, + sbi->sect_per_clus); + return -EIO; + } + + /* Zeroing the unused blocks on this cluster */ + n = 0; + while (blknr < last_blknr) { + bhs[n] = sb_getblk(sb, blknr); + if (!bhs[n]) { + err = -ENOMEM; + goto release_bhs; + } + memset(bhs[n]->b_data, 0, sb->s_blocksize); + exfat_update_bh(sb, bhs[n], 0); + + n++; + blknr++; + + if (n == nr_bhs) { + if (IS_DIRSYNC(dir)) { + err = exfat_sync_bhs(bhs, n); + if (err) + goto release_bhs; + } + + for (i = 0; i < n; i++) + brelse(bhs[i]); + n = 0; + } + } + + if (IS_DIRSYNC(dir)) { + err = exfat_sync_bhs(bhs, n); + if (err) + goto release_bhs; + } + + for (i = 0; i < n; i++) + brelse(bhs[i]); + + return 0; + +release_bhs: + exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n", + (unsigned long long)blknr); + for (i = 0; i < n; i++) + bforget(bhs[i]); + return err; +} + +int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, + struct exfat_chain *p_chain) +{ + int ret = -ENOSPC; + unsigned int num_clusters = 0, total_cnt; + unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); + + if (unlikely(total_cnt < sbi->used_clusters)) { + exfat_fs_error_ratelimit(sb, + "%s: invalid used clusters(t:%u,u:%u)\n", + __func__, total_cnt, sbi->used_clusters); + return -EIO; + } + + if (num_alloc > total_cnt - sbi->used_clusters) + return -ENOSPC; + + hint_clu = p_chain->dir; + /* find new cluster */ + if (hint_clu == EXFAT_EOF_CLUSTER) { + if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { + exfat_msg(sb, KERN_ERR, + "sbi->clu_srch_ptr is invalid (%u)\n", + sbi->clu_srch_ptr); + sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; + } + + hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); + if (hint_clu == EXFAT_EOF_CLUSTER) + return -ENOSPC; + } + + /* check cluster validation */ + if (hint_clu < EXFAT_FIRST_CLUSTER && hint_clu >= sbi->num_clusters) { + exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n", + hint_clu); + hint_clu = EXFAT_FIRST_CLUSTER; + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) + return -EIO; + p_chain->flags = ALLOC_FAT_CHAIN; + } + } + + set_bit(EXFAT_SB_DIRTY, &sbi->s_state); + + p_chain->dir = EXFAT_EOF_CLUSTER; + + while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != + EXFAT_EOF_CLUSTER) { + if (new_clu != hint_clu && + p_chain->flags == ALLOC_NO_FAT_CHAIN) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) { + ret = -EIO; + goto free_cluster; + } + p_chain->flags = ALLOC_FAT_CHAIN; + } + + /* update allocation bitmap */ + if (exfat_set_bitmap(inode, new_clu)) { + ret = -EIO; + goto free_cluster; + } + + num_clusters++; + + /* update FAT table */ + if (p_chain->flags == ALLOC_FAT_CHAIN) { + if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { + ret = -EIO; + goto free_cluster; + } + } + + if (p_chain->dir == EXFAT_EOF_CLUSTER) { + p_chain->dir = new_clu; + } else if (p_chain->flags == ALLOC_FAT_CHAIN) { + if (exfat_ent_set(sb, last_clu, new_clu)) { + ret = -EIO; + goto free_cluster; + } + } + last_clu = new_clu; + + if (--num_alloc == 0) { + sbi->clu_srch_ptr = hint_clu; + sbi->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return 0; + } + + hint_clu = new_clu + 1; + if (hint_clu >= sbi->num_clusters) { + hint_clu = EXFAT_FIRST_CLUSTER; + + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) { + ret = -EIO; + goto free_cluster; + } + p_chain->flags = ALLOC_FAT_CHAIN; + } + } + } +free_cluster: + if (num_clusters) + exfat_free_cluster(inode, p_chain); + return ret; +} + +int exfat_count_num_clusters(struct super_block *sb, + struct exfat_chain *p_chain, unsigned int *ret_count) +{ + unsigned int i, count; + unsigned int clu; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { + *ret_count = 0; + return 0; + } + + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + *ret_count = p_chain->size; + return 0; + } + + clu = p_chain->dir; + count = 0; + for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { + count++; + if (exfat_ent_get(sb, clu, &clu)) + return -EIO; + if (clu == EXFAT_EOF_CLUSTER) + break; + } + + *ret_count = count; + return 0; +} From 1e49a94cf707204b66a3fb242f2814712c941f52 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:38 +0900 Subject: [PATCH 184/809] exfat: add bitmap operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of bitmap operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/balloc.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 fs/exfat/balloc.c diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c new file mode 100644 index 000000000000..6a04cc02565a --- /dev/null +++ b/fs/exfat/balloc.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static const unsigned char free_bit[] = { + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/ + 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/ + 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/ + 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/ + 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/ +}; + +static const unsigned char used_bit[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/ + 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/ + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/ + 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/ + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/ + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/ + 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/ + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/ + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/ + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/ + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/ +}; + +/* + * Allocation Bitmap Management Functions + */ +static int exfat_allocate_bitmap(struct super_block *sb, + struct exfat_dentry *ep) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long long map_size; + unsigned int i, need_map_size; + sector_t sector; + + sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu); + map_size = le64_to_cpu(ep->dentry.bitmap.size); + need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE) + + 1; + if (need_map_size != map_size) { + exfat_msg(sb, KERN_ERR, + "bogus allocation bitmap size(need : %u, cur : %lld)", + need_map_size, map_size); + /* + * Only allowed when bogus allocation + * bitmap size is large + */ + if (need_map_size > map_size) + return -EIO; + } + sbi->map_sectors = ((need_map_size - 1) >> + (sb->s_blocksize_bits)) + 1; + sbi->vol_amap = kmalloc_array(sbi->map_sectors, + sizeof(struct buffer_head *), GFP_KERNEL); + if (!sbi->vol_amap) + return -ENOMEM; + + sector = exfat_cluster_to_sector(sbi, sbi->map_clu); + for (i = 0; i < sbi->map_sectors; i++) { + sbi->vol_amap[i] = sb_bread(sb, sector + i); + if (!sbi->vol_amap[i]) { + /* release all buffers and free vol_amap */ + int j = 0; + + while (j < i) + brelse(sbi->vol_amap[j++]); + + kfree(sbi->vol_amap); + sbi->vol_amap = NULL; + return -EIO; + } + } + + sbi->pbr_bh = NULL; + return 0; +} + +int exfat_load_bitmap(struct super_block *sb) +{ + unsigned int i, type; + struct exfat_chain clu; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + while (clu.dir != EXFAT_EOF_CLUSTER) { + for (i = 0; i < sbi->dentries_per_clu; i++) { + struct exfat_dentry *ep; + struct buffer_head *bh; + + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + + type = exfat_get_entry_type(ep); + if (type == TYPE_UNUSED) + break; + if (type != TYPE_BITMAP) + continue; + if (ep->dentry.bitmap.flags == 0x0) { + int err; + + err = exfat_allocate_bitmap(sb, ep); + brelse(bh); + return err; + } + brelse(bh); + } + + if (exfat_get_next_cluster(sb, &clu.dir)) + return -EIO; + } + + return -EINVAL; +} + +void exfat_free_bitmap(struct exfat_sb_info *sbi) +{ + int i; + + brelse(sbi->pbr_bh); + + for (i = 0; i < sbi->map_sectors; i++) + __brelse(sbi->vol_amap[i]); + + kfree(sbi->vol_amap); +} + +/* + * If the value of "clu" is 0, it means cluster 2 which is the first cluster of + * the cluster heap. + */ +int exfat_set_bitmap(struct inode *inode, unsigned int clu) +{ + int i, b; + unsigned int ent_idx; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + WARN_ON(clu < EXFAT_FIRST_CLUSTER); + ent_idx = CLUSTER_TO_BITMAP_ENT(clu); + i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); + b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); + + set_bit_le(b, sbi->vol_amap[i]->b_data); + exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); + return 0; +} + +/* + * If the value of "clu" is 0, it means cluster 2 which is the first cluster of + * the cluster heap. + */ +void exfat_clear_bitmap(struct inode *inode, unsigned int clu) +{ + int i, b; + unsigned int ent_idx; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_mount_options *opts = &sbi->options; + + WARN_ON(clu < EXFAT_FIRST_CLUSTER); + ent_idx = CLUSTER_TO_BITMAP_ENT(clu); + i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); + b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); + + clear_bit_le(b, sbi->vol_amap[i]->b_data); + exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); + + if (opts->discard) { + int ret_discard; + + ret_discard = sb_issue_discard(sb, + exfat_cluster_to_sector(sbi, clu + + EXFAT_RESERVED_CLUSTERS), + (1 << sbi->sect_per_clus_bits), GFP_NOFS, 0); + + if (ret_discard == -EOPNOTSUPP) { + exfat_msg(sb, KERN_ERR, + "discard not supported by device, disabling"); + opts->discard = 0; + } + } +} + +/* + * If the value of "clu" is 0, it means cluster 2 which is the first cluster of + * the cluster heap. + */ +unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu) +{ + unsigned int i, map_i, map_b, ent_idx; + unsigned int clu_base, clu_free; + unsigned char k, clu_mask; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + WARN_ON(clu < EXFAT_FIRST_CLUSTER); + ent_idx = CLUSTER_TO_BITMAP_ENT(clu); + clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK)); + clu_mask = IGNORED_BITS_REMAINED(clu, clu_base); + + map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); + map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx); + + for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; + i += BITS_PER_BYTE) { + k = *(sbi->vol_amap[map_i]->b_data + map_b); + if (clu_mask > 0) { + k |= clu_mask; + clu_mask = 0; + } + if (k < 0xFF) { + clu_free = clu_base + free_bit[k]; + if (clu_free < sbi->num_clusters) + return clu_free; + } + clu_base += BITS_PER_BYTE; + + if (++map_b >= sb->s_blocksize || + clu_base >= sbi->num_clusters) { + if (++map_i >= sbi->map_sectors) { + clu_base = EXFAT_FIRST_CLUSTER; + map_i = 0; + } + map_b = 0; + } + } + + return EXFAT_EOF_CLUSTER; +} + +int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned int count = 0; + unsigned int i, map_i = 0, map_b = 0; + unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi); + unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK; + unsigned char clu_bits; + const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011, + 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111}; + + total_clus &= ~last_mask; + for (i = 0; i < total_clus; i += BITS_PER_BYTE) { + clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); + count += used_bit[clu_bits]; + if (++map_b >= (unsigned int)sb->s_blocksize) { + map_i++; + map_b = 0; + } + } + + if (last_mask) { + clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); + clu_bits &= last_bit_mask[last_mask]; + count += used_bit[clu_bits]; + } + + *ret_count = count; + return 0; +} From c35b6810c4952ae5776607e2c1d6a587425d5834 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:39 +0900 Subject: [PATCH 185/809] exfat: add exfat cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of exfat cache. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/cache.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 fs/exfat/cache.c diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c new file mode 100644 index 000000000000..03d0824fc368 --- /dev/null +++ b/fs/exfat/cache.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/fs/fat/cache.c + * + * Written 1992,1993 by Werner Almesberger + * + * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead + * of inode number. + * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +#define EXFAT_CACHE_VALID 0 +#define EXFAT_MAX_CACHE 16 + +struct exfat_cache { + struct list_head cache_list; + unsigned int nr_contig; /* number of contiguous clusters */ + unsigned int fcluster; /* cluster number in the file. */ + unsigned int dcluster; /* cluster number on disk. */ +}; + +struct exfat_cache_id { + unsigned int id; + unsigned int nr_contig; + unsigned int fcluster; + unsigned int dcluster; +}; + +static struct kmem_cache *exfat_cachep; + +static void exfat_cache_init_once(void *c) +{ + struct exfat_cache *cache = (struct exfat_cache *)c; + + INIT_LIST_HEAD(&cache->cache_list); +} + +int exfat_cache_init(void) +{ + exfat_cachep = kmem_cache_create("exfat_cache", + sizeof(struct exfat_cache), + 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, + exfat_cache_init_once); + if (!exfat_cachep) + return -ENOMEM; + return 0; +} + +void exfat_cache_shutdown(void) +{ + if (!exfat_cachep) + return; + kmem_cache_destroy(exfat_cachep); +} + +void exfat_cache_init_inode(struct inode *inode) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + + spin_lock_init(&ei->cache_lru_lock); + ei->nr_caches = 0; + ei->cache_valid_id = EXFAT_CACHE_VALID + 1; + INIT_LIST_HEAD(&ei->cache_lru); +} + +static inline struct exfat_cache *exfat_cache_alloc(void) +{ + return kmem_cache_alloc(exfat_cachep, GFP_NOFS); +} + +static inline void exfat_cache_free(struct exfat_cache *cache) +{ + WARN_ON(!list_empty(&cache->cache_list)); + kmem_cache_free(exfat_cachep, cache); +} + +static inline void exfat_cache_update_lru(struct inode *inode, + struct exfat_cache *cache) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + + if (ei->cache_lru.next != &cache->cache_list) + list_move(&cache->cache_list, &ei->cache_lru); +} + +static unsigned int exfat_cache_lookup(struct inode *inode, + unsigned int fclus, struct exfat_cache_id *cid, + unsigned int *cached_fclus, unsigned int *cached_dclus) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + static struct exfat_cache nohit = { .fcluster = 0, }; + struct exfat_cache *hit = &nohit, *p; + unsigned int offset = EXFAT_EOF_CLUSTER; + + spin_lock(&ei->cache_lru_lock); + list_for_each_entry(p, &ei->cache_lru, cache_list) { + /* Find the cache of "fclus" or nearest cache. */ + if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { + hit = p; + if (hit->fcluster + hit->nr_contig < fclus) { + offset = hit->nr_contig; + } else { + offset = fclus - hit->fcluster; + break; + } + } + } + if (hit != &nohit) { + exfat_cache_update_lru(inode, hit); + + cid->id = ei->cache_valid_id; + cid->nr_contig = hit->nr_contig; + cid->fcluster = hit->fcluster; + cid->dcluster = hit->dcluster; + *cached_fclus = cid->fcluster + offset; + *cached_dclus = cid->dcluster + offset; + } + spin_unlock(&ei->cache_lru_lock); + + return offset; +} + +static struct exfat_cache *exfat_cache_merge(struct inode *inode, + struct exfat_cache_id *new) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_cache *p; + + list_for_each_entry(p, &ei->cache_lru, cache_list) { + /* Find the same part as "new" in cluster-chain. */ + if (p->fcluster == new->fcluster) { + if (new->nr_contig > p->nr_contig) + p->nr_contig = new->nr_contig; + return p; + } + } + return NULL; +} + +static void exfat_cache_add(struct inode *inode, + struct exfat_cache_id *new) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_cache *cache, *tmp; + + if (new->fcluster == EXFAT_EOF_CLUSTER) /* dummy cache */ + return; + + spin_lock(&ei->cache_lru_lock); + if (new->id != EXFAT_CACHE_VALID && + new->id != ei->cache_valid_id) + goto unlock; /* this cache was invalidated */ + + cache = exfat_cache_merge(inode, new); + if (cache == NULL) { + if (ei->nr_caches < EXFAT_MAX_CACHE) { + ei->nr_caches++; + spin_unlock(&ei->cache_lru_lock); + + tmp = exfat_cache_alloc(); + if (!tmp) { + spin_lock(&ei->cache_lru_lock); + ei->nr_caches--; + spin_unlock(&ei->cache_lru_lock); + return; + } + + spin_lock(&ei->cache_lru_lock); + cache = exfat_cache_merge(inode, new); + if (cache != NULL) { + ei->nr_caches--; + exfat_cache_free(tmp); + goto out_update_lru; + } + cache = tmp; + } else { + struct list_head *p = ei->cache_lru.prev; + + cache = list_entry(p, + struct exfat_cache, cache_list); + } + cache->fcluster = new->fcluster; + cache->dcluster = new->dcluster; + cache->nr_contig = new->nr_contig; + } +out_update_lru: + exfat_cache_update_lru(inode, cache); +unlock: + spin_unlock(&ei->cache_lru_lock); +} + +/* + * Cache invalidation occurs rarely, thus the LRU chain is not updated. It + * fixes itself after a while. + */ +static void __exfat_cache_inval_inode(struct inode *inode) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_cache *cache; + + while (!list_empty(&ei->cache_lru)) { + cache = list_entry(ei->cache_lru.next, + struct exfat_cache, cache_list); + list_del_init(&cache->cache_list); + ei->nr_caches--; + exfat_cache_free(cache); + } + /* Update. The copy of caches before this id is discarded. */ + ei->cache_valid_id++; + if (ei->cache_valid_id == EXFAT_CACHE_VALID) + ei->cache_valid_id++; +} + +void exfat_cache_inval_inode(struct inode *inode) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + + spin_lock(&ei->cache_lru_lock); + __exfat_cache_inval_inode(inode); + spin_unlock(&ei->cache_lru_lock); +} + +static inline int cache_contiguous(struct exfat_cache_id *cid, + unsigned int dclus) +{ + cid->nr_contig++; + return cid->dcluster + cid->nr_contig == dclus; +} + +static inline void cache_init(struct exfat_cache_id *cid, + unsigned int fclus, unsigned int dclus) +{ + cid->id = EXFAT_CACHE_VALID; + cid->fcluster = fclus; + cid->dcluster = dclus; + cid->nr_contig = 0; +} + +int exfat_get_cluster(struct inode *inode, unsigned int cluster, + unsigned int *fclus, unsigned int *dclus, + unsigned int *last_dclus, int allow_eof) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned int limit = sbi->num_clusters; + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_cache_id cid; + unsigned int content; + + if (ei->start_clu == EXFAT_FREE_CLUSTER) { + exfat_fs_error(sb, + "invalid access to exfat cache (entry 0x%08x)", + ei->start_clu); + return -EIO; + } + + *fclus = 0; + *dclus = ei->start_clu; + *last_dclus = *dclus; + + /* + * Don`t use exfat_cache if zero offset or non-cluster allocation + */ + if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER) + return 0; + + cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER); + + if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) == + EXFAT_EOF_CLUSTER) { + /* + * dummy, always not contiguous + * This is reinitialized by cache_init(), later. + */ + WARN_ON(cid.id != EXFAT_CACHE_VALID || + cid.fcluster != EXFAT_EOF_CLUSTER || + cid.dcluster != EXFAT_EOF_CLUSTER || + cid.nr_contig != 0); + } + + if (*fclus == cluster) + return 0; + + while (*fclus < cluster) { + /* prevent the infinite loop of cluster chain */ + if (*fclus > limit) { + exfat_fs_error(sb, + "detected the cluster chain loop (i_pos %u)", + (*fclus)); + return -EIO; + } + + if (exfat_ent_get(sb, *dclus, &content)) + return -EIO; + + *last_dclus = *dclus; + *dclus = content; + (*fclus)++; + + if (content == EXFAT_EOF_CLUSTER) { + if (!allow_eof) { + exfat_fs_error(sb, + "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)", + *fclus, (*last_dclus)); + return -EIO; + } + + break; + } + + if (!cache_contiguous(&cid, *dclus)) + cache_init(&cid, *fclus, *dclus); + } + + exfat_cache_add(inode, &cid); + return 0; +} From 772b29cca528fcb21374bb3e597d848779938d16 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:40 +0900 Subject: [PATCH 186/809] exfat: add misc operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of misc operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Arnd Bergmann Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/misc.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 fs/exfat/misc.c diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c new file mode 100644 index 000000000000..14a3300848f6 --- /dev/null +++ b/fs/exfat/misc.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +/* + * exfat_fs_error reports a file system problem that might indicate fa data + * corruption/inconsistency. Depending on 'errors' mount option the + * panic() is called, or error message is printed FAT and nothing is done, + * or filesystem is remounted read-only (default behavior). + * In case the file system is remounted read-only, it can be made writable + * again by remounting it. + */ +void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) +{ + struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; + va_list args; + struct va_format vaf; + + if (report) { + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + exfat_msg(sb, KERN_ERR, "error, %pV\n", &vaf); + va_end(args); + } + + if (opts->errors == EXFAT_ERRORS_PANIC) { + panic("exFAT-fs (%s): fs panic from previous error\n", + sb->s_id); + } else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) { + sb->s_flags |= SB_RDONLY; + exfat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); + } +} + +/* + * exfat_msg() - print preformated EXFAT specific messages. + * All logs except what uses exfat_fs_error() should be written by exfat_msg() + */ +void exfat_msg(struct super_block *sb, const char *level, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + /* level means KERN_ pacility level */ + printk("%sexFAT-fs (%s): %pV\n", level, sb->s_id, &vaf); + va_end(args); +} + +#define SECS_PER_MIN (60) +#define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN) + +static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) +{ + if (tz_off <= 0x3F) + ts->tv_sec -= TIMEZONE_SEC(tz_off); + else /* 0x40 <= (tz_off & 0x7F) <=0x7F */ + ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off); +} + +/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ +void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, + u8 tz, __le16 time, __le16 date, u8 time_ms) +{ + u16 t = le16_to_cpu(time); + u16 d = le16_to_cpu(date); + + ts->tv_sec = mktime64(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F, + t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1); + + + /* time_ms field represent 0 ~ 199(1990 ms) */ + if (time_ms) { + ts->tv_sec += time_ms / 100; + ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; + } + + if (tz & EXFAT_TZ_VALID) + /* Adjust timezone to UTC0. */ + exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID); + else + /* Convert from local time to UTC using time_offset. */ + ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; +} + +/* Convert linear UNIX date to a EXFAT time/date pair. */ +void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, + u8 *tz, __le16 *time, __le16 *date, u8 *time_ms) +{ + struct tm tm; + u16 t, d; + + time64_to_tm(ts->tv_sec, 0, &tm); + t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); + d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday; + + *time = cpu_to_le16(t); + *date = cpu_to_le16(d); + + /* time_ms field represent 0 ~ 199(1990 ms) */ + if (time_ms) + *time_ms = (tm.tm_sec & 1) * 100 + + ts->tv_nsec / (10 * NSEC_PER_MSEC); + + /* + * Record 00h value for OffsetFromUtc field and 1 value for OffsetValid + * to indicate that local time and UTC are the same. + */ + *tz = EXFAT_TZ_VALID; +} + +unsigned short exfat_calc_chksum_2byte(void *data, int len, + unsigned short chksum, int type) +{ + int i; + unsigned char *c = (unsigned char *)data; + + for (i = 0; i < len; i++, c++) { + if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY)) + continue; + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + + (unsigned short)*c; + } + return chksum; +} + +void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync) +{ + set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + + if (sync) + sync_dirty_buffer(bh); +} + +void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, + unsigned int size, unsigned char flags) +{ + ec->dir = dir; + ec->size = size; + ec->flags = flags; +} + +void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec) +{ + return exfat_chain_set(dup, ec->dir, ec->size, ec->flags); +} From 370e812b3ec190fa492c9fd5a80c38b086d105c0 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:41 +0900 Subject: [PATCH 187/809] exfat: add nls operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the implementation of nls operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exfat/nls.c | 831 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 831 insertions(+) create mode 100644 fs/exfat/nls.c diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c new file mode 100644 index 000000000000..6d1c3ae130ff --- /dev/null +++ b/fs/exfat/nls.c @@ -0,0 +1,831 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +/* Upcase tabel macro */ +#define EXFAT_NUM_UPCASE (2918) +#define UTBL_COUNT (0x10000) + +/* + * Upcase table in compressed format (7.2.5.1 Recommended Up-case Table + * in exfat specification, See: + * https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification). + */ +static const unsigned short uni_def_upcase[EXFAT_NUM_UPCASE] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00f7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178, + 0x0100, 0x0100, 0x0102, 0x0102, 0x0104, 0x0104, 0x0106, 0x0106, + 0x0108, 0x0108, 0x010a, 0x010a, 0x010c, 0x010c, 0x010e, 0x010e, + 0x0110, 0x0110, 0x0112, 0x0112, 0x0114, 0x0114, 0x0116, 0x0116, + 0x0118, 0x0118, 0x011a, 0x011a, 0x011c, 0x011c, 0x011e, 0x011e, + 0x0120, 0x0120, 0x0122, 0x0122, 0x0124, 0x0124, 0x0126, 0x0126, + 0x0128, 0x0128, 0x012a, 0x012a, 0x012c, 0x012c, 0x012e, 0x012e, + 0x0130, 0x0131, 0x0132, 0x0132, 0x0134, 0x0134, 0x0136, 0x0136, + 0x0138, 0x0139, 0x0139, 0x013b, 0x013b, 0x013d, 0x013d, 0x013f, + 0x013f, 0x0141, 0x0141, 0x0143, 0x0143, 0x0145, 0x0145, 0x0147, + 0x0147, 0x0149, 0x014a, 0x014a, 0x014c, 0x014c, 0x014e, 0x014e, + 0x0150, 0x0150, 0x0152, 0x0152, 0x0154, 0x0154, 0x0156, 0x0156, + 0x0158, 0x0158, 0x015a, 0x015a, 0x015c, 0x015c, 0x015e, 0x015e, + 0x0160, 0x0160, 0x0162, 0x0162, 0x0164, 0x0164, 0x0166, 0x0166, + 0x0168, 0x0168, 0x016a, 0x016a, 0x016c, 0x016c, 0x016e, 0x016e, + 0x0170, 0x0170, 0x0172, 0x0172, 0x0174, 0x0174, 0x0176, 0x0176, + 0x0178, 0x0179, 0x0179, 0x017b, 0x017b, 0x017d, 0x017d, 0x017f, + 0x0243, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187, + 0x0187, 0x0189, 0x018a, 0x018b, 0x018b, 0x018d, 0x018e, 0x018f, + 0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01f6, 0x0196, 0x0197, + 0x0198, 0x0198, 0x023d, 0x019b, 0x019c, 0x019d, 0x0220, 0x019f, + 0x01a0, 0x01a0, 0x01a2, 0x01a2, 0x01a4, 0x01a4, 0x01a6, 0x01a7, + 0x01a7, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ac, 0x01ae, 0x01af, + 0x01af, 0x01b1, 0x01b2, 0x01b3, 0x01b3, 0x01b5, 0x01b5, 0x01b7, + 0x01b8, 0x01b8, 0x01ba, 0x01bb, 0x01bc, 0x01bc, 0x01be, 0x01f7, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c4, 0x01c7, + 0x01c8, 0x01c7, 0x01ca, 0x01cb, 0x01ca, 0x01cd, 0x01cd, 0x01cf, + 0x01cf, 0x01d1, 0x01d1, 0x01d3, 0x01d3, 0x01d5, 0x01d5, 0x01d7, + 0x01d7, 0x01d9, 0x01d9, 0x01db, 0x01db, 0x018e, 0x01de, 0x01de, + 0x01e0, 0x01e0, 0x01e2, 0x01e2, 0x01e4, 0x01e4, 0x01e6, 0x01e6, + 0x01e8, 0x01e8, 0x01ea, 0x01ea, 0x01ec, 0x01ec, 0x01ee, 0x01ee, + 0x01f0, 0x01f1, 0x01f2, 0x01f1, 0x01f4, 0x01f4, 0x01f6, 0x01f7, + 0x01f8, 0x01f8, 0x01fa, 0x01fa, 0x01fc, 0x01fc, 0x01fe, 0x01fe, + 0x0200, 0x0200, 0x0202, 0x0202, 0x0204, 0x0204, 0x0206, 0x0206, + 0x0208, 0x0208, 0x020a, 0x020a, 0x020c, 0x020c, 0x020e, 0x020e, + 0x0210, 0x0210, 0x0212, 0x0212, 0x0214, 0x0214, 0x0216, 0x0216, + 0x0218, 0x0218, 0x021a, 0x021a, 0x021c, 0x021c, 0x021e, 0x021e, + 0x0220, 0x0221, 0x0222, 0x0222, 0x0224, 0x0224, 0x0226, 0x0226, + 0x0228, 0x0228, 0x022a, 0x022a, 0x022c, 0x022c, 0x022e, 0x022e, + 0x0230, 0x0230, 0x0232, 0x0232, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x2c65, 0x023b, 0x023b, 0x023d, 0x2c66, 0x023f, + 0x0240, 0x0241, 0x0241, 0x0243, 0x0244, 0x0245, 0x0246, 0x0246, + 0x0248, 0x0248, 0x024a, 0x024a, 0x024c, 0x024c, 0x024e, 0x024e, + 0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018a, + 0x0258, 0x018f, 0x025a, 0x0190, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0197, 0x0196, 0x026a, 0x2c62, 0x026c, 0x026d, 0x026e, 0x019c, + 0x0270, 0x0271, 0x019d, 0x0273, 0x0274, 0x019f, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x2c64, 0x027e, 0x027f, + 0x01a6, 0x0281, 0x0282, 0x01a9, 0x0284, 0x0285, 0x0286, 0x0287, + 0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x01b7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, + 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, + 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x037a, 0x03fd, 0x03fe, 0x03ff, 0x037e, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, + 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038d, 0x038e, 0x038f, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x0386, 0x0388, 0x0389, 0x038a, + 0x03b0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a3, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x03cf, + 0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d5, 0x03d6, 0x03d7, + 0x03d8, 0x03d8, 0x03da, 0x03da, 0x03dc, 0x03dc, 0x03de, 0x03de, + 0x03e0, 0x03e0, 0x03e2, 0x03e2, 0x03e4, 0x03e4, 0x03e6, 0x03e6, + 0x03e8, 0x03e8, 0x03ea, 0x03ea, 0x03ec, 0x03ec, 0x03ee, 0x03ee, + 0x03f0, 0x03f1, 0x03f9, 0x03f3, 0x03f4, 0x03f5, 0x03f6, 0x03f7, + 0x03f7, 0x03f9, 0x03fa, 0x03fa, 0x03fc, 0x03fd, 0x03fe, 0x03ff, + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, + 0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466, + 0x0468, 0x0468, 0x046a, 0x046a, 0x046c, 0x046c, 0x046e, 0x046e, + 0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0476, 0x0476, + 0x0478, 0x0478, 0x047a, 0x047a, 0x047c, 0x047c, 0x047e, 0x047e, + 0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048a, 0x048a, 0x048c, 0x048c, 0x048e, 0x048e, + 0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496, + 0x0498, 0x0498, 0x049a, 0x049a, 0x049c, 0x049c, 0x049e, 0x049e, + 0x04a0, 0x04a0, 0x04a2, 0x04a2, 0x04a4, 0x04a4, 0x04a6, 0x04a6, + 0x04a8, 0x04a8, 0x04aa, 0x04aa, 0x04ac, 0x04ac, 0x04ae, 0x04ae, + 0x04b0, 0x04b0, 0x04b2, 0x04b2, 0x04b4, 0x04b4, 0x04b6, 0x04b6, + 0x04b8, 0x04b8, 0x04ba, 0x04ba, 0x04bc, 0x04bc, 0x04be, 0x04be, + 0x04c0, 0x04c1, 0x04c1, 0x04c3, 0x04c3, 0x04c5, 0x04c5, 0x04c7, + 0x04c7, 0x04c9, 0x04c9, 0x04cb, 0x04cb, 0x04cd, 0x04cd, 0x04c0, + 0x04d0, 0x04d0, 0x04d2, 0x04d2, 0x04d4, 0x04d4, 0x04d6, 0x04d6, + 0x04d8, 0x04d8, 0x04da, 0x04da, 0x04dc, 0x04dc, 0x04de, 0x04de, + 0x04e0, 0x04e0, 0x04e2, 0x04e2, 0x04e4, 0x04e4, 0x04e6, 0x04e6, + 0x04e8, 0x04e8, 0x04ea, 0x04ea, 0x04ec, 0x04ec, 0x04ee, 0x04ee, + 0x04f0, 0x04f0, 0x04f2, 0x04f2, 0x04f4, 0x04f4, 0x04f6, 0x04f6, + 0x04f8, 0x04f8, 0x04fa, 0x04fa, 0x04fc, 0x04fc, 0x04fe, 0x04fe, + 0x0500, 0x0500, 0x0502, 0x0502, 0x0504, 0x0504, 0x0506, 0x0506, + 0x0508, 0x0508, 0x050a, 0x050a, 0x050c, 0x050c, 0x050e, 0x050e, + 0x0510, 0x0510, 0x0512, 0x0512, 0x0514, 0x0515, 0x0516, 0x0517, + 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, + 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, + 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, + 0x0530, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, + 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, + 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, + 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, + 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557, + 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, + 0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, + 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, + 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, + 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, + 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0xffff, + 0x17f6, 0x2c63, 0x1d7e, 0x1d7f, 0x1d80, 0x1d81, 0x1d82, 0x1d83, + 0x1d84, 0x1d85, 0x1d86, 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, + 0x1d8c, 0x1d8d, 0x1d8e, 0x1d8f, 0x1d90, 0x1d91, 0x1d92, 0x1d93, + 0x1d94, 0x1d95, 0x1d96, 0x1d97, 0x1d98, 0x1d99, 0x1d9a, 0x1d9b, + 0x1d9c, 0x1d9d, 0x1d9e, 0x1d9f, 0x1da0, 0x1da1, 0x1da2, 0x1da3, + 0x1da4, 0x1da5, 0x1da6, 0x1da7, 0x1da8, 0x1da9, 0x1daa, 0x1dab, + 0x1dac, 0x1dad, 0x1dae, 0x1daf, 0x1db0, 0x1db1, 0x1db2, 0x1db3, + 0x1db4, 0x1db5, 0x1db6, 0x1db7, 0x1db8, 0x1db9, 0x1dba, 0x1dbb, + 0x1dbc, 0x1dbd, 0x1dbe, 0x1dbf, 0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3, + 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dca, 0x1dcb, + 0x1dcc, 0x1dcd, 0x1dce, 0x1dcf, 0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3, + 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, + 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, + 0x1de4, 0x1de5, 0x1de6, 0x1de7, 0x1de8, 0x1de9, 0x1dea, 0x1deb, + 0x1dec, 0x1ded, 0x1dee, 0x1def, 0x1df0, 0x1df1, 0x1df2, 0x1df3, + 0x1df4, 0x1df5, 0x1df6, 0x1df7, 0x1df8, 0x1df9, 0x1dfa, 0x1dfb, + 0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x1e00, 0x1e00, 0x1e02, 0x1e02, + 0x1e04, 0x1e04, 0x1e06, 0x1e06, 0x1e08, 0x1e08, 0x1e0a, 0x1e0a, + 0x1e0c, 0x1e0c, 0x1e0e, 0x1e0e, 0x1e10, 0x1e10, 0x1e12, 0x1e12, + 0x1e14, 0x1e14, 0x1e16, 0x1e16, 0x1e18, 0x1e18, 0x1e1a, 0x1e1a, + 0x1e1c, 0x1e1c, 0x1e1e, 0x1e1e, 0x1e20, 0x1e20, 0x1e22, 0x1e22, + 0x1e24, 0x1e24, 0x1e26, 0x1e26, 0x1e28, 0x1e28, 0x1e2a, 0x1e2a, + 0x1e2c, 0x1e2c, 0x1e2e, 0x1e2e, 0x1e30, 0x1e30, 0x1e32, 0x1e32, + 0x1e34, 0x1e34, 0x1e36, 0x1e36, 0x1e38, 0x1e38, 0x1e3a, 0x1e3a, + 0x1e3c, 0x1e3c, 0x1e3e, 0x1e3e, 0x1e40, 0x1e40, 0x1e42, 0x1e42, + 0x1e44, 0x1e44, 0x1e46, 0x1e46, 0x1e48, 0x1e48, 0x1e4a, 0x1e4a, + 0x1e4c, 0x1e4c, 0x1e4e, 0x1e4e, 0x1e50, 0x1e50, 0x1e52, 0x1e52, + 0x1e54, 0x1e54, 0x1e56, 0x1e56, 0x1e58, 0x1e58, 0x1e5a, 0x1e5a, + 0x1e5c, 0x1e5c, 0x1e5e, 0x1e5e, 0x1e60, 0x1e60, 0x1e62, 0x1e62, + 0x1e64, 0x1e64, 0x1e66, 0x1e66, 0x1e68, 0x1e68, 0x1e6a, 0x1e6a, + 0x1e6c, 0x1e6c, 0x1e6e, 0x1e6e, 0x1e70, 0x1e70, 0x1e72, 0x1e72, + 0x1e74, 0x1e74, 0x1e76, 0x1e76, 0x1e78, 0x1e78, 0x1e7a, 0x1e7a, + 0x1e7c, 0x1e7c, 0x1e7e, 0x1e7e, 0x1e80, 0x1e80, 0x1e82, 0x1e82, + 0x1e84, 0x1e84, 0x1e86, 0x1e86, 0x1e88, 0x1e88, 0x1e8a, 0x1e8a, + 0x1e8c, 0x1e8c, 0x1e8e, 0x1e8e, 0x1e90, 0x1e90, 0x1e92, 0x1e92, + 0x1e94, 0x1e94, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e9b, + 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea0, 0x1ea0, 0x1ea2, 0x1ea2, + 0x1ea4, 0x1ea4, 0x1ea6, 0x1ea6, 0x1ea8, 0x1ea8, 0x1eaa, 0x1eaa, + 0x1eac, 0x1eac, 0x1eae, 0x1eae, 0x1eb0, 0x1eb0, 0x1eb2, 0x1eb2, + 0x1eb4, 0x1eb4, 0x1eb6, 0x1eb6, 0x1eb8, 0x1eb8, 0x1eba, 0x1eba, + 0x1ebc, 0x1ebc, 0x1ebe, 0x1ebe, 0x1ec0, 0x1ec0, 0x1ec2, 0x1ec2, + 0x1ec4, 0x1ec4, 0x1ec6, 0x1ec6, 0x1ec8, 0x1ec8, 0x1eca, 0x1eca, + 0x1ecc, 0x1ecc, 0x1ece, 0x1ece, 0x1ed0, 0x1ed0, 0x1ed2, 0x1ed2, + 0x1ed4, 0x1ed4, 0x1ed6, 0x1ed6, 0x1ed8, 0x1ed8, 0x1eda, 0x1eda, + 0x1edc, 0x1edc, 0x1ede, 0x1ede, 0x1ee0, 0x1ee0, 0x1ee2, 0x1ee2, + 0x1ee4, 0x1ee4, 0x1ee6, 0x1ee6, 0x1ee8, 0x1ee8, 0x1eea, 0x1eea, + 0x1eec, 0x1eec, 0x1eee, 0x1eee, 0x1ef0, 0x1ef0, 0x1ef2, 0x1ef2, + 0x1ef4, 0x1ef4, 0x1ef6, 0x1ef6, 0x1ef8, 0x1ef8, 0x1efa, 0x1efb, + 0x1efc, 0x1efd, 0x1efe, 0x1eff, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, + 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, + 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, + 0x1f1c, 0x1f1d, 0x1f16, 0x1f17, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, + 0x1f1c, 0x1f1d, 0x1f1e, 0x1f1f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, + 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, + 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, + 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, + 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, + 0x1f4c, 0x1f4d, 0x1f46, 0x1f47, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, + 0x1f4c, 0x1f4d, 0x1f4e, 0x1f4f, 0x1f50, 0x1f59, 0x1f52, 0x1f5b, + 0x1f54, 0x1f5d, 0x1f56, 0x1f5f, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, + 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, + 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, + 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, + 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, + 0x1ffa, 0x1ffb, 0x1f7e, 0x1f7f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, + 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, + 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, + 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, + 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, + 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, + 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fb2, 0x1fbc, + 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb, + 0x1fbc, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, + 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, + 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, 0x1fd8, 0x1fd9, 0x1fd2, 0x1fd3, + 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb, + 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, 0x1fe8, 0x1fe9, 0x1fe2, 0x1fe3, + 0x1fe4, 0x1fec, 0x1fe6, 0x1fe7, 0x1fe8, 0x1fe9, 0x1fea, 0x1feb, + 0x1fec, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, + 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb, + 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff, 0x2000, 0x2001, 0x2002, 0x2003, + 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x200b, + 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2013, + 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b, + 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, 0x2021, 0x2022, 0x2023, + 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x202a, 0x202b, + 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2031, 0x2032, 0x2033, + 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, + 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, + 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204a, 0x204b, + 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, 0x2051, 0x2052, 0x2053, + 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205a, 0x205b, + 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, 0x2061, 0x2062, 0x2063, + 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x206b, + 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, 0x2071, 0x2072, 0x2073, + 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207a, 0x207b, + 0x207c, 0x207d, 0x207e, 0x207f, 0x2080, 0x2081, 0x2082, 0x2083, + 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208a, 0x208b, + 0x208c, 0x208d, 0x208e, 0x208f, 0x2090, 0x2091, 0x2092, 0x2093, + 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209a, 0x209b, + 0x209c, 0x209d, 0x209e, 0x209f, 0x20a0, 0x20a1, 0x20a2, 0x20a3, + 0x20a4, 0x20a5, 0x20a6, 0x20a7, 0x20a8, 0x20a9, 0x20aa, 0x20ab, + 0x20ac, 0x20ad, 0x20ae, 0x20af, 0x20b0, 0x20b1, 0x20b2, 0x20b3, + 0x20b4, 0x20b5, 0x20b6, 0x20b7, 0x20b8, 0x20b9, 0x20ba, 0x20bb, + 0x20bc, 0x20bd, 0x20be, 0x20bf, 0x20c0, 0x20c1, 0x20c2, 0x20c3, + 0x20c4, 0x20c5, 0x20c6, 0x20c7, 0x20c8, 0x20c9, 0x20ca, 0x20cb, + 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20d0, 0x20d1, 0x20d2, 0x20d3, + 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8, 0x20d9, 0x20da, 0x20db, + 0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0, 0x20e1, 0x20e2, 0x20e3, + 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8, 0x20e9, 0x20ea, 0x20eb, + 0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0, 0x20f1, 0x20f2, 0x20f3, + 0x20f4, 0x20f5, 0x20f6, 0x20f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, + 0x20fc, 0x20fd, 0x20fe, 0x20ff, 0x2100, 0x2101, 0x2102, 0x2103, + 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210a, 0x210b, + 0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113, + 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211a, 0x211b, + 0x211c, 0x211d, 0x211e, 0x211f, 0x2120, 0x2121, 0x2122, 0x2123, + 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212b, + 0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133, + 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213a, 0x213b, + 0x213c, 0x213d, 0x213e, 0x213f, 0x2140, 0x2141, 0x2142, 0x2143, + 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214a, 0x214b, + 0x214c, 0x214d, 0x2132, 0x214f, 0x2150, 0x2151, 0x2152, 0x2153, + 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x215b, + 0x215c, 0x215d, 0x215e, 0x215f, 0x2160, 0x2161, 0x2162, 0x2163, + 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, + 0x216c, 0x216d, 0x216e, 0x216f, 0x2160, 0x2161, 0x2162, 0x2163, + 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, + 0x216c, 0x216d, 0x216e, 0x216f, 0x2180, 0x2181, 0x2182, 0x2183, + 0x2183, 0xffff, 0x034b, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, + 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, + 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, + 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0xffff, 0x0746, 0x2c00, + 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, + 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, + 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, + 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, + 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, + 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c5f, 0x2c60, + 0x2c60, 0x2c62, 0x2c63, 0x2c64, 0x2c65, 0x2c66, 0x2c67, 0x2c67, + 0x2c69, 0x2c69, 0x2c6b, 0x2c6b, 0x2c6d, 0x2c6e, 0x2c6f, 0x2c70, + 0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c75, 0x2c75, 0x2c77, 0x2c78, + 0x2c79, 0x2c7a, 0x2c7b, 0x2c7c, 0x2c7d, 0x2c7e, 0x2c7f, 0x2c80, + 0x2c80, 0x2c82, 0x2c82, 0x2c84, 0x2c84, 0x2c86, 0x2c86, 0x2c88, + 0x2c88, 0x2c8a, 0x2c8a, 0x2c8c, 0x2c8c, 0x2c8e, 0x2c8e, 0x2c90, + 0x2c90, 0x2c92, 0x2c92, 0x2c94, 0x2c94, 0x2c96, 0x2c96, 0x2c98, + 0x2c98, 0x2c9a, 0x2c9a, 0x2c9c, 0x2c9c, 0x2c9e, 0x2c9e, 0x2ca0, + 0x2ca0, 0x2ca2, 0x2ca2, 0x2ca4, 0x2ca4, 0x2ca6, 0x2ca6, 0x2ca8, + 0x2ca8, 0x2caa, 0x2caa, 0x2cac, 0x2cac, 0x2cae, 0x2cae, 0x2cb0, + 0x2cb0, 0x2cb2, 0x2cb2, 0x2cb4, 0x2cb4, 0x2cb6, 0x2cb6, 0x2cb8, + 0x2cb8, 0x2cba, 0x2cba, 0x2cbc, 0x2cbc, 0x2cbe, 0x2cbe, 0x2cc0, + 0x2cc0, 0x2cc2, 0x2cc2, 0x2cc4, 0x2cc4, 0x2cc6, 0x2cc6, 0x2cc8, + 0x2cc8, 0x2cca, 0x2cca, 0x2ccc, 0x2ccc, 0x2cce, 0x2cce, 0x2cd0, + 0x2cd0, 0x2cd2, 0x2cd2, 0x2cd4, 0x2cd4, 0x2cd6, 0x2cd6, 0x2cd8, + 0x2cd8, 0x2cda, 0x2cda, 0x2cdc, 0x2cdc, 0x2cde, 0x2cde, 0x2ce0, + 0x2ce0, 0x2ce2, 0x2ce2, 0x2ce4, 0x2ce5, 0x2ce6, 0x2ce7, 0x2ce8, + 0x2ce9, 0x2cea, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cef, 0x2cf0, + 0x2cf1, 0x2cf2, 0x2cf3, 0x2cf4, 0x2cf5, 0x2cf6, 0x2cf7, 0x2cf8, + 0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfd, 0x2cfe, 0x2cff, 0x10a0, + 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, + 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, + 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, + 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, + 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0xffff, 0xd21b, 0xff21, + 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, + 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, + 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, + 0xff3a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61, + 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69, + 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71, + 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79, + 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81, + 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89, + 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91, + 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99, + 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xffa0, 0xffa1, + 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, 0xffa8, 0xffa9, + 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, 0xffb0, 0xffb1, + 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, 0xffb8, 0xffb9, + 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, 0xffc0, 0xffc1, + 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, + 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, 0xffd0, 0xffd1, + 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, 0xffd8, 0xffd9, + 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, 0xffe0, 0xffe1, + 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, 0xffe8, 0xffe9, + 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, 0xfff0, 0xfff1, + 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, 0xfff8, 0xfff9, + 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff, +}; + +/* + * Allow full-width illegal characters : + * "MS windows 7" supports full-width-invalid-name-characters. + * So we should check half-width-invalid-name-characters(ASCII) only + * for compatibility. + * + * " * / : < > ? \ | + */ +static unsigned short bad_uni_chars[] = { + 0x0022, 0x002A, 0x002F, 0x003A, + 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, + 0 +}; + +static int exfat_convert_char_to_ucs2(struct nls_table *nls, + const unsigned char *ch, int ch_len, unsigned short *ucs2, + int *lossy) +{ + int len; + + *ucs2 = 0x0; + + if (ch[0] < 0x80) { + *ucs2 = ch[0]; + return 1; + } + + len = nls->char2uni(ch, ch_len, ucs2); + if (len < 0) { + /* conversion failed */ + if (lossy != NULL) + *lossy |= NLS_NAME_LOSSY; + *ucs2 = '_'; + return 1; + } + return len; +} + +static int exfat_convert_ucs2_to_char(struct nls_table *nls, + unsigned short ucs2, unsigned char *ch, int *lossy) +{ + int len; + + ch[0] = 0x0; + + if (ucs2 < 0x0080) { + ch[0] = ucs2; + return 1; + } + + len = nls->uni2char(ucs2, ch, MAX_CHARSET_SIZE); + if (len < 0) { + /* conversion failed */ + if (lossy != NULL) + *lossy |= NLS_NAME_LOSSY; + ch[0] = '_'; + return 1; + } + return len; +} + +unsigned short exfat_toupper(struct super_block *sb, unsigned short a) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + return sbi->vol_utbl[a] ? sbi->vol_utbl[a] : a; +} + +static unsigned short *exfat_wstrchr(unsigned short *str, unsigned short wchar) +{ + while (*str) { + if (*(str++) == wchar) + return str; + } + return NULL; +} + +int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, + unsigned short *b, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++, a++, b++) + if (exfat_toupper(sb, *a) != exfat_toupper(sb, *b)) + return 1; + return 0; +} + +static int exfat_utf16_to_utf8(struct super_block *sb, + struct exfat_uni_name *p_uniname, unsigned char *p_cstring, + int buflen) +{ + int len; + const unsigned short *uniname = p_uniname->name; + + /* always len >= 0 */ + len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, + p_cstring, buflen); + p_cstring[len] = '\0'; + return len; +} + +static int exfat_utf8_to_utf16(struct super_block *sb, + const unsigned char *p_cstring, const int len, + struct exfat_uni_name *p_uniname, int *p_lossy) +{ + int i, unilen, lossy = NLS_NAME_NO_LOSSY; + unsigned short upname[MAX_NAME_LENGTH + 1]; + unsigned short *uniname = p_uniname->name; + + WARN_ON(!len); + + unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN, + (wchar_t *)uniname, MAX_NAME_LENGTH + 2); + if (unilen < 0) { + exfat_msg(sb, KERN_ERR, + "failed to %s (err : %d) nls len : %d", + __func__, unilen, len); + return unilen; + } + + if (unilen > MAX_NAME_LENGTH) { + exfat_msg(sb, KERN_ERR, + "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", + __func__, len, unilen, MAX_NAME_LENGTH); + return -ENAMETOOLONG; + } + + p_uniname->name_len = unilen & 0xFF; + + for (i = 0; i < unilen; i++) { + if (*uniname < 0x0020 || + exfat_wstrchr(bad_uni_chars, *uniname)) + lossy |= NLS_NAME_LOSSY; + + upname[i] = exfat_toupper(sb, *uniname); + uniname++; + } + + *uniname = '\0'; + p_uniname->name_len = unilen; + p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, + CS_DEFAULT); + + if (p_lossy) + *p_lossy = lossy; + return unilen; +} + +#define PLANE_SIZE 0x00010000 +#define SURROGATE_MASK 0xfffff800 +#define SURROGATE_PAIR 0x0000d800 +#define SURROGATE_LOW 0x00000400 +#define SURROGATE_BITS 0x000003ff + +unsigned short exfat_high_surrogate(unicode_t u) +{ + return ((u - PLANE_SIZE) >> 10) + SURROGATE_PAIR; +} + +unsigned short exfat_low_surrogate(unicode_t u) +{ + return ((u - PLANE_SIZE) & SURROGATE_BITS) | SURROGATE_PAIR | + SURROGATE_LOW; +} + +static int __exfat_utf16_to_nls(struct super_block *sb, + struct exfat_uni_name *p_uniname, unsigned char *p_cstring, + int buflen) +{ + int i, j, len, out_len = 0; + unsigned char buf[MAX_CHARSET_SIZE]; + const unsigned short *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + i = 0; + while (i < MAX_NAME_LENGTH && out_len < (buflen - 1)) { + if (*uniname == '\0') + break; + if ((*uniname & SURROGATE_MASK) != SURROGATE_PAIR) { + len = exfat_convert_ucs2_to_char(nls, *uniname, buf, + NULL); + } else { + /* Process UTF-16 surrogate pair as one character */ + if (!(*uniname & SURROGATE_LOW) && + i+1 < MAX_NAME_LENGTH && + (*(uniname+1) & SURROGATE_MASK) == SURROGATE_PAIR && + (*(uniname+1) & SURROGATE_LOW)) { + uniname++; + i++; + } + + /* + * UTF-16 surrogate pair encodes code points above + * U+FFFF. Code points above U+FFFF are not supported + * by kernel NLS framework therefore use replacement + * character + */ + len = 1; + buf[0] = '_'; + } + + if (out_len + len >= buflen) + len = buflen - 1 - out_len; + out_len += len; + + if (len > 1) { + for (j = 0; j < len; j++) + *p_cstring++ = buf[j]; + } else { /* len == 1 */ + *p_cstring++ = *buf; + } + + uniname++; + i++; + } + + *p_cstring = '\0'; + return out_len; +} + +static int exfat_nls_to_ucs2(struct super_block *sb, + const unsigned char *p_cstring, const int len, + struct exfat_uni_name *p_uniname, int *p_lossy) +{ + int i = 0, unilen = 0, lossy = NLS_NAME_NO_LOSSY; + unsigned short upname[MAX_NAME_LENGTH + 1]; + unsigned short *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + WARN_ON(!len); + + while (unilen < MAX_NAME_LENGTH && i < len) { + i += exfat_convert_char_to_ucs2(nls, p_cstring + i, len - i, + uniname, &lossy); + + if (*uniname < 0x0020 || + exfat_wstrchr(bad_uni_chars, *uniname)) + lossy |= NLS_NAME_LOSSY; + + upname[unilen] = exfat_toupper(sb, *uniname); + uniname++; + unilen++; + } + + if (p_cstring[i] != '\0') + lossy |= NLS_NAME_OVERLEN; + + *uniname = '\0'; + p_uniname->name_len = unilen; + p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, + CS_DEFAULT); + + if (p_lossy) + *p_lossy = lossy; + return unilen; +} + +int exfat_utf16_to_nls(struct super_block *sb, struct exfat_uni_name *uniname, + unsigned char *p_cstring, int buflen) +{ + if (EXFAT_SB(sb)->options.utf8) + return exfat_utf16_to_utf8(sb, uniname, p_cstring, + buflen); + return __exfat_utf16_to_nls(sb, uniname, p_cstring, buflen); +} + +int exfat_nls_to_utf16(struct super_block *sb, const unsigned char *p_cstring, + const int len, struct exfat_uni_name *uniname, int *p_lossy) +{ + if (EXFAT_SB(sb)->options.utf8) + return exfat_utf8_to_utf16(sb, p_cstring, len, + uniname, p_lossy); + return exfat_nls_to_ucs2(sb, p_cstring, len, uniname, p_lossy); +} + +static int exfat_load_upcase_table(struct super_block *sb, + sector_t sector, unsigned long long num_sectors, + unsigned int utbl_checksum) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned int sect_size = sb->s_blocksize; + unsigned int i, index = 0, checksum = 0; + int ret; + unsigned char skip = false; + unsigned short *upcase_table; + + upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); + if (!upcase_table) + return -ENOMEM; + + sbi->vol_utbl = upcase_table; + num_sectors += sector; + + while (sector < num_sectors) { + struct buffer_head *bh; + + bh = sb_bread(sb, sector); + if (!bh) { + exfat_msg(sb, KERN_ERR, + "failed to read sector(0x%llx)\n", + (unsigned long long)sector); + ret = -EIO; + goto free_table; + } + sector++; + for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) { + unsigned short uni = get_unaligned_le16(bh->b_data + i); + + checksum = ((checksum & 1) ? 0x80000000 : 0) + + (checksum >> 1) + + *(((unsigned char *)bh->b_data) + i); + checksum = ((checksum & 1) ? 0x80000000 : 0) + + (checksum >> 1) + + *(((unsigned char *)bh->b_data) + (i + 1)); + + if (skip) { + index += uni; + skip = false; + } else if (uni == index) { + index++; + } else if (uni == 0xFFFF) { + skip = true; + } else { /* uni != index , uni != 0xFFFF */ + upcase_table[index] = uni; + index++; + } + } + brelse(bh); + } + + if (index >= 0xFFFF && utbl_checksum == checksum) + return 0; + + exfat_msg(sb, KERN_ERR, + "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)\n", + index, checksum, utbl_checksum); + ret = -EINVAL; +free_table: + exfat_free_upcase_table(sbi); + return ret; +} + +static int exfat_load_default_upcase_table(struct super_block *sb) +{ + int i, ret = -EIO; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + unsigned char skip = false; + unsigned short uni = 0, *upcase_table; + unsigned int index = 0; + + upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); + if (!upcase_table) + return -ENOMEM; + + sbi->vol_utbl = upcase_table; + + for (i = 0; index <= 0xFFFF && i < EXFAT_NUM_UPCASE; i++) { + uni = uni_def_upcase[i]; + if (skip) { + index += uni; + skip = false; + } else if (uni == index) { + index++; + } else if (uni == 0xFFFF) { + skip = true; + } else { + upcase_table[index] = uni; + index++; + } + } + + if (index >= 0xFFFF) + return 0; + + /* FATAL error: default upcase table has error */ + exfat_free_upcase_table(sbi); + return ret; +} + +int exfat_create_upcase_table(struct super_block *sb) +{ + int i, ret; + unsigned int tbl_clu, type; + sector_t sector; + unsigned long long tbl_size, num_sectors; + unsigned char blksize_bits = sb->s_blocksize_bits; + struct exfat_chain clu; + struct exfat_dentry *ep; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + clu.dir = sbi->root_dir; + clu.flags = ALLOC_FAT_CHAIN; + + while (clu.dir != EXFAT_EOF_CLUSTER) { + for (i = 0; i < sbi->dentries_per_clu; i++) { + ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); + if (!ep) + return -EIO; + + type = exfat_get_entry_type(ep); + if (type == TYPE_UNUSED) { + brelse(bh); + break; + } + + if (type != TYPE_UPCASE) { + brelse(bh); + continue; + } + + tbl_clu = le32_to_cpu(ep->dentry.upcase.start_clu); + tbl_size = le64_to_cpu(ep->dentry.upcase.size); + + sector = exfat_cluster_to_sector(sbi, tbl_clu); + num_sectors = ((tbl_size - 1) >> blksize_bits) + 1; + ret = exfat_load_upcase_table(sb, sector, num_sectors, + le32_to_cpu(ep->dentry.upcase.checksum)); + + brelse(bh); + if (ret && ret != -EIO) + goto load_default; + + /* load successfully */ + return ret; + } + + if (exfat_get_next_cluster(sb, &(clu.dir))) + return -EIO; + } + +load_default: + /* load default upcase table */ + return exfat_load_default_upcase_table(sb); +} + +void exfat_free_upcase_table(struct exfat_sb_info *sbi) +{ + kfree(sbi->vol_utbl); +} From b9d1e2e6265f5dc25e9f5dbfbde3e53d8a4958ac Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:42 +0900 Subject: [PATCH 188/809] exfat: add Kconfig and Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the Kconfig and Makefile for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/Kconfig | 3 ++- fs/Makefile | 1 + fs/exfat/Kconfig | 21 +++++++++++++++++++++ fs/exfat/Makefile | 8 ++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 fs/exfat/Kconfig create mode 100644 fs/exfat/Makefile diff --git a/fs/Kconfig b/fs/Kconfig index 708ba336e689..f08fbbfafd9a 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -140,9 +140,10 @@ endmenu endif # BLOCK if BLOCK -menu "DOS/FAT/NT Filesystems" +menu "DOS/FAT/EXFAT/NT Filesystems" source "fs/fat/Kconfig" +source "fs/exfat/Kconfig" source "fs/ntfs/Kconfig" endmenu diff --git a/fs/Makefile b/fs/Makefile index 505e51166973..2ce5112b02c8 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_MINIX_FS) += minix/ obj-$(CONFIG_FAT_FS) += fat/ +obj-$(CONFIG_EXFAT_FS) += exfat/ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig new file mode 100644 index 000000000000..2d3636dc5b8c --- /dev/null +++ b/fs/exfat/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config EXFAT_FS + tristate "exFAT filesystem support" + select NLS + help + This allows you to mount devices formatted with the exFAT file system. + exFAT is typically used on SD-Cards or USB sticks. + + To compile this as a module, choose M here: the module will be called + exfat. + +config EXFAT_DEFAULT_IOCHARSET + string "Default iocharset for exFAT" + default "utf8" + depends on EXFAT_FS + help + Set this to the default input/output character set to use for + converting between the encoding is used for user visible filename and + UTF-16 character that exfat filesystem use, and can be overridden with + the "iocharset" mount option for exFAT filesystems. diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile new file mode 100644 index 000000000000..ed51926a4971 --- /dev/null +++ b/fs/exfat/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the linux exFAT filesystem support. +# +obj-$(CONFIG_EXFAT_FS) += exfat.o + +exfat-y := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o \ + file.o balloc.o From 88ab55f16aae90e2e974eb67cc2380edb92b0661 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:43 +0900 Subject: [PATCH 189/809] MAINTAINERS: add exfat filesystem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add myself and Sungjong Seo as exfat maintainer. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 38fe2f3f7b6f..27d912bc5ae2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6305,6 +6305,13 @@ F: include/trace/events/mdio.h F: include/uapi/linux/mdio.h F: include/uapi/linux/mii.h +EXFAT FILE SYSTEM +M: Namjae Jeon +M: Sungjong Seo +L: linux-fsdevel@vger.kernel.org +S: Maintained +F: fs/exfat/ + EXFAT FILE SYSTEM M: Valdis Kletnieks L: linux-fsdevel@vger.kernel.org From 1a3c0509ce83ce48104907207423c6eb929caa59 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 2 Mar 2020 15:21:44 +0900 Subject: [PATCH 190/809] staging: exfat: make staging/exfat and fs/exfat mutually exclusive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make staging/exfat and fs/exfat mutually exclusive to select the one between two same filesystem. Suggested-by: Amir Goldstein Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo Acked-by: Greg Kroah-Hartman Reviewed-by: Pali Rohár Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- drivers/staging/exfat/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/exfat/Kconfig b/drivers/staging/exfat/Kconfig index 292a19dfcaf5..9a0fccec65d9 100644 --- a/drivers/staging/exfat/Kconfig +++ b/drivers/staging/exfat/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config STAGING_EXFAT_FS tristate "exFAT fs support" - depends on BLOCK + depends on BLOCK && !EXFAT_FS select NLS help This adds support for the exFAT file system. From 9acd0d53800c55c6e2186e29b6433daf24617451 Mon Sep 17 00:00:00 2001 From: Valdis Kletnieks Date: Mon, 2 Mar 2020 15:21:45 +0900 Subject: [PATCH 191/809] exfat: update file system parameter handling Al Viro recently reworked the way file system parameters are handled Update super.c to work with it in linux-next 20200203. Signed-off-by: Valdis Kletnieks Reviewed-by: Christoph Hellwig Acked-by: Namjae Jeon Signed-off-by: Al Viro --- fs/exfat/super.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/fs/exfat/super.c b/fs/exfat/super.c index f06e0b53e393..16ed202ef527 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -214,7 +214,14 @@ enum { Opt_time_offset, }; -static const struct fs_parameter_spec exfat_param_specs[] = { +static const struct constant_table exfat_param_enums[] = { + { "continue", EXFAT_ERRORS_CONT }, + { "panic", EXFAT_ERRORS_PANIC }, + { "remount-ro", EXFAT_ERRORS_RO }, + {} +}; + +static const struct fs_parameter_spec exfat_parameters[] = { fsparam_u32("uid", Opt_uid), fsparam_u32("gid", Opt_gid), fsparam_u32oct("umask", Opt_umask), @@ -222,25 +229,12 @@ static const struct fs_parameter_spec exfat_param_specs[] = { fsparam_u32oct("fmask", Opt_fmask), fsparam_u32oct("allow_utime", Opt_allow_utime), fsparam_string("iocharset", Opt_charset), - fsparam_enum("errors", Opt_errors), + fsparam_enum("errors", Opt_errors, exfat_param_enums), fsparam_flag("discard", Opt_discard), fsparam_s32("time_offset", Opt_time_offset), {} }; -static const struct fs_parameter_enum exfat_param_enums[] = { - { Opt_errors, "continue", EXFAT_ERRORS_CONT }, - { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, - { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, - {} -}; - -static const struct fs_parameter_description exfat_parameters = { - .name = "exfat", - .specs = exfat_param_specs, - .enums = exfat_param_enums, -}; - static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct exfat_sb_info *sbi = fc->s_fs_info; @@ -248,7 +242,7 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) struct fs_parse_result result; int opt; - opt = fs_parse(fc, &exfat_parameters, param, &result); + opt = fs_parse(fc, exfat_parameters, param, &result); if (opt < 0) return opt; @@ -665,7 +659,7 @@ static struct file_system_type exfat_fs_type = { .owner = THIS_MODULE, .name = "exfat", .init_fs_context = exfat_init_fs_context, - .parameters = &exfat_parameters, + .parameters = exfat_parameters, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; From 28936b62e71e41600bab319f262ea9f9b1027629 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Fri, 21 Feb 2020 23:32:58 -0500 Subject: [PATCH 192/809] ext4: fix a data race at inode->i_blocks inode->i_blocks could be accessed concurrently as noticed by KCSAN, BUG: KCSAN: data-race in ext4_do_update_inode [ext4] / inode_add_bytes write to 0xffff9a00d4b982d0 of 8 bytes by task 22100 on cpu 118: inode_add_bytes+0x65/0xf0 __inode_add_bytes at fs/stat.c:689 (inlined by) inode_add_bytes at fs/stat.c:702 ext4_mb_new_blocks+0x418/0xca0 [ext4] ext4_ext_map_blocks+0x1a6b/0x27b0 [ext4] ext4_map_blocks+0x1a9/0x950 [ext4] _ext4_get_block+0xfc/0x270 [ext4] ext4_get_block_unwritten+0x33/0x50 [ext4] __block_write_begin_int+0x22e/0xae0 __block_write_begin+0x39/0x50 ext4_write_begin+0x388/0xb50 [ext4] ext4_da_write_begin+0x35f/0x8f0 [ext4] generic_perform_write+0x15d/0x290 ext4_buffered_write_iter+0x11f/0x210 [ext4] ext4_file_write_iter+0xce/0x9e0 [ext4] new_sync_write+0x29c/0x3b0 __vfs_write+0x92/0xa0 vfs_write+0x103/0x260 ksys_write+0x9d/0x130 __x64_sys_write+0x4c/0x60 do_syscall_64+0x91/0xb05 entry_SYSCALL_64_after_hwframe+0x49/0xbe read to 0xffff9a00d4b982d0 of 8 bytes by task 8 on cpu 65: ext4_do_update_inode+0x4a0/0xf60 [ext4] ext4_inode_blocks_set at fs/ext4/inode.c:4815 ext4_mark_iloc_dirty+0xaf/0x160 [ext4] ext4_mark_inode_dirty+0x129/0x3e0 [ext4] ext4_convert_unwritten_extents+0x253/0x2d0 [ext4] ext4_convert_unwritten_io_end_vec+0xc5/0x150 [ext4] ext4_end_io_rsv_work+0x22c/0x350 [ext4] process_one_work+0x54f/0xb90 worker_thread+0x80/0x5f0 kthread+0x1cd/0x1f0 ret_from_fork+0x27/0x50 4 locks held by kworker/u256:0/8: #0: ffff9a025abc4328 ((wq_completion)ext4-rsv-conversion){+.+.}, at: process_one_work+0x443/0xb90 #1: ffffab5a862dbe20 ((work_completion)(&ei->i_rsv_conversion_work)){+.+.}, at: process_one_work+0x443/0xb90 #2: ffff9a025a9d0f58 (jbd2_handle){++++}, at: start_this_handle+0x1c1/0x9d0 [jbd2] #3: ffff9a00d4b985d8 (&(&ei->i_raw_lock)->rlock){+.+.}, at: ext4_do_update_inode+0xaa/0xf60 [ext4] irq event stamp: 3009267 hardirqs last enabled at (3009267): [] __find_get_block+0x107/0x790 hardirqs last disabled at (3009266): [] __find_get_block+0x49/0x790 softirqs last enabled at (3009230): [] __do_softirq+0x34c/0x57c softirqs last disabled at (3009223): [] irq_exit+0xa2/0xc0 Reported by Kernel Concurrency Sanitizer on: CPU: 65 PID: 8 Comm: kworker/u256:0 Tainted: G L 5.6.0-rc2-next-20200221+ #7 Hardware name: HPE ProLiant DL385 Gen10/ProLiant DL385 Gen10, BIOS A40 07/10/2019 Workqueue: ext4-rsv-conversion ext4_end_io_rsv_work [ext4] The plain read is outside of inode->i_lock critical section which results in a data race. Fix it by adding READ_ONCE() there. Link: https://lore.kernel.org/r/20200222043258.2279-1-cai@lca.pw Signed-off-by: Qian Cai Signed-off-by: Theodore Ts'o Cc: stable@kernel.org --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 416aec6d6c65..fa70ae21d032 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4810,7 +4810,7 @@ static int ext4_inode_blocks_set(handle_t *handle, struct ext4_inode_info *ei) { struct inode *inode = &(ei->vfs_inode); - u64 i_blocks = inode->i_blocks; + u64 i_blocks = READ_ONCE(inode->i_blocks); struct super_block *sb = inode->i_sb; if (i_blocks <= ~0U) { From dce8e237100f60c28cc66effb526ba65a01d8cb3 Mon Sep 17 00:00:00 2001 From: Qiujun Huang Date: Mon, 24 Feb 2020 23:02:46 +0800 Subject: [PATCH 193/809] ext4: fix a data race at inode->i_disksize KCSAN find inode->i_disksize could be accessed concurrently. BUG: KCSAN: data-race in ext4_mark_iloc_dirty / ext4_write_end write (marked) to 0xffff8b8932f40090 of 8 bytes by task 66792 on cpu 0: ext4_write_end+0x53f/0x5b0 ext4_da_write_end+0x237/0x510 generic_perform_write+0x1c4/0x2a0 ext4_buffered_write_iter+0x13a/0x210 ext4_file_write_iter+0xe2/0x9b0 new_sync_write+0x29c/0x3a0 __vfs_write+0x92/0xa0 vfs_write+0xfc/0x2a0 ksys_write+0xe8/0x140 __x64_sys_write+0x4c/0x60 do_syscall_64+0x8a/0x2a0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 read to 0xffff8b8932f40090 of 8 bytes by task 14414 on cpu 1: ext4_mark_iloc_dirty+0x716/0x1190 ext4_mark_inode_dirty+0xc9/0x360 ext4_convert_unwritten_extents+0x1bc/0x2a0 ext4_convert_unwritten_io_end_vec+0xc5/0x150 ext4_put_io_end+0x82/0x130 ext4_writepages+0xae7/0x16f0 do_writepages+0x64/0x120 __writeback_single_inode+0x7d/0x650 writeback_sb_inodes+0x3a4/0x860 __writeback_inodes_wb+0xc4/0x150 wb_writeback+0x43f/0x510 wb_workfn+0x3b2/0x8a0 process_one_work+0x39b/0x7e0 worker_thread+0x88/0x650 kthread+0x1d4/0x1f0 ret_from_fork+0x35/0x40 The plain read is outside of inode->i_data_sem critical section which results in a data race. Fix it by adding READ_ONCE(). Signed-off-by: Qiujun Huang Link: https://lore.kernel.org/r/1582556566-3909-1-git-send-email-hqjagain@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index fa70ae21d032..27d009bf183f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4980,7 +4980,7 @@ static int ext4_do_update_inode(handle_t *handle, raw_inode->i_file_acl_high = cpu_to_le16(ei->i_file_acl >> 32); raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl); - if (ei->i_disksize != ext4_isize(inode->i_sb, raw_inode)) { + if (READ_ONCE(ei->i_disksize) != ext4_isize(inode->i_sb, raw_inode)) { ext4_isize_set(raw_inode, ei->i_disksize); need_datasync = 1; } From 014b020475d4b9670d3cff11b751a7c20208f78b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 25 Feb 2020 12:44:06 +0100 Subject: [PATCH 194/809] s390/mm: cleanup phys_to_pfn() and friends Make page, frame, virtual and physical address conversion macros more expressive by avoiding redundant definitions and defining new macros using existing ones. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/page.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 85e944f04c70..2e53b27f4f1a 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -161,20 +161,20 @@ static inline int devmem_is_allowed(unsigned long pfn) #define __pa(x) ((unsigned long)(x)) #define __va(x) ((void *)(unsigned long)(x)) -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) +#define phys_to_pfn(phys) ((phys) >> PAGE_SHIFT) +#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) + +#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) +#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) + +#define pfn_to_virt(pfn) __va(pfn_to_phys(pfn)) +#define virt_to_pfn(kaddr) (phys_to_pfn(__pa(kaddr))) #define pfn_to_kaddr(pfn) pfn_to_virt(pfn) #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) #define page_to_virt(page) pfn_to_virt(page_to_pfn(page)) -#define phys_to_pfn(kaddr) ((kaddr) >> PAGE_SHIFT) -#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) - -#define phys_to_page(kaddr) pfn_to_page(phys_to_pfn(kaddr)) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - -#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) +#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) From ad451abee4ba787508c2a344aae4c9316b96cab9 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 24 Feb 2020 09:53:47 +0100 Subject: [PATCH 195/809] s390/qdio: export SSQD via debugfs While we print out various SSQD fields at initialization time, having raw & full access to the current SSQD can help with debugging. Signed-off-by: Julian Wiedmann Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio_debug.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index bf8d82503870..8544faddf80c 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -190,6 +190,23 @@ static int qstat_show(struct seq_file *m, void *v) DEFINE_SHOW_ATTRIBUTE(qstat); +static int ssqd_show(struct seq_file *m, void *v) +{ + struct ccw_device *cdev = m->private; + struct qdio_ssqd_desc ssqd; + int rc; + + rc = qdio_get_ssqd_desc(cdev, &ssqd); + if (rc) + return rc; + + seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd), + false); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(ssqd); + static char *qperf_names[] = { "Assumed adapter interrupts", "QDIO interrupts", @@ -303,6 +320,8 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) debugfs_root); debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); + debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, cdev, + &ssqd_fops); for_each_input_queue(irq_ptr, q, i) setup_debugfs_entry(irq_ptr->debugfs_dev, q); From d894992502474a6e84644012deb14a0280acbf96 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 3 Mar 2020 20:29:56 +0100 Subject: [PATCH 196/809] clk: rockchip: fix mmc get phase If the mmc clock has no rate, it can be assumed to be constant. In such case, there is no measurable phase shift. Just return 0 in this case instead of returning an error. Fixes: 2760878662a2 ("clk: Bail out when calculating phase fails during clk registration") Tested-by: Markus Reichl Signed-off-by: Jerome Brunet Link: https://lkml.kernel.org/r/20200303192956.64410-1-jbrunet@baylibre.com Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-mmc-phase.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 4abe7ff31f53..975454a3dd72 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -51,9 +51,9 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) u16 degrees; u32 delay_num = 0; - /* See the comment for rockchip_mmc_set_phase below */ + /* Constant signal, no measurable phase shift */ if (!rate) - return -EINVAL; + return 0; raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); From 241eaabc3c315cdfea505725a43de848f498527f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 6 Mar 2020 10:34:10 +0800 Subject: [PATCH 197/809] power: supply: Allow charger manager can be built as a module Allow charger manager can be built as a module like other charger drivers. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 2 +- include/linux/power/charger-manager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 9a5591ab90d0..195bc0462d3e 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -480,7 +480,7 @@ config CHARGER_GPIO called gpio-charger. config CHARGER_MANAGER - bool "Battery charger manager for multiple chargers" + tristate "Battery charger manager for multiple chargers" depends on REGULATOR select EXTCON help diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index ad19e68e1fc3..ae94dcebd936 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h @@ -248,7 +248,7 @@ struct charger_manager { u64 charging_end_time; }; -#ifdef CONFIG_CHARGER_MANAGER +#if IS_ENABLED(CONFIG_CHARGER_MANAGER) extern void cm_notify_event(struct power_supply *psy, enum cm_event_types type, char *msg); #else From ddb74e985f2d3db1ef5688121c8b1961f0c9d80d Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Wed, 26 Feb 2020 23:22:23 +0530 Subject: [PATCH 198/809] power: supply: ab8500_charger: Fix typos in commit messages Trivial fix to spelling mistake in commit messages. Signed-off-by: Ashish Chavan Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 35 +++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index f69550d64f09..9469fe182d02 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -404,7 +404,7 @@ disable_otp: } /** - * ab8500_power_supply_changed - a wrapper with local extentions for + * ab8500_power_supply_changed - a wrapper with local extensions for * power_supply_changed * @di: pointer to the ab8500_charger structure * @psy: pointer to power_supply_that have changed. @@ -683,7 +683,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, /* * Platform only supports USB 2.0. * This means that charging current from USB source - * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_* + * is maximum 500 mA. Every occurrence of USB_STAT_*_HOST_* * should set USB_CH_IP_CUR_LVL_0P5. */ @@ -1379,13 +1379,13 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts - * will be triggered everytime we enable the VDD ADC supply. + * will be triggered every time we enable the VDD ADC supply. * This will turn off charging for a short while. * It can be avoided by having the supply on when * there is a charger enabled. Normally the VDD ADC supply - * is enabled everytime a GPADC conversion is triggered. We will - * force it to be enabled from this driver to have - * the GPADC module independant of the AB8500 chargers + * is enabled every time a GPADC conversion is triggered. + * We will force it to be enabled from this driver to have + * the GPADC module independent of the AB8500 chargers */ if (!di->vddadc_en_ac) { ret = regulator_enable(di->regu); @@ -1455,7 +1455,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, if (is_ab8500_1p1_or_earlier(di->parent)) { /* * For ABB revision 1.0 and 1.1 there is a bug in the - * watchdog logic. That means we have to continously + * watchdog logic. That means we have to continuously * kick the charger watchdog even when no charger is * connected. This is only valid once the AC charger * has been enabled. This is a bug that is not handled @@ -1552,13 +1552,13 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts - * will be triggered everytime we enable the VDD ADC supply. + * will be triggered every time we enable the VDD ADC supply. * This will turn off charging for a short while. * It can be avoided by having the supply on when * there is a charger enabled. Normally the VDD ADC supply - * is enabled everytime a GPADC conversion is triggered. We will - * force it to be enabled from this driver to have - * the GPADC module independant of the AB8500 chargers + * is enabled every time a GPADC conversion is triggered. + * We will force it to be enabled from this driver to have + * the GPADC module independent of the AB8500 chargers */ if (!di->vddadc_en_usb) { ret = regulator_enable(di->regu); @@ -1582,7 +1582,10 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return -ENXIO; } - /* ChVoltLevel: max voltage upto which battery can be charged */ + /* + * ChVoltLevel: max voltage up to which battery can be + * charged + */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_VOLT_LVL_REG, (u8) volt_index); if (ret) { @@ -2014,7 +2017,7 @@ static void ab8500_charger_check_hw_failure_work(struct work_struct *work) * Work queue function for kicking the charger watchdog. * * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the @@ -2262,7 +2265,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) * Some chargers that breaks the USB spec is * identified as invalid by AB8500 and it refuse * to start the charging process. but by jumping - * thru a few hoops it can be forced to start. + * through a few hoops it can be forced to start. */ if (is_ab8500(di->parent)) ret = abx500_get_register_interruptible(di->dev, AB8500_USB, @@ -3214,7 +3217,7 @@ static int ab8500_charger_resume(struct platform_device *pdev) /* * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the @@ -3483,7 +3486,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) /* * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the From e42fe5b29ac07210297e75f36deefe54edbdbf80 Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Tue, 25 Feb 2020 16:59:41 -0600 Subject: [PATCH 199/809] power: supply: axp288_fuel_gauge: Broaden vendor check for Intel Compute Sticks. The Intel Compute Stick `STK1A32SC` can have a system vendor of "Intel(R) Client Systems". Broaden the Intel Compute Stick DMI checks so that they match "Intel Corporation" as well as "Intel(R) Client Systems". This fixes an issue where the STK1A32SC compute sticks were still exposing a battery with the existing blacklist entry. Signed-off-by: Jeffery Miller Reviewed-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index e1bc4e6e6f30..f40fa0e63b6e 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -706,14 +706,14 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { { /* Intel Cherry Trail Compute Stick, Windows version */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_SYS_VENDOR, "Intel"), DMI_MATCH(DMI_PRODUCT_NAME, "STK1AW32SC"), }, }, { /* Intel Cherry Trail Compute Stick, version without an OS */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_SYS_VENDOR, "Intel"), DMI_MATCH(DMI_PRODUCT_NAME, "STK1A32SC"), }, }, From 9c80662a74cd2a5d1113f5c69d027face963a556 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 23 Feb 2020 16:32:08 +0100 Subject: [PATCH 200/809] power: supply: axp288_charger: Add special handling for HP Pavilion x2 10 Some HP Pavilion x2 10 models use an AXP288 for charging and fuel-gauge. We use a native power_supply / PMIC driver in this case, because on most models with an AXP288 the ACPI AC / Battery code is either completely missing or relies on custom / proprietary ACPI OpRegions which Linux does not implement. The native drivers mostly work fine, but there are 2 problems: 1. These model uses a Type-C connector for charging which the AXP288 does not support. As long as a Type-A charger (which uses the USB data pins for charger type detection) is used everything is fine. But if a Type-C charger is used (such as the charger shipped with the device) then the charger is not recognized. So we end up slowly discharging the device even though a charger is connected, because we are limiting the current from the charger to 500mA. To make things worse this happens with the device's official charger. Looking at the ACPI tables HP has "solved" the problem of the AXP288 not being able to recognize Type-C chargers by simply always programming the input-current-limit at 3000mA and relying on a Vhold setting of 4.7V (normally 4.4V) to limit the current intake if the charger cannot handle this. 2. If no charger is connected when the machine boots then it boots with the vbus-path disabled. On other devices this is done when a 5V boost converter is active to avoid the PMIC trying to charge from the 5V boost output. This is done when an OTG host cable is inserted and the ID pin on the micro-B receptacle is pulled low, the ID pin has an ACPI event handler associated with it which re-enables the vbus-path when the ID pin is pulled high when the OTG cable is removed. The Type-C connector has no ID pin, there is no ID pin handler and there appears to be no 5V boost converter, so we end up not charging because the vbus-path is disabled, until we unplug the charger which automatically clears the vbus-path disable bit and then on the second plug-in of the adapter we start charging. The HP Pavilion x2 10 models with an AXP288 do have mostly working ACPI AC / Battery code which does not rely on custom / proprietary ACPI OpRegions. So one possible solution would be to blacklist the AXP288 native power_supply drivers and add the HP Pavilion x2 10 with AXP288 DMI ids to the list of devices which should use the ACPI AC / Battery code even though they have an AXP288 PMIC. This would require changes to 4 files: drivers/acpi/ac.c, drivers/power/supply/axp288_charger.c, drivers/acpi/battery.c and drivers/power/supply/axp288_fuel_gauge.c. Beside needing adding the same DMI matches to 4 different files, this approach also triggers problem 2. from above, but then when suspended, during suspend the machine will not wakeup because the vbus path is disabled by the AML code when not charging, so the Vbus low-to-high IRQ is not triggered, the CPU never wakes up and the device does not charge even though the user likely things it is charging, esp. since the charge status LED is directly coupled to an adapter being plugged in and does not reflect actual charging. This could be worked by enabling vbus-path explicitly from say the axp288_charger driver's suspend handler. So neither situation is ideal, in both cased we need to explicitly enable the vbus-path to work around different variants of problem 2 above, this requires a quirk in the axp288_charger code. If we go the route of using the ACPI AC / Battery drivers then we need modifications to 3 other drivers; and we need to partially disable the axp288_charger code, while at the same time keeping it around to enable vbus-path on suspend. OTOH we can copy the hardcoding of 3A input-current-limit (we never touch Vhold, so that would stay at 4.7V) to the axp288_charger code, which needs changes regardless, then we concentrate all special handling of this interesting device model in the axp288_charger code. That is what this commit does. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1791098 Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_charger.c | 57 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 1bbba6bba673..cf4c67b2d235 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -21,6 +21,7 @@ #include #include #include +#include #define PS_STAT_VBUS_TRIGGER BIT(0) #define PS_STAT_BAT_CHRG_DIR BIT(2) @@ -545,6 +546,49 @@ out: return IRQ_HANDLED; } +/* + * The HP Pavilion x2 10 series comes in a number of variants: + * Bay Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "815D" + * Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E" + * Cherry Trail SoC + TI PMIC, DMI_BOARD_NAME: "827C" or "82F4" + * + * The variants with the AXP288 PMIC are all kinds of special: + * + * 1. All variants use a Type-C connector which the AXP288 does not support, so + * when using a Type-C charger it is not recognized. Unlike most AXP288 devices, + * this model actually has mostly working ACPI AC / Battery code, the ACPI code + * "solves" this by simply setting the input_current_limit to 3A. + * There are still some issues with the ACPI code, so we use this native driver, + * and to solve the charging not working (500mA is not enough) issue we hardcode + * the 3A input_current_limit like the ACPI code does. + * + * 2. If no charger is connected the machine boots with the vbus-path disabled. + * Normally this is done when a 5V boost converter is active to avoid the PMIC + * trying to charge from the 5V boost converter's output. This is done when + * an OTG host cable is inserted and the ID pin on the micro-B receptacle is + * pulled low and the ID pin has an ACPI event handler associated with it + * which re-enables the vbus-path when the ID pin is pulled high when the + * OTG host cable is removed. The Type-C connector has no ID pin, there is + * no ID pin handler and there appears to be no 5V boost converter, so we + * end up not charging because the vbus-path is disabled, until we unplug + * the charger which automatically clears the vbus-path disable bit and then + * on the second plug-in of the adapter we start charging. To solve the not + * charging on first charger plugin we unconditionally enable the vbus-path at + * probe on this model, which is safe since there is no 5V boost converter. + */ +static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = { + { + /* + * Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry + * Trail model has "HP", so we only match on product_name. + */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + }, + }, + {} /* Terminating entry */ +}; + static void axp288_charger_extcon_evt_worker(struct work_struct *work) { struct axp288_chrg_info *info = @@ -568,7 +612,11 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) } /* Determine cable/charger type */ - if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { + if (dmi_check_system(axp288_hp_x2_dmi_ids)) { + /* See comment above axp288_hp_x2_dmi_ids declaration */ + dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n"); + current_limit = 3000000; + } else if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n"); current_limit = 500000; } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) { @@ -685,6 +733,13 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) return ret; } + if (dmi_check_system(axp288_hp_x2_dmi_ids)) { + /* See comment above axp288_hp_x2_dmi_ids declaration */ + ret = axp288_charger_vbus_path_select(info, true); + if (ret < 0) + return ret; + } + /* Read current charge voltage and current limit */ ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val); if (ret < 0) { From 12879bda3c2a974b7e4fe199a9c21f0c5f6bca04 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Wed, 26 Feb 2020 10:23:26 +0800 Subject: [PATCH 201/809] csky: Fixup init_fpu compile warning with __init WARNING: vmlinux.o(.text+0x2366): Section mismatch in reference from the function csky_start_secondary() to the function .init.text:init_fpu() The function csky_start_secondary() references the function __init init_fpu(). This is often because csky_start_secondary lacks a __init annotation or the annotation of init_fpu is wrong. Reported-by: Lu Chongzhi Signed-off-by: Guo Ren --- arch/csky/abiv2/fpu.c | 5 ----- arch/csky/abiv2/inc/abi/fpu.h | 3 ++- arch/csky/kernel/smp.c | 3 +++ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/csky/abiv2/fpu.c b/arch/csky/abiv2/fpu.c index 86d187d4e5af..5acc5c2e544e 100644 --- a/arch/csky/abiv2/fpu.c +++ b/arch/csky/abiv2/fpu.c @@ -10,11 +10,6 @@ #define MTCR_DIST 0xC0006420 #define MFCR_DIST 0xC0006020 -void __init init_fpu(void) -{ - mtcr("cr<1, 2>", 0); -} - /* * fpu_libc_helper() is to help libc to excute: * - mfcr %a, cr<1, 2> diff --git a/arch/csky/abiv2/inc/abi/fpu.h b/arch/csky/abiv2/inc/abi/fpu.h index 22ca3cf2794a..09e2700a3693 100644 --- a/arch/csky/abiv2/inc/abi/fpu.h +++ b/arch/csky/abiv2/inc/abi/fpu.h @@ -9,7 +9,8 @@ int fpu_libc_helper(struct pt_regs *regs); void fpu_fpe(struct pt_regs *regs); -void __init init_fpu(void); + +static inline void init_fpu(void) { mtcr("cr<1, 2>", 0); } void save_to_user_fp(struct user_fp *user_fp); void restore_from_user_fp(struct user_fp *user_fp); diff --git a/arch/csky/kernel/smp.c b/arch/csky/kernel/smp.c index 0bb0954d5570..df2e2174dbd0 100644 --- a/arch/csky/kernel/smp.c +++ b/arch/csky/kernel/smp.c @@ -22,6 +22,9 @@ #include #include #include +#ifdef CONFIG_CPU_HAS_FPU +#include +#endif struct ipi_data_struct { unsigned long bits ____cacheline_aligned; From bfe47f358ad298a1efb9b8f8299a81541d90df87 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 17 Dec 2019 14:57:22 +0800 Subject: [PATCH 202/809] csky: Implement ptrace regs and stack API Needed for kprobes support. Copied and adapted from Patrick's patch, but it has been modified for csky's pt_regs. ref: https://lore.kernel.org/linux-riscv/1572919114-3886-2-git-send-email-vincent.chen@sifive.com/raw Signed-off-by: Guo Ren Cc: Patrick Staehlin --- arch/csky/Kconfig | 1 + arch/csky/include/asm/ptrace.h | 41 +++++++++++++ arch/csky/kernel/ptrace.c | 103 +++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 047427f71d83..2dfd3fb07db9 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -48,6 +48,7 @@ config CSKY select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_DMA_CONTIGUOUS + select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select MAY_HAVE_SPARSE_IRQ diff --git a/arch/csky/include/asm/ptrace.h b/arch/csky/include/asm/ptrace.h index d0aba7b32417..f16ca256e007 100644 --- a/arch/csky/include/asm/ptrace.h +++ b/arch/csky/include/asm/ptrace.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ @@ -22,6 +23,18 @@ #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + regs->pc = val; +} + +#if defined(__CSKYABIV2__) +#define MAX_REG_OFFSET offsetof(struct pt_regs, dcsr) +#else +#define MAX_REG_OFFSET offsetof(struct pt_regs, regs[9]) +#endif + static inline bool in_syscall(struct pt_regs const *regs) { return ((regs->sr >> 16) & 0xff) == VEC_TRAP0; @@ -37,5 +50,33 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->a0; } +/* Valid only for Kernel mode traps. */ +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->usp; +} + +extern int regs_query_register_offset(const char *name); +extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n); + +/* + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten + * @offset: offset of the register. + * + * regs_get_register returns the value of a register whose offset from @regs. + * The @offset is the offset of the register in struct pt_regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + #endif /* __ASSEMBLY__ */ #endif /* __ASM_CSKY_PTRACE_H */ diff --git a/arch/csky/kernel/ptrace.c b/arch/csky/kernel/ptrace.c index 313623a19ecb..21ac2608f205 100644 --- a/arch/csky/kernel/ptrace.c +++ b/arch/csky/kernel/ptrace.c @@ -193,6 +193,109 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_csky_view; } +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +static const struct pt_regs_offset regoffset_table[] = { + REG_OFFSET_NAME(tls), + REG_OFFSET_NAME(lr), + REG_OFFSET_NAME(pc), + REG_OFFSET_NAME(sr), + REG_OFFSET_NAME(usp), + REG_OFFSET_NAME(orig_a0), + REG_OFFSET_NAME(a0), + REG_OFFSET_NAME(a1), + REG_OFFSET_NAME(a2), + REG_OFFSET_NAME(a3), + REG_OFFSET_NAME(regs[0]), + REG_OFFSET_NAME(regs[1]), + REG_OFFSET_NAME(regs[2]), + REG_OFFSET_NAME(regs[3]), + REG_OFFSET_NAME(regs[4]), + REG_OFFSET_NAME(regs[5]), + REG_OFFSET_NAME(regs[6]), + REG_OFFSET_NAME(regs[7]), + REG_OFFSET_NAME(regs[8]), + REG_OFFSET_NAME(regs[9]), +#if defined(__CSKYABIV2__) + REG_OFFSET_NAME(exregs[0]), + REG_OFFSET_NAME(exregs[1]), + REG_OFFSET_NAME(exregs[2]), + REG_OFFSET_NAME(exregs[3]), + REG_OFFSET_NAME(exregs[4]), + REG_OFFSET_NAME(exregs[5]), + REG_OFFSET_NAME(exregs[6]), + REG_OFFSET_NAME(exregs[7]), + REG_OFFSET_NAME(exregs[8]), + REG_OFFSET_NAME(exregs[9]), + REG_OFFSET_NAME(exregs[10]), + REG_OFFSET_NAME(exregs[11]), + REG_OFFSET_NAME(exregs[12]), + REG_OFFSET_NAME(exregs[13]), + REG_OFFSET_NAME(exregs[14]), + REG_OFFSET_NAME(rhi), + REG_OFFSET_NAME(rlo), + REG_OFFSET_NAME(dcsr), +#endif + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) +{ + return (addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + void ptrace_disable(struct task_struct *child) { singlestep_disable(child); From 9866d141a0977ace974400bf1f793dfc163409ce Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 5 Nov 2019 09:58:33 +0800 Subject: [PATCH 203/809] csky: Add support for restartable sequence Copied and adapted from vincent's patch, but modified for csky. ref: https://lore.kernel.org/linux-riscv/1572919114-3886-3-git-send-email-vincent.chen@sifive.com/raw Add calls to rseq_signal_deliver(), rseq_handle_notify_resume() and rseq_syscall() to introduce RSEQ support. 1. Call the rseq_handle_notify_resume() function on return to userspace if TIF_NOTIFY_RESUME thread flag is set. 2. Call the rseq_signal_deliver() function to fixup on the pre-signal frame when a signal is delivered on top of a restartable sequence critical section. 3. Check that system calls are not invoked from within rseq critical sections by invoking rseq_signal() from ret_from_syscall(). With CONFIG_DEBUG_RSEQ, such behavior results in termination of the process with SIGSEGV. Signed-off-by: Guo Ren --- arch/csky/Kconfig | 1 + arch/csky/kernel/entry.S | 5 ++++- arch/csky/kernel/signal.c | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 2dfd3fb07db9..0e9b14367fa8 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -49,6 +49,7 @@ config CSKY select HAVE_PERF_USER_STACK_DUMP select HAVE_DMA_CONTIGUOUS select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RSEQ select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select MAY_HAVE_SPARSE_IRQ diff --git a/arch/csky/kernel/entry.S b/arch/csky/kernel/entry.S index 007706328000..0bde1d9fd277 100644 --- a/arch/csky/kernel/entry.S +++ b/arch/csky/kernel/entry.S @@ -128,7 +128,10 @@ tlbop_end 1 ENTRY(csky_systemcall) SAVE_ALL TRAP0_SIZE zero_fp - +#ifdef CONFIG_RSEQ_DEBUG + mov a0, sp + jbsr rseq_syscall +#endif psrset ee, ie lrw r11, __NR_syscalls diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c index 9b1b7c039ddf..3d6b728cbb72 100644 --- a/arch/csky/kernel/signal.c +++ b/arch/csky/kernel/signal.c @@ -175,6 +175,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) sigset_t *oldset = sigmask_to_save(); int ret; + rseq_signal_deliver(ksig, regs); + /* Are we from a system call? */ if (in_syscall(regs)) { /* Avoid additional syscall restarting via ret_from_exception */ @@ -258,5 +260,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + rseq_handle_notify_resume(NULL, regs); } } From 89a3927a775c0a7212e2e3c4e2d42cd48895bee0 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 18 Feb 2020 20:27:39 +0800 Subject: [PATCH 204/809] csky: Implement ftrace with regs This patch implements FTRACE_WITH_REGS for csky, which allows a traced function's arguments (and some other registers) to be captured into a struct pt_regs, allowing these to be inspected and/or modified. Signed-off-by: Guo Ren --- arch/csky/Kconfig | 1 + arch/csky/abiv2/inc/abi/entry.h | 60 +++++++++++++++++++++++++++++++++ arch/csky/abiv2/mcount.S | 48 ++++++++++++++++++++++++++ arch/csky/include/asm/ftrace.h | 2 ++ arch/csky/kernel/asm-offsets.c | 1 + arch/csky/kernel/ftrace.c | 11 ++++++ 6 files changed, 123 insertions(+) diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 0e9b14367fa8..6cf169a15794 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -38,6 +38,7 @@ config CSKY select HAVE_ARCH_AUDITSYSCALL select HAVE_COPY_THREAD_TLS select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD diff --git a/arch/csky/abiv2/inc/abi/entry.h b/arch/csky/abiv2/inc/abi/entry.h index 94a7a58765df..6a404393d0f4 100644 --- a/arch/csky/abiv2/inc/abi/entry.h +++ b/arch/csky/abiv2/inc/abi/entry.h @@ -100,6 +100,66 @@ rte .endm +.macro SAVE_REGS_FTRACE + subi sp, 152 + stw tls, (sp, 0) + stw lr, (sp, 4) + + mfcr lr, psr + stw lr, (sp, 12) + + addi lr, sp, 152 + stw lr, (sp, 16) + + stw a0, (sp, 20) + stw a0, (sp, 24) + stw a1, (sp, 28) + stw a2, (sp, 32) + stw a3, (sp, 36) + + addi sp, 40 + stm r4-r13, (sp) + + addi sp, 40 + stm r16-r30, (sp) +#ifdef CONFIG_CPU_HAS_HILO + mfhi lr + stw lr, (sp, 60) + mflo lr + stw lr, (sp, 64) + mfcr lr, cr14 + stw lr, (sp, 68) +#endif + subi sp, 80 +.endm + +.macro RESTORE_REGS_FTRACE + ldw tls, (sp, 0) + ldw a0, (sp, 16) + mtcr a0, ss0 + +#ifdef CONFIG_CPU_HAS_HILO + ldw a0, (sp, 140) + mthi a0 + ldw a0, (sp, 144) + mtlo a0 + ldw a0, (sp, 148) + mtcr a0, cr14 +#endif + + ldw a0, (sp, 24) + ldw a1, (sp, 28) + ldw a2, (sp, 32) + ldw a3, (sp, 36) + + addi sp, 40 + ldm r4-r13, (sp) + addi sp, 40 + ldm r16-r30, (sp) + addi sp, 72 + mfcr sp, ss0 +.endm + .macro SAVE_SWITCH_STACK subi sp, 64 stm r4-r11, (sp) diff --git a/arch/csky/abiv2/mcount.S b/arch/csky/abiv2/mcount.S index 326402e65f9e..9331c7ed5958 100644 --- a/arch/csky/abiv2/mcount.S +++ b/arch/csky/abiv2/mcount.S @@ -3,6 +3,8 @@ #include #include +#include +#include /* * csky-gcc with -pg will put the following asm after prologue: @@ -44,6 +46,22 @@ jmp t1 .endm +.macro mcount_enter_regs + subi sp, 8 + stw lr, (sp, 0) + stw r8, (sp, 4) + SAVE_REGS_FTRACE +.endm + +.macro mcount_exit_regs + RESTORE_REGS_FTRACE + ldw t1, (sp, 0) + ldw r8, (sp, 4) + ldw lr, (sp, 8) + addi sp, 12 + jmp t1 +.endm + .macro save_return_regs subi sp, 16 stw a0, (sp, 0) @@ -122,6 +140,8 @@ ENTRY(ftrace_caller) ldw a0, (sp, 16) subi a0, 4 ldw a1, (sp, 24) + lrw a2, function_trace_op + ldw a2, (a2, 0) nop GLOBAL(ftrace_call) @@ -157,3 +177,31 @@ ENTRY(return_to_handler) jmp lr END(return_to_handler) #endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +ENTRY(ftrace_regs_caller) + mcount_enter_regs + + lrw t1, PT_FRAME_SIZE + add t1, sp + + ldw a0, (t1, 0) + subi a0, 4 + ldw a1, (t1, 8) + lrw a2, function_trace_op + ldw a2, (a2, 0) + mov a3, sp + + nop +GLOBAL(ftrace_regs_call) + nop32_stub + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + nop +GLOBAL(ftrace_graph_regs_call) + nop32_stub +#endif + + mcount_exit_regs +ENDPROC(ftrace_regs_caller) +#endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h index ba35d93ecda2..fae72b0b1374 100644 --- a/arch/csky/include/asm/ftrace.h +++ b/arch/csky/include/asm/ftrace.h @@ -10,6 +10,8 @@ #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR +#define ARCH_SUPPORTS_FTRACE_OPS 1 + #define MCOUNT_ADDR ((unsigned long)_mcount) #ifndef __ASSEMBLY__ diff --git a/arch/csky/kernel/asm-offsets.c b/arch/csky/kernel/asm-offsets.c index 9b48b1b1a61b..f8be348df9e4 100644 --- a/arch/csky/kernel/asm-offsets.c +++ b/arch/csky/kernel/asm-offsets.c @@ -72,6 +72,7 @@ int main(void) DEFINE(PT_RLO, offsetof(struct pt_regs, rlo)); #endif DEFINE(PT_USP, offsetof(struct pt_regs, usp)); + DEFINE(PT_FRAME_SIZE, sizeof(struct pt_regs)); /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, diff --git a/arch/csky/kernel/ftrace.c b/arch/csky/kernel/ftrace.c index 44f4880179b7..b4502cd2eabe 100644 --- a/arch/csky/kernel/ftrace.c +++ b/arch/csky/kernel/ftrace.c @@ -126,6 +126,9 @@ int ftrace_update_ftrace_func(ftrace_func_t func) { int ret = ftrace_modify_code((unsigned long)&ftrace_call, (unsigned long)func, true, true); + if (!ret) + ret = ftrace_modify_code((unsigned long)&ftrace_regs_call, + (unsigned long)func, true, true); return ret; } @@ -135,6 +138,14 @@ int __init ftrace_dyn_arch_init(void) } #endif /* CONFIG_DYNAMIC_FTRACE */ +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + return ftrace_modify_code(rec->ip, addr, true, true); +} +#endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, unsigned long frame_pointer) From b2a16610f2ba72468b4a7ac1e462af1e9c70bae8 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:29 +0000 Subject: [PATCH 205/809] power: reset: at91-reset: introduce struct at91_reset Introduce struct at91_reset intended to keep all the at91 reset controller data. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index d94e3267c3b6..2df0610e5527 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,7 +49,13 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; -static void __iomem *at91_ramc_base[2], *at91_rstc_base; +struct at91_reset { + void __iomem *rstc_base; +}; + +static struct at91_reset reset; + +static void __iomem *at91_ramc_base[2]; static struct clk *sclk; /* @@ -76,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : : "r" (at91_ramc_base[0]), - "r" (at91_rstc_base), + "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); @@ -119,7 +125,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, : : "r" (at91_ramc_base[0]), "r" (at91_ramc_base[1]), - "r" (at91_rstc_base), + "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) @@ -131,8 +137,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { - writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, - at91_rstc_base); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + reset.rstc_base); return NOTIFY_DONE; } @@ -140,14 +146,16 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { - writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), + reset.rstc_base); + return NOTIFY_DONE; } static void __init at91_reset_status(struct platform_device *pdev) { const char *reason; - u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); + u32 reg = readl(reset.rstc_base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -208,8 +216,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) struct device_node *np; int ret, idx = 0; - at91_rstc_base = of_iomap(pdev->dev.of_node, 0); - if (!at91_rstc_base) { + reset.rstc_base = of_iomap(pdev->dev.of_node, 0); + if (!reset.rstc_base) { dev_err(&pdev->dev, "Could not map reset controller address\n"); return -ENODEV; } From 4d9ce0f56aeeb46c8be0e8974646f163d3f6b72d Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:30 +0000 Subject: [PATCH 206/809] power: reset: at91-reset: add ramc_base[] to struct at91_reset Add ramc_base[] to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 2df0610e5527..999d3a1653d2 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -51,11 +51,11 @@ enum reset_type { struct at91_reset { void __iomem *rstc_base; + void __iomem *ramc_base[2]; }; static struct at91_reset reset; -static void __iomem *at91_ramc_base[2]; static struct clk *sclk; /* @@ -81,7 +81,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : - : "r" (at91_ramc_base[0]), + : "r" (reset.ramc_base[0]), "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), @@ -123,8 +123,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, " b .\n\t" : - : "r" (at91_ramc_base[0]), - "r" (at91_ramc_base[1]), + : "r" (reset.ramc_base[0]), + "r" (reset.ramc_base[1]), "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), @@ -225,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { + reset.ramc_base[idx] = of_iomap(np, 0); + if (!reset.ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); of_node_put(np); return -ENODEV; From f9e6ce74cbf2a34f4d37bccbbfc7865e5b3e01dd Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:30 +0000 Subject: [PATCH 207/809] power: reset: at91-reset: add sclk to struct at91_reset Add sclk to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 999d3a1653d2..1bc39bfda0aa 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -52,12 +52,11 @@ enum reset_type { struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; + struct clk *sclk; }; static struct at91_reset reset; -static struct clk *sclk; - /* * unless the SDRAM is cleanly shutdown before we hit the * reset register it can be left driving the data bus and @@ -238,11 +237,11 @@ static int __init at91_reset_probe(struct platform_device *pdev) match = of_match_node(at91_reset_of_match, pdev->dev.of_node); at91_restart_nb.notifier_call = match->data; - sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(sclk)) - return PTR_ERR(sclk); + reset.sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(reset.sclk)) + return PTR_ERR(reset.sclk); - ret = clk_prepare_enable(sclk); + ret = clk_prepare_enable(reset.sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; @@ -250,7 +249,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) ret = register_restart_handler(&at91_restart_nb); if (ret) { - clk_disable_unprepare(sclk); + clk_disable_unprepare(reset.sclk); return ret; } @@ -262,7 +261,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { unregister_restart_handler(&at91_restart_nb); - clk_disable_unprepare(sclk); + clk_disable_unprepare(reset.sclk); return 0; } From 1e3c4af9de26a0246cf00aba207c49846e80c37b Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:31 +0000 Subject: [PATCH 208/809] power: reset: at91-reset: add notifier block to struct at91_reset Add struct notifier_block to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 1bc39bfda0aa..e8840193620d 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -53,6 +53,7 @@ struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; struct clk *sclk; + struct notifier_block nb; }; static struct at91_reset reset; @@ -205,10 +206,6 @@ static const struct of_device_id at91_reset_of_match[] = { }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); -static struct notifier_block at91_restart_nb = { - .priority = 192, -}; - static int __init at91_reset_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -235,7 +232,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - at91_restart_nb.notifier_call = match->data; + reset.nb.notifier_call = match->data; + reset.nb.priority = 192; reset.sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset.sclk)) @@ -247,7 +245,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } - ret = register_restart_handler(&at91_restart_nb); + ret = register_restart_handler(&reset.nb); if (ret) { clk_disable_unprepare(reset.sclk); return ret; @@ -260,7 +258,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { - unregister_restart_handler(&at91_restart_nb); + unregister_restart_handler(&reset.nb); clk_disable_unprepare(reset.sclk); return 0; From b7967b7919f0e3787d6e23424b5ad367fbb937e2 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:31 +0000 Subject: [PATCH 209/809] power: reset: at91-reset: convert reset in pointer to struct at91_reset Convert reset in pointer to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 50 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index e8840193620d..4bb5eef4b258 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -56,7 +56,7 @@ struct at91_reset { struct notifier_block nb; }; -static struct at91_reset reset; +static struct at91_reset *reset; /* * unless the SDRAM is cleanly shutdown before we hit the @@ -81,8 +81,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : - : "r" (reset.ramc_base[0]), - "r" (reset.rstc_base), + : "r" (reset->ramc_base[0]), + "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); @@ -123,9 +123,9 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, " b .\n\t" : - : "r" (reset.ramc_base[0]), - "r" (reset.ramc_base[1]), - "r" (reset.rstc_base), + : "r" (reset->ramc_base[0]), + "r" (reset->ramc_base[1]), + "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) @@ -138,7 +138,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), - reset.rstc_base); + reset->rstc_base); return NOTIFY_DONE; } @@ -147,7 +147,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), - reset.rstc_base); + reset->rstc_base); return NOTIFY_DONE; } @@ -155,7 +155,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, static void __init at91_reset_status(struct platform_device *pdev) { const char *reason; - u32 reg = readl(reset.rstc_base + AT91_RSTC_SR); + u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -212,8 +212,12 @@ static int __init at91_reset_probe(struct platform_device *pdev) struct device_node *np; int ret, idx = 0; - reset.rstc_base = of_iomap(pdev->dev.of_node, 0); - if (!reset.rstc_base) { + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rstc_base = of_iomap(pdev->dev.of_node, 0); + if (!reset->rstc_base) { dev_err(&pdev->dev, "Could not map reset controller address\n"); return -ENODEV; } @@ -221,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ for_each_matching_node(np, at91_ramc_of_match) { - reset.ramc_base[idx] = of_iomap(np, 0); - if (!reset.ramc_base[idx]) { + reset->ramc_base[idx] = of_iomap(np, 0); + if (!reset->ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); of_node_put(np); return -ENODEV; @@ -232,22 +236,22 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset.nb.notifier_call = match->data; - reset.nb.priority = 192; + reset->nb.notifier_call = match->data; + reset->nb.priority = 192; - reset.sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(reset.sclk)) - return PTR_ERR(reset.sclk); + reset->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(reset->sclk)) + return PTR_ERR(reset->sclk); - ret = clk_prepare_enable(reset.sclk); + ret = clk_prepare_enable(reset->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; } - ret = register_restart_handler(&reset.nb); + ret = register_restart_handler(&reset->nb); if (ret) { - clk_disable_unprepare(reset.sclk); + clk_disable_unprepare(reset->sclk); return ret; } @@ -258,8 +262,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { - unregister_restart_handler(&reset.nb); - clk_disable_unprepare(reset.sclk); + unregister_restart_handler(&reset->nb); + clk_disable_unprepare(reset->sclk); return 0; } From 55f8e6fdefbe926e1729bba3a7608eed7d7f24f5 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 210/809] power: reset: at91-reset: pass rstc base address to at91_reset_status() Add new argument to at91_reset_status() that is the pointer to reset controller base address. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 4bb5eef4b258..bd05496c5ac7 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -152,10 +152,11 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } -static void __init at91_reset_status(struct platform_device *pdev) +static void __init at91_reset_status(struct platform_device *pdev, + void __iomem *base) { const char *reason; - u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); + u32 reg = readl(base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -255,7 +256,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } - at91_reset_status(pdev); + at91_reset_status(pdev, reset->rstc_base); return 0; } From 583ef884c8dc8e5ec9a7fde12d40ef7fdf18f5fb Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 211/809] power: reset: at91-reset: devm_kzalloc() for at91_reset data structure Allocate at91_reset data on probe and set it as platform data. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index bd05496c5ac7..7ba77555e9e1 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -56,8 +56,6 @@ struct at91_reset { struct notifier_block nb; }; -static struct at91_reset *reset; - /* * unless the SDRAM is cleanly shutdown before we hit the * reset register it can be left driving the data bus and @@ -66,6 +64,8 @@ static struct at91_reset *reset; static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + asm volatile( /* Align to cache lines */ ".balign 32\n\t" @@ -93,6 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + asm volatile( /* * Test wether we have a second RAM controller to care @@ -137,6 +139,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), reset->rstc_base); @@ -146,6 +150,8 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), reset->rstc_base); @@ -210,6 +216,7 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { const struct of_device_id *match; + struct at91_reset *reset; struct device_node *np; int ret, idx = 0; @@ -250,6 +257,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } + platform_set_drvdata(pdev, reset); + ret = register_restart_handler(&reset->nb); if (ret) { clk_disable_unprepare(reset->sclk); @@ -263,6 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { + struct at91_reset *reset = platform_get_drvdata(pdev); + unregister_restart_handler(&reset->nb); clk_disable_unprepare(reset->sclk); From a5bbad258a9ec41df4a158c828b9ef0af7955854 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 212/809] power: reset: at91-reset: introduce struct at91_reset_data Introduce struct at91_reset_data to be able to provide per SoC data. At the moment this being only notifier callback. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 50 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 7ba77555e9e1..c653bd7ac29a 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,6 +49,11 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; +struct at91_reset_data { + int (*notifier_call)(struct notifier_block *this, unsigned long mode, + void *cmd); +}; + struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; @@ -203,18 +208,50 @@ static const struct of_device_id at91_ramc_of_match[] = { { /* sentinel */ } }; +static const struct at91_reset_data at91sam9260_reset_data = { + .notifier_call = at91sam9260_restart, +}; + +static const struct at91_reset_data at91sam9g45_reset_data = { + .notifier_call = at91sam9g45_restart, +}; + +static const struct at91_reset_data sama5d3_reset_data = { + .notifier_call = sama5d3_restart, +}; + +static const struct at91_reset_data samx7_reset_data = { + .notifier_call = samx7_restart, +}; + static const struct of_device_id at91_reset_of_match[] = { - { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, - { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, - { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, - { .compatible = "atmel,samx7-rstc", .data = samx7_restart }, - { .compatible = "microchip,sam9x60-rstc", .data = samx7_restart }, + { + .compatible = "atmel,at91sam9260-rstc", + .data = &at91sam9260_reset_data + }, + { + .compatible = "atmel,at91sam9g45-rstc", + .data = &at91sam9g45_reset_data + }, + { + .compatible = "atmel,sama5d3-rstc", + .data = &sama5d3_reset_data + }, + { + .compatible = "atmel,samx7-rstc", + .data = &samx7_reset_data + }, + { + .compatible = "microchip,sam9x60-rstc", + .data = &samx7_reset_data + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { + const struct at91_reset_data *reset_data; const struct of_device_id *match; struct at91_reset *reset; struct device_node *np; @@ -244,7 +281,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset->nb.notifier_call = match->data; + reset_data = match->data; + reset->nb.notifier_call = reset_data->notifier_call; reset->nb.priority = 192; reset->sclk = devm_clk_get(&pdev->dev, NULL); From 25b80b7d5a5b41cb52db441e37a04d71e7196f60 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:33 +0000 Subject: [PATCH 213/809] power: reset: at91-reset: introduce args member in at91_reset_data Introduce args member in struct at91_reset_data. It stores the value that needs to be written in mode register so that the reboot actions to happen. With these changes samx7_restart() could be removed. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index c653bd7ac29a..dc48f6850796 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -52,6 +52,7 @@ enum reset_type { struct at91_reset_data { int (*notifier_call)(struct notifier_block *this, unsigned long mode, void *cmd); + u32 args; }; struct at91_reset { @@ -59,6 +60,7 @@ struct at91_reset { void __iomem *ramc_base[2]; struct clk *sclk; struct notifier_block nb; + u32 args; }; /* @@ -90,7 +92,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); + "r" (reset->args)); return NOTIFY_DONE; } @@ -135,7 +137,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), - "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) + "r" (reset->args) : "r0"); return NOTIFY_DONE; @@ -146,19 +148,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, { struct at91_reset *reset = container_of(this, struct at91_reset, nb); - writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), - reset->rstc_base); - - return NOTIFY_DONE; -} - -static int samx7_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), - reset->rstc_base); + writel(reset->args, reset->rstc_base); return NOTIFY_DONE; } @@ -210,18 +200,22 @@ static const struct of_device_id at91_ramc_of_match[] = { static const struct at91_reset_data at91sam9260_reset_data = { .notifier_call = at91sam9260_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data at91sam9g45_reset_data = { .notifier_call = at91sam9g45_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data sama5d3_reset_data = { .notifier_call = sama5d3_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data samx7_reset_data = { - .notifier_call = samx7_restart, + .notifier_call = sama5d3_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, }; static const struct of_device_id at91_reset_of_match[] = { @@ -284,6 +278,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) reset_data = match->data; reset->nb.notifier_call = reset_data->notifier_call; reset->nb.priority = 192; + reset->args = reset_data->args; reset->sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset->sclk)) From 7cb290d3dd559dff5028b9418a31ecb99988f640 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:33 +0000 Subject: [PATCH 214/809] power: reset: at91-reset: use r4 as tmp argument Use r4 as temporary register. On ARM r0-r3 should be used to hold function arguments. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index dc48f6850796..3b1d566350f4 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -113,8 +113,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "beq 1f\n\t" /* Then, test that the RAM controller is enabled */ - "ldr r0, [%1]\n\t" - "cmp r0, #0\n\t" + "ldr r4, [%1]\n\t" + "cmp r4, #0\n\t" /* Align to cache lines */ ".balign 32\n\t" @@ -138,7 +138,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" (reset->args) - : "r0"); + : "r4"); return NOTIFY_DONE; } From 68a84a3e68a2238036dd6c7dbb677fe62a92d70a Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:34 +0000 Subject: [PATCH 215/809] power: reset: at91-reset: introduce ramc_lpr to struct at91_reset Introduce ramc_lpr to struct at91_reset. This will lead to the unification of at91sam9260_restart() and at91sam9g45_restart(). Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 3b1d566350f4..4e1961334e4d 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -61,6 +61,7 @@ struct at91_reset { struct clk *sclk; struct notifier_block nb; u32 args; + u32 ramc_lpr; }; /* @@ -81,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" /* Power down SDRAM */ - "str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t" + "str %3, [%0, %5]\n\t" /* Reset CPU */ "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" @@ -92,7 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" (reset->args)); + "r" (reset->args), + "r" (reset->ramc_lpr)); return NOTIFY_DONE; } @@ -122,11 +124,11 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, /* Disable SDRAM0 accesses */ "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM0 */ - " str %4, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + " str %4, [%0, %6]\n\t" /* Disable SDRAM1 accesses */ " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM1 */ - " strne %4, [%1, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + " strne %4, [%1, %6]\n\t" /* Reset CPU */ " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" @@ -137,7 +139,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), - "r" (reset->args) + "r" (reset->args), + "r" (reset->ramc_lpr) : "r4"); return NOTIFY_DONE; @@ -193,8 +196,14 @@ static void __init at91_reset_status(struct platform_device *pdev, } static const struct of_device_id at91_ramc_of_match[] = { - { .compatible = "atmel,at91sam9260-sdramc", }, - { .compatible = "atmel,at91sam9g45-ddramc", }, + { + .compatible = "atmel,at91sam9260-sdramc", + .data = (void *)AT91_SDRAMC_LPR, + }, + { + .compatible = "atmel,at91sam9g45-ddramc", + .data = (void *)AT91_DDRSDRC_LPR, + }, { /* sentinel */ } }; @@ -263,7 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ - for_each_matching_node(np, at91_ramc_of_match) { + for_each_matching_node_and_match(np, at91_ramc_of_match, &match) { + reset->ramc_lpr = (u32)match->data; reset->ramc_base[idx] = of_iomap(np, 0); if (!reset->ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); From fcd0532fac2ac82cec6d7b43298c8ecfc93e1049 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:37 +0000 Subject: [PATCH 216/809] power: reset: at91-reset: make at91sam9g45_restart() generic Make at91sam9g45_restart() generic. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 4e1961334e4d..61433060d784 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -105,32 +105,23 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, struct at91_reset *reset = container_of(this, struct at91_reset, nb); asm volatile( - /* - * Test wether we have a second RAM controller to care - * about. - * - * First, test that we can dereference the virtual address. - */ - "cmp %1, #0\n\t" - "beq 1f\n\t" - - /* Then, test that the RAM controller is enabled */ - "ldr r4, [%1]\n\t" - "cmp r4, #0\n\t" - /* Align to cache lines */ ".balign 32\n\t" /* Disable SDRAM0 accesses */ - "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + " tst %0, #0\n\t" + " beq 1f\n\t" + " str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM0 */ " str %4, [%0, %6]\n\t" /* Disable SDRAM1 accesses */ + "1: tst %1, #0\n\t" + " beq 2f\n\t" " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM1 */ " strne %4, [%1, %6]\n\t" /* Reset CPU */ - " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" + "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" " b .\n\t" : From 51aa7d45f905ca03d3c61d32a09537903a7ea707 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:38 +0000 Subject: [PATCH 217/809] power: reset: at91-reset: keep only one reset function Keep only one reset function. With this, notifier_call member of struct at91_reset_data could be removed. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 52 ++------------------------------ 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 61433060d784..9c1b69f76a01 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -50,8 +50,6 @@ enum reset_type { }; struct at91_reset_data { - int (*notifier_call)(struct notifier_block *this, unsigned long mode, - void *cmd); u32 args; }; @@ -69,38 +67,8 @@ struct at91_reset { * reset register it can be left driving the data bus and * killing the chance of a subsequent boot from NAND */ -static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - asm volatile( - /* Align to cache lines */ - ".balign 32\n\t" - - /* Disable SDRAM accesses */ - "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" - - /* Power down SDRAM */ - "str %3, [%0, %5]\n\t" - - /* Reset CPU */ - "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" - - "b .\n\t" - : - : "r" (reset->ramc_base[0]), - "r" (reset->rstc_base), - "r" (1), - "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" (reset->args), - "r" (reset->ramc_lpr)); - - return NOTIFY_DONE; -} - -static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, - void *cmd) +static int at91_reset(struct notifier_block *this, unsigned long mode, + void *cmd) { struct at91_reset *reset = container_of(this, struct at91_reset, nb); @@ -137,16 +105,6 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } -static int sama5d3_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - writel(reset->args, reset->rstc_base); - - return NOTIFY_DONE; -} - static void __init at91_reset_status(struct platform_device *pdev, void __iomem *base) { @@ -199,22 +157,18 @@ static const struct of_device_id at91_ramc_of_match[] = { }; static const struct at91_reset_data at91sam9260_reset_data = { - .notifier_call = at91sam9260_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data at91sam9g45_reset_data = { - .notifier_call = at91sam9g45_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data sama5d3_reset_data = { - .notifier_call = sama5d3_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data samx7_reset_data = { - .notifier_call = sama5d3_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, }; @@ -277,7 +231,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) match = of_match_node(at91_reset_of_match, pdev->dev.of_node); reset_data = match->data; - reset->nb.notifier_call = reset_data->notifier_call; + reset->nb.notifier_call = at91_reset; reset->nb.priority = 192; reset->args = reset_data->args; From 766b0162e613a89a330382e566e29da57f5f0de5 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:39 +0000 Subject: [PATCH 218/809] power: reset: at91-reset: get rid of at91_reset_data After refactoring struct at91_reset_data and struct at91_reset_data at91sam9260_reset_data are not needed anymore. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 37 ++++++++------------------------ 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 9c1b69f76a01..537ccb180568 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,10 +49,6 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; -struct at91_reset_data { - u32 args; -}; - struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; @@ -156,42 +152,29 @@ static const struct of_device_id at91_ramc_of_match[] = { { /* sentinel */ } }; -static const struct at91_reset_data at91sam9260_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data at91sam9g45_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data sama5d3_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data samx7_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, -}; - static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", - .data = &at91sam9260_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST), }, { .compatible = "atmel,at91sam9g45-rstc", - .data = &at91sam9g45_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST) }, { .compatible = "atmel,sama5d3-rstc", - .data = &sama5d3_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST) }, { .compatible = "atmel,samx7-rstc", - .data = &samx7_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST) }, { .compatible = "microchip,sam9x60-rstc", - .data = &samx7_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST) }, { /* sentinel */ } }; @@ -199,7 +182,6 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { - const struct at91_reset_data *reset_data; const struct of_device_id *match; struct at91_reset *reset; struct device_node *np; @@ -230,10 +212,9 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset_data = match->data; reset->nb.notifier_call = at91_reset; reset->nb.priority = 192; - reset->args = reset_data->args; + reset->args = (u32)match->data; reset->sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset->sclk)) From e48bbb52a2aad8613291a9e4e757bbf995769015 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:39 +0000 Subject: [PATCH 219/809] power: reset: at91-reset: handle nrst async for sam9x60 Handle NRST asynchronously for SAM9X60 to avoid problem with fast drop of VDDCORE on shutdown operations in the first 100 us after CPU is shutdown. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 537ccb180568..3ff9d93a5226 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -35,6 +35,7 @@ #define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ #define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ +#define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */ #define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ #define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ @@ -228,6 +229,13 @@ static int __init at91_reset_probe(struct platform_device *pdev) platform_set_drvdata(pdev, reset); + if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) { + u32 val = readl(reset->rstc_base + AT91_RSTC_MR); + + writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val, + reset->rstc_base + AT91_RSTC_MR); + } + ret = register_restart_handler(&reset->nb); if (ret) { clk_disable_unprepare(reset->sclk); From fc51da4c15fa1e00cd1f855e14e8b05abbc555c7 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 4 Mar 2020 15:42:14 +0900 Subject: [PATCH 220/809] dt-bindings: clock: renesas: rcar-usb2-clock-sel: Fix clock[-name]s properties Since the hardware requires to enable both USB 2.0 host and peripheral functional clock, this patch fixes the documentation. Fortunately, no one has this device node for now, so that we don't need to think of backward compatibility. Fixes: 311accb64570 ("clk: renesas: rcar-usb2-clock-sel: Add R-Car USB 2.0 clock selector PHY") Signed-off-by: Yoshihiro Shimoda Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1583304137-28482-2-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- .../bindings/clock/renesas,rcar-usb2-clock-sel.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt index 83f6c6a7c41c..5c1903fc40b3 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt @@ -38,7 +38,8 @@ Required properties: - reg: offset and length of the USB 2.0 clock selector register block. - clocks: A list of phandles and specifier pairs. - clock-names: Name of the clocks. - - The functional clock must be "ehci_ohci" + - The functional clock of USB 2.0 host side must be "ehci_ohci" + - The functional clock of HS-USB side must be "hs-usb-if" - The USB_EXTAL clock pin must be "usb_extal" - The USB_XTAL clock pin must be "usb_xtal" - #clock-cells: Must be 0 @@ -49,7 +50,8 @@ Example (R-Car H3): compatible = "renesas,r8a7795-rcar-usb2-clock-sel", "renesas,rcar-gen3-usb2-clock-sel"; reg = <0 0xe6590630 0 0x02>; - clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>; - clock-names = "ehci_ohci", "usb_extal", "usb_xtal"; + clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, + <&usb_extal>, <&usb_xtal>; + clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal"; #clock-cells = <0>; }; From f70ae8ecf950fc49291eb4aeca43192b28ff342f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 4 Mar 2020 15:42:15 +0900 Subject: [PATCH 221/809] dt-bindings: clock: renesas: rcar-usb2-clock-sel: Add power-domains and resets properties This patch adds missing required properties of power-domains and resets. Fortunately, no one has this device node for now, so that we don't need to think of backward compatibility. Fixes: 311accb64570 ("clk: renesas: rcar-usb2-clock-sel: Add R-Car USB 2.0 clock selector PHY") Signed-off-by: Yoshihiro Shimoda Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1583304137-28482-3-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- .../bindings/clock/renesas,rcar-usb2-clock-sel.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt index 5c1903fc40b3..4bf6f53bd95e 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt @@ -43,6 +43,12 @@ Required properties: - The USB_EXTAL clock pin must be "usb_extal" - The USB_XTAL clock pin must be "usb_xtal" - #clock-cells: Must be 0 +- power-domains: A phandle and symbolic PM domain specifier. + See power/renesas,rcar-sysc.yaml. +- resets: A list of phandles and specifier pairs. +- reset-names: Name of the resets. + - The reset of USB 2.0 host side must be "ehci_ohci" + - The reset of HS-USB side must be "hs-usb-if" Example (R-Car H3): @@ -54,4 +60,7 @@ Example (R-Car H3): <&usb_extal>, <&usb_xtal>; clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal"; #clock-cells = <0>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 703>, <&cpg 704>; + reset-names = "ehci_ohci", "hs-usb-if"; }; From 80cf67dd010b4a187360bb8ce8a1974bdad8c076 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 4 Mar 2020 15:42:16 +0900 Subject: [PATCH 222/809] clk: renesas: rcar-usb2-clock-sel: Add multiple clocks management This hardware needs to enable clocks of both host and peripheral. So, this patch adds multiple clocks management. Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/1583304137-28482-4-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-usb2-clock-sel.c | 27 +++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c index b97f5f9326cf..d5f47ab017b7 100644 --- a/drivers/clk/renesas/rcar-usb2-clock-sel.c +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -26,9 +26,15 @@ #define CLKSET0_PRIVATE BIT(0) #define CLKSET0_EXTAL_ONLY (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE) +static const struct clk_bulk_data rcar_usb2_clocks[] = { + { .id = "ehci_ohci", }, + { .id = "hs-usb-if", }, +}; + struct usb2_clock_sel_priv { void __iomem *base; struct clk_hw hw; + struct clk_bulk_data clks[ARRAY_SIZE(rcar_usb2_clocks)]; bool extal; bool xtal; }; @@ -53,14 +59,25 @@ static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv *priv) static int usb2_clock_sel_enable(struct clk_hw *hw) { - usb2_clock_sel_enable_extal_only(to_priv(hw)); + struct usb2_clock_sel_priv *priv = to_priv(hw); + int ret; + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clks), priv->clks); + if (ret) + return ret; + + usb2_clock_sel_enable_extal_only(priv); return 0; } static void usb2_clock_sel_disable(struct clk_hw *hw) { - usb2_clock_sel_disable_extal_only(to_priv(hw)); + struct usb2_clock_sel_priv *priv = to_priv(hw); + + usb2_clock_sel_disable_extal_only(priv); + + clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clks), priv->clks); } /* @@ -119,6 +136,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) struct usb2_clock_sel_priv *priv; struct clk *clk; struct clk_init_data init; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -128,6 +146,11 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); + memcpy(priv->clks, rcar_usb2_clocks, sizeof(priv->clks)); + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clks), priv->clks); + if (ret < 0) + return ret; + pm_runtime_enable(dev); pm_runtime_get_sync(dev); From 1ab4f43927a452ef24cd47ef686f3e1cbac9ab61 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 4 Mar 2020 15:42:17 +0900 Subject: [PATCH 223/809] clk: renesas: rcar-usb2-clock-sel: Add reset_control This hardware needs to deassert resets of both host and peripheral. So, this patch adds reset control. Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/1583304137-28482-5-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 1 + drivers/clk/renesas/rcar-usb2-clock-sel.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 879d96ead06b..ac2dd92ce2ef 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -161,6 +161,7 @@ config CLK_RCAR_GEN3_CPG config CLK_RCAR_USB2_CLOCK_SEL bool "Renesas R-Car USB2 clock selector support" depends on ARCH_RENESAS || COMPILE_TEST + select RESET_CONTROLLER help This is a driver for R-Car USB2 clock selector diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c index d5f47ab017b7..d4c02986c34e 100644 --- a/drivers/clk/renesas/rcar-usb2-clock-sel.c +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #define USB20_CLKSET0 0x00 @@ -35,6 +36,7 @@ struct usb2_clock_sel_priv { void __iomem *base; struct clk_hw hw; struct clk_bulk_data clks[ARRAY_SIZE(rcar_usb2_clocks)]; + struct reset_control *rsts; bool extal; bool xtal; }; @@ -62,10 +64,16 @@ static int usb2_clock_sel_enable(struct clk_hw *hw) struct usb2_clock_sel_priv *priv = to_priv(hw); int ret; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clks), priv->clks); + ret = reset_control_deassert(priv->rsts); if (ret) return ret; + ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clks), priv->clks); + if (ret) { + reset_control_assert(priv->rsts); + return ret; + } + usb2_clock_sel_enable_extal_only(priv); return 0; @@ -78,6 +86,7 @@ static void usb2_clock_sel_disable(struct clk_hw *hw) usb2_clock_sel_disable_extal_only(priv); clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clks), priv->clks); + reset_control_assert(priv->rsts); } /* @@ -151,6 +160,10 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) if (ret < 0) return ret; + priv->rsts = devm_reset_control_array_get(dev, true, false); + if (IS_ERR(priv->rsts)) + return PTR_ERR(priv->rsts); + pm_runtime_enable(dev); pm_runtime_get_sync(dev); From bc0ae0e737f5167348579612493e2754e2122dfb Mon Sep 17 00:00:00 2001 From: Asmaa Mnebhi Date: Mon, 2 Mar 2020 16:04:46 -0500 Subject: [PATCH 224/809] gpio: add driver for Mellanox BlueField 2 GPIO controller This patch adds support for the GPIO controller used by Mellanox BlueField 2 SOCs. Signed-off-by: Asmaa Mnebhi Link: https://lore.kernel.org/r/1680de9eb6d2b8855228dde9a2dd065f0dcbe1fb.1583182325.git.Asmaa@mellanox.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mlxbf2.c | 335 +++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/gpio/gpio-mlxbf2.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b8013cf90064..6234ccc90e7e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1399,6 +1399,13 @@ config GPIO_MLXBF help Say Y here if you want GPIO support on Mellanox BlueField SoC. +config GPIO_MLXBF2 + tristate "Mellanox BlueField 2 SoC GPIO" + depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST) + select GPIO_GENERIC + help + Say Y here if you want GPIO support on Mellanox BlueField 2 SoC. + config GPIO_ML_IOH tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" depends on X86 || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0b571264ddbc..b2cfc21a97f3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o +obj-$(CONFIG_GPIO_MLXBF2) += gpio-mlxbf2.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c new file mode 100644 index 000000000000..7b7085050219 --- /dev/null +++ b/drivers/gpio/gpio-mlxbf2.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * There are 3 YU GPIO blocks: + * gpio[0]: HOST_GPIO0->HOST_GPIO31 + * gpio[1]: HOST_GPIO32->HOST_GPIO63 + * gpio[2]: HOST_GPIO64->HOST_GPIO69 + */ +#define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32 + +/* + * arm_gpio_lock register: + * bit[31] lock status: active if set + * bit[15:0] set lock + * The lock is enabled only if 0xd42f is written to this field + */ +#define YU_ARM_GPIO_LOCK_ADDR 0x2801088 +#define YU_ARM_GPIO_LOCK_SIZE 0x8 +#define YU_LOCK_ACTIVE_BIT(val) (val >> 31) +#define YU_ARM_GPIO_LOCK_ACQUIRE 0xd42f +#define YU_ARM_GPIO_LOCK_RELEASE 0x0 + +/* + * gpio[x] block registers and their offset + */ +#define YU_GPIO_DATAIN 0x04 +#define YU_GPIO_MODE1 0x08 +#define YU_GPIO_MODE0 0x0c +#define YU_GPIO_DATASET 0x14 +#define YU_GPIO_DATACLEAR 0x18 +#define YU_GPIO_MODE1_CLEAR 0x50 +#define YU_GPIO_MODE0_SET 0x54 +#define YU_GPIO_MODE0_CLEAR 0x58 + +#ifdef CONFIG_PM +struct mlxbf2_gpio_context_save_regs { + u32 gpio_mode0; + u32 gpio_mode1; +}; +#endif + +/* BlueField-2 gpio block context structure. */ +struct mlxbf2_gpio_context { + struct gpio_chip gc; + + /* YU GPIO blocks address */ + void __iomem *gpio_io; + +#ifdef CONFIG_PM + struct mlxbf2_gpio_context_save_regs *csave_regs; +#endif +}; + +/* BlueField-2 gpio shared structure. */ +struct mlxbf2_gpio_param { + void __iomem *io; + struct resource *res; + struct mutex *lock; +}; + +static struct resource yu_arm_gpio_lock_res = { + .start = YU_ARM_GPIO_LOCK_ADDR, + .end = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1, + .name = "YU_ARM_GPIO_LOCK", +}; + +static DEFINE_MUTEX(yu_arm_gpio_lock_mutex); + +static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = { + .res = &yu_arm_gpio_lock_res, + .lock = &yu_arm_gpio_lock_mutex, +}; + +/* Request memory region and map yu_arm_gpio_lock resource */ +static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + resource_size_t size; + int ret = 0; + + mutex_lock(yu_arm_gpio_lock_param.lock); + + /* Check if the memory map already exists */ + if (yu_arm_gpio_lock_param.io) + goto exit; + + res = yu_arm_gpio_lock_param.res; + size = resource_size(res); + + if (!devm_request_mem_region(dev, res->start, size, res->name)) { + ret = -EFAULT; + goto exit; + } + + yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size); + if (IS_ERR(yu_arm_gpio_lock_param.io)) + ret = PTR_ERR(yu_arm_gpio_lock_param.io); + +exit: + mutex_unlock(yu_arm_gpio_lock_param.lock); + + return ret; +} + +/* + * Acquire the YU arm_gpio_lock to be able to change the direction + * mode. If the lock_active bit is already set, return an error. + */ +static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs) +{ + u32 arm_gpio_lock_val; + + spin_lock(&gs->gc.bgpio_lock); + mutex_lock(yu_arm_gpio_lock_param.lock); + + arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io); + + /* + * When lock active bit[31] is set, ModeX is write enabled + */ + if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) { + mutex_unlock(yu_arm_gpio_lock_param.lock); + spin_unlock(&gs->gc.bgpio_lock); + return -EINVAL; + } + + writel(YU_ARM_GPIO_LOCK_ACQUIRE, yu_arm_gpio_lock_param.io); + + return 0; +} + +/* + * Release the YU arm_gpio_lock after changing the direction mode. + */ +static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs) +{ + writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io); + mutex_unlock(yu_arm_gpio_lock_param.lock); + spin_unlock(&gs->gc.bgpio_lock); +} + +/* + * mode0 and mode1 are both locked by the gpio_lock field. + * + * Together, mode0 and mode1 define the gpio Mode dependeing also + * on Reg_DataOut. + * + * {mode1,mode0}:{Reg_DataOut=0,Reg_DataOut=1}->{DataOut=0,DataOut=1} + * + * {0,0}:Reg_DataOut{0,1}->{Z,Z} Input PAD + * {0,1}:Reg_DataOut{0,1}->{0,1} Full drive Output PAD + * {1,0}:Reg_DataOut{0,1}->{0,Z} 0-set PAD to low, 1-float + * {1,1}:Reg_DataOut{0,1}->{Z,1} 0-float, 1-set PAD to high + */ + +/* + * Set input direction: + * {mode1,mode0} = {0,0} + */ +static int mlxbf2_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip); + int ret; + + /* + * Although the arm_gpio_lock was set in the probe function, check again + * if it is still enabled to be able to write to the ModeX registers. + */ + ret = mlxbf2_gpio_lock_acquire(gs); + if (ret < 0) + return ret; + + writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_CLEAR); + writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR); + + mlxbf2_gpio_lock_release(gs); + + return ret; +} + +/* + * Set output direction: + * {mode1,mode0} = {0,1} + */ +static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, + int value) +{ + struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip); + int ret = 0; + + /* + * Although the arm_gpio_lock was set in the probe function, + * check again it is still enabled to be able to write to the + * ModeX registers. + */ + ret = mlxbf2_gpio_lock_acquire(gs); + if (ret < 0) + return ret; + + writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR); + writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET); + + mlxbf2_gpio_lock_release(gs); + + return ret; +} + +/* BlueField-2 GPIO driver initialization routine. */ +static int +mlxbf2_gpio_probe(struct platform_device *pdev) +{ + struct mlxbf2_gpio_context *gs; + struct device *dev = &pdev->dev; + struct gpio_chip *gc; + struct resource *res; + unsigned int npins; + int ret; + + gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); + if (!gs) + return -ENOMEM; + + /* YU GPIO block address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); + if (!gs->gpio_io) + return -ENOMEM; + + ret = mlxbf2_gpio_get_lock_res(pdev); + if (ret) { + dev_err(dev, "Failed to get yu_arm_gpio_lock resource\n"); + return ret; + } + + if (device_property_read_u32(dev, "npins", &npins)) + npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; + + gc = &gs->gc; + + ret = bgpio_init(gc, dev, 4, + gs->gpio_io + YU_GPIO_DATAIN, + gs->gpio_io + YU_GPIO_DATASET, + gs->gpio_io + YU_GPIO_DATACLEAR, + NULL, + NULL, + 0); + + gc->direction_input = mlxbf2_gpio_direction_input; + gc->direction_output = mlxbf2_gpio_direction_output; + gc->ngpio = npins; + gc->owner = THIS_MODULE; + + platform_set_drvdata(pdev, gs); + + ret = devm_gpiochip_add_data(dev, &gs->gc, gs); + if (ret) { + dev_err(dev, "Failed adding memory mapped gpiochip\n"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM +static int mlxbf2_gpio_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev); + + gs->csave_regs->gpio_mode0 = readl(gs->gpio_io + + YU_GPIO_MODE0); + gs->csave_regs->gpio_mode1 = readl(gs->gpio_io + + YU_GPIO_MODE1); + + return 0; +} + +static int mlxbf2_gpio_resume(struct platform_device *pdev) +{ + struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev); + + writel(gs->csave_regs->gpio_mode0, gs->gpio_io + + YU_GPIO_MODE0); + writel(gs->csave_regs->gpio_mode1, gs->gpio_io + + YU_GPIO_MODE1); + + return 0; +} +#endif + +static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = { + { "MLNXBF22", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match); + +static struct platform_driver mlxbf2_gpio_driver = { + .driver = { + .name = "mlxbf2_gpio", + .acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match), + }, + .probe = mlxbf2_gpio_probe, +#ifdef CONFIG_PM + .suspend = mlxbf2_gpio_suspend, + .resume = mlxbf2_gpio_resume, +#endif +}; + +module_platform_driver(mlxbf2_gpio_driver); + +MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver"); +MODULE_AUTHOR("Mellanox Technologies"); +MODULE_LICENSE("GPL v2"); From 55be2f50336f67800513b46c5ba6270e4ed0e784 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 4 Mar 2020 14:54:30 -0800 Subject: [PATCH 225/809] ARM: OMAP2+: Handle errors for cpu_pm We need to check for errors when calling cpu_pm_enter() and cpu_cluster_pm_enter(). And we need to bail out on errors as otherwise we can enter a deeper idle state when not desired. I'm not aware of the lack of error handling causing issues yet, but we need this at least for blocking deeper idle states when a GPIO instance has pending interrupts. Cc: Dave Gerlach Cc: Grygorii Strashko Cc: Keerthy Cc: Ladislav Michl Cc: Russell King Cc: Tero Kristo Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20200304225433.37336-2-tony@atomide.com Signed-off-by: Linus Walleij --- arch/arm/mach-omap2/cpuidle34xx.c | 9 +++++++-- arch/arm/mach-omap2/cpuidle44xx.c | 26 +++++++++++++++++--------- arch/arm/mach-omap2/pm34xx.c | 8 ++++++-- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 532a3e4b98c6..090a8aafb25e 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -109,6 +109,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, int index) { struct omap3_idle_statedata *cx = &omap3_idle_data[index]; + int error; if (omap_irq_pending() || need_resched()) goto return_sleep_time; @@ -125,8 +126,11 @@ static int omap3_enter_idle(struct cpuidle_device *dev, * Call idle CPU PM enter notifier chain so that * VFP context is saved. */ - if (cx->mpu_state == PWRDM_POWER_OFF) - cpu_pm_enter(); + if (cx->mpu_state == PWRDM_POWER_OFF) { + error = cpu_pm_enter(); + if (error) + goto out_clkdm_set; + } /* Execute ARM wfi */ omap_sram_idle(); @@ -139,6 +143,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) cpu_pm_exit(); +out_clkdm_set: /* Re-allow idle for C1 */ if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index fe75d4fa6073..6f5f89711f25 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -122,6 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, { struct idle_statedata *cx = state_ptr + index; u32 mpuss_can_lose_context = 0; + int error; /* * CPU0 has to wait and stay ON until CPU1 is OFF state. @@ -159,7 +160,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU PM enter notifier chain so that * VFP and per CPU interrupt context is saved. */ - cpu_pm_enter(); + error = cpu_pm_enter(); + if (error) + goto cpu_pm_out; if (dev->cpu == 0) { pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); @@ -169,13 +172,17 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU cluster PM enter notifier chain * to save GIC and wakeupgen context. */ - if (mpuss_can_lose_context) - cpu_cluster_pm_enter(); + if (mpuss_can_lose_context) { + error = cpu_cluster_pm_enter(); + if (error) + goto cpu_cluster_pm_out; + } } omap4_enter_lowpower(dev->cpu, cx->cpu_state); cpu_done[dev->cpu] = true; +cpu_cluster_pm_out: /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { @@ -197,12 +204,6 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, } } - /* - * Call idle CPU PM exit notifier chain to restore - * VFP and per CPU IRQ context. - */ - cpu_pm_exit(); - /* * Call idle CPU cluster PM exit notifier chain * to restore GIC and wakeupgen context. @@ -210,6 +211,13 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, if (dev->cpu == 0 && mpuss_can_lose_context) cpu_cluster_pm_exit(); + /* + * Call idle CPU PM exit notifier chain to restore + * VFP and per CPU IRQ context. + */ + cpu_pm_exit(); + +cpu_pm_out: tick_broadcast_exit(); fail: diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index e66e9948636c..6df395fff971 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -191,6 +191,7 @@ void omap_sram_idle(void) int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; u32 sdrc_pwr = 0; + int error; mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { @@ -219,8 +220,11 @@ void omap_sram_idle(void) pwrdm_pre_transition(NULL); /* PER */ - if (per_next_state == PWRDM_POWER_OFF) - cpu_cluster_pm_enter(); + if (per_next_state == PWRDM_POWER_OFF) { + error = cpu_cluster_pm_enter(); + if (error) + return; + } /* CORE */ if (core_next_state < PWRDM_POWER_ON) { From 43582265be8c5c29f4f420ce08a29d48f560c86e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 4 Mar 2020 14:54:31 -0800 Subject: [PATCH 226/809] gpio: omap: Block idle on pending gpio interrupts With the SoC cpuidle handling fixed for cpu_pm, we can now start to return NOTIFY_BAD if there there are pending gpio interrupts. This way the deeper SoC idle states can get blocked, and gpio latency is improved in some cases. Note that this will not help with the latency if the SoC has already entered a deeper idle state. Note that this patch depends on cpu_pm properly handling the errors returned by notifiers. For omap variants, this is fixed with patch "ARM: OMAP2+: Handle errors for cpu_pm". Cc: Dave Gerlach Cc: Grygorii Strashko Cc: Keerthy Cc: Ladislav Michl Cc: Russell King Cc: Tero Kristo Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20200304225433.37336-3-tony@atomide.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 3bd8adaeed9e..3d50cb25aa24 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1237,26 +1237,35 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb, { struct gpio_bank *bank; unsigned long flags; + int ret = NOTIFY_OK; + u32 isr, mask; bank = container_of(nb, struct gpio_bank, nb); raw_spin_lock_irqsave(&bank->lock, flags); + if (bank->is_suspended) + goto out_unlock; + switch (cmd) { case CPU_CLUSTER_PM_ENTER: - if (bank->is_suspended) + mask = omap_get_gpio_irqbank_mask(bank); + isr = readl_relaxed(bank->base + bank->regs->irqstatus) & mask; + if (isr) { + ret = NOTIFY_BAD; break; + } omap_gpio_idle(bank, true); break; case CPU_CLUSTER_PM_ENTER_FAILED: case CPU_CLUSTER_PM_EXIT: - if (bank->is_suspended) - break; omap_gpio_unidle(bank); break; } + +out_unlock: raw_spin_unlock_irqrestore(&bank->lock, flags); - return NOTIFY_OK; + return ret; } static const struct omap_gpio_reg_offs omap2_gpio_regs = { From 579ced8fdb00b8e94304a83e3cc419f6f8eab08e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 4 Mar 2020 14:54:32 -0800 Subject: [PATCH 227/809] Revert "gpio: omap: Fix lost edge wake-up interrupts" This reverts commit a522f1d0c381c42f3ace13b8bbeeccabdd6d2e5c. With cpu_pm handling fixed for omaps, and with gpio-omap now returning notify error on pending interrupts, we can drop the old workaround for seeing if there may be pending edge interrupts. Depends-on: ARM: OMAP2+: Handle errors for cpu_pm Depends-on: gpio: omap: Block idle on pending gpio interrupts Cc: Aaro Koskinen Cc: Grygorii Strashko Cc: Keerthy Cc: Ladislav Michl Cc: Peter Ujfalusi Cc: Russell King Cc: Tero Kristo Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200304225433.37336-4-tony@atomide.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 3d50cb25aa24..b8e2ecc3eade 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1102,23 +1102,13 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) { struct device *dev = bank->chip.parent; void __iomem *base = bank->base; - u32 mask, nowake; + u32 nowake; bank->saved_datain = readl_relaxed(base + bank->regs->datain); if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count; - /* Check for pending EDGE_FALLING, ignore EDGE_BOTH */ - mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect; - mask &= ~bank->context.risingdetect; - bank->saved_datain |= mask; - - /* Check for pending EDGE_RISING, ignore EDGE_BOTH */ - mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect; - mask &= ~bank->context.fallingdetect; - bank->saved_datain &= ~mask; - if (!may_lose_context) goto update_gpio_context_count; From dad4e7fda4bdc1a6357db500a7bab8843c08e521 Mon Sep 17 00:00:00 2001 From: Mike Tipton Date: Fri, 14 Feb 2020 18:12:32 -0800 Subject: [PATCH 228/809] clk: qcom: clk-rpmh: Wait for completion when enabling clocks The current implementation always uses rpmh_write_async, which doesn't wait for completion. That's fine for disable requests since there's no immediate need for the clocks and they can be disabled in the background. However, for enable requests we need to ensure the clocks are actually enabled before returning to the client. Otherwise, clients can end up accessing their HW before the necessary clocks are enabled, which can lead to bus errors. Use the synchronous version of this API (rpmh_write) for enable requests in the active set to ensure completion. Completion isn't required for sleep/wake sets, since they don't take effect until after we enter sleep. All rpmh requests are automatically flushed prior to entering sleep. Fixes: 9c7e47025a6b ("clk: qcom: clk-rpmh: Add QCOM RPMh clock driver") Signed-off-by: Mike Tipton Link: https://lkml.kernel.org/r/20200215021232.1149-1-mdtipton@codeaurora.org Reviewed-by: Bjorn Andersson [sboyd@kernel.org: Reorg code a bit for readability, rename to 'wait' to make local variable not conflict with completion.h mechanism] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 12bd8715dece..bfc29aec3a78 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -143,12 +143,22 @@ static inline bool has_state_changed(struct clk_rpmh *c, u32 state) != (c->aggr_state & BIT(state)); } +static int clk_rpmh_send(struct clk_rpmh *c, enum rpmh_state state, + struct tcs_cmd *cmd, bool wait) +{ + if (wait) + return rpmh_write(c->dev, state, cmd, 1); + + return rpmh_write_async(c->dev, state, cmd, 1); +} + static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c) { struct tcs_cmd cmd = { 0 }; u32 cmd_state, on_val; enum rpmh_state state = RPMH_SLEEP_STATE; int ret; + bool wait; cmd.addr = c->res_addr; cmd_state = c->aggr_state; @@ -159,7 +169,8 @@ static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c) if (cmd_state & BIT(state)) cmd.data = on_val; - ret = rpmh_write_async(c->dev, state, &cmd, 1); + wait = cmd_state && state == RPMH_ACTIVE_ONLY_STATE; + ret = clk_rpmh_send(c, state, &cmd, wait); if (ret) { dev_err(c->dev, "set %s state of %s failed: (%d)\n", !state ? "sleep" : @@ -267,7 +278,7 @@ static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) cmd.addr = c->res_addr; cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state); - ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); + ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable); if (ret) { dev_err(c->dev, "set active state of %s failed: (%d)\n", c->res_name, ret); From 7d61e773c3ed8a4aea866eb287cc0191f9f35779 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 31 Oct 2019 12:29:50 +0100 Subject: [PATCH 229/809] clk: qcom: smd: Add support for MSM8976 rpm clocks Add rpm smd clocks, PMIC and bus clocks which are required on MSM8976, MSM8956 (and APQ variants) for clients to vote on. Signed-off-by: AngeloGioacchino Del Regno Link: https://lkml.kernel.org/r/20191031112951.35850-2-kholk11@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-smd-rpm.c | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 0bbfef9fa6de..52f63ad787ba 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -525,6 +525,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8974 = { .num_clks = ARRAY_SIZE(msm8974_clks), }; + +/* msm8976 */ +DEFINE_CLK_SMD_RPM(msm8976, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8976, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8976, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, + QCOM_SMD_RPM_BUS_CLK, 2); +DEFINE_CLK_SMD_RPM(msm8976, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8976, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0); +DEFINE_CLK_SMD_RPM_QDSS(msm8976, qdss_clk, qdss_a_clk, + QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk1, bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk2, bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, rf_clk2, rf_clk2_a, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, div_clk2, div_clk2_a, 12); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk1_pin, bb_clk1_a_pin, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk2_pin, bb_clk2_a_pin, 2); + +static struct clk_smd_rpm *msm8976_clks[] = { + [RPM_SMD_PCNOC_CLK] = &msm8976_pcnoc_clk, + [RPM_SMD_PCNOC_A_CLK] = &msm8976_pcnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &msm8976_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8976_snoc_a_clk, + [RPM_SMD_BIMC_CLK] = &msm8976_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &msm8976_bimc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8976_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8976_qdss_a_clk, + [RPM_SMD_BB_CLK1] = &msm8976_bb_clk1, + [RPM_SMD_BB_CLK1_A] = &msm8976_bb_clk1_a, + [RPM_SMD_BB_CLK2] = &msm8976_bb_clk2, + [RPM_SMD_BB_CLK2_A] = &msm8976_bb_clk2_a, + [RPM_SMD_RF_CLK2] = &msm8976_rf_clk2, + [RPM_SMD_RF_CLK2_A] = &msm8976_rf_clk2_a, + [RPM_SMD_BB_CLK1_PIN] = &msm8976_bb_clk1_pin, + [RPM_SMD_BB_CLK1_A_PIN] = &msm8976_bb_clk1_a_pin, + [RPM_SMD_BB_CLK2_PIN] = &msm8976_bb_clk2_pin, + [RPM_SMD_BB_CLK2_A_PIN] = &msm8976_bb_clk2_a_pin, + [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8976_mmssnoc_ahb_clk, + [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8976_mmssnoc_ahb_a_clk, + [RPM_SMD_DIV_CLK2] = &msm8976_div_clk2, + [RPM_SMD_DIV_A_CLK2] = &msm8976_div_clk2_a, + [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk, + [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8976 = { + .clks = msm8976_clks, + .num_clks = ARRAY_SIZE(msm8976_clks), +}; + /* msm8996 */ DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); @@ -720,6 +769,7 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = { static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, + { .compatible = "qcom,rpmcc-msm8976", .data = &rpm_clk_msm8976 }, { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 }, { .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 }, { .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 }, From cd5d5d8dec5e08e3e6ded9fa8366750a203b1d2a Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 31 Oct 2019 12:29:51 +0100 Subject: [PATCH 230/809] dt-bindings: clock: rpmcc: Document msm8976 compatible Support for MSM8976 was added to the clk-smd-rpm driver: let's document here the newly added compatible string. Signed-off-by: AngeloGioacchino Del Regno Link: https://lkml.kernel.org/r/20191031112951.35850-3-kholk11@gmail.com Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/qcom,rpmcc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt index 944719bd586f..356cabcd844d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt @@ -14,6 +14,7 @@ Required properties : "qcom,rpmcc-apq8060", "qcom,rpmcc" "qcom,rpmcc-msm8916", "qcom,rpmcc" "qcom,rpmcc-msm8974", "qcom,rpmcc" + "qcom,rpmcc-msm8976", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc" "qcom,rpmcc-msm8996", "qcom,rpmcc" "qcom,rpmcc-msm8998", "qcom,rpmcc" From 57d98e8e75bd6137a4e993913464c07802593d03 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 24 Feb 2020 10:19:59 +0530 Subject: [PATCH 231/809] clk: qcom: clk-alpha-pll: Use common names for defines The PLL run and standby modes are similar across the PLLs, thus rename them to common names and update the use of these. Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Vinod Koul Link: https://lkml.kernel.org/r/20200224045003.3783838-2-vkoul@kernel.org Reviewed-by: Bryan O'Donoghue Tested-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 40 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 6d946770a80f..0bdf6e45fac9 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -134,15 +134,10 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define PLL_HUAYRA_N_MASK 0xff #define PLL_HUAYRA_ALPHA_WIDTH 16 -#define FABIA_OPMODE_STANDBY 0x0 -#define FABIA_OPMODE_RUN 0x1 - -#define FABIA_PLL_OUT_MASK 0x7 -#define FABIA_PLL_RATE_MARGIN 500 - -#define TRION_PLL_STANDBY 0x0 -#define TRION_PLL_RUN 0x1 -#define TRION_PLL_OUT_MASK 0x7 +#define PLL_STANDBY 0x0 +#define PLL_RUN 0x1 +#define PLL_OUT_MASK 0x7 +#define PLL_RATE_MARGIN 500 #define pll_alpha_width(p) \ ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \ @@ -766,7 +761,7 @@ static int trion_pll_is_enabled(struct clk_alpha_pll *pll, if (ret) return 0; - return ((opmode_regval & TRION_PLL_RUN) && (mode_regval & PLL_OUTCTRL)); + return ((opmode_regval & PLL_RUN) && (mode_regval & PLL_OUTCTRL)); } static int clk_trion_pll_is_enabled(struct clk_hw *hw) @@ -796,7 +791,7 @@ static int clk_trion_pll_enable(struct clk_hw *hw) } /* Set operation mode to RUN */ - regmap_write(regmap, PLL_OPMODE(pll), TRION_PLL_RUN); + regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN); ret = wait_for_pll_enable_lock(pll); if (ret) @@ -804,7 +799,7 @@ static int clk_trion_pll_enable(struct clk_hw *hw) /* Enable the PLL outputs */ ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), - TRION_PLL_OUT_MASK, TRION_PLL_OUT_MASK); + PLL_OUT_MASK, PLL_OUT_MASK); if (ret) return ret; @@ -837,12 +832,12 @@ static void clk_trion_pll_disable(struct clk_hw *hw) /* Disable the PLL outputs */ ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), - TRION_PLL_OUT_MASK, 0); + PLL_OUT_MASK, 0); if (ret) return; /* Place the PLL mode in STANDBY */ - regmap_write(regmap, PLL_OPMODE(pll), TRION_PLL_STANDBY); + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); } @@ -1089,14 +1084,14 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw) return ret; /* Skip If PLL is already running */ - if ((opmode_val & FABIA_OPMODE_RUN) && (val & PLL_OUTCTRL)) + if ((opmode_val & PLL_RUN) && (val & PLL_OUTCTRL)) return 0; ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); if (ret) return ret; - ret = regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_STANDBY); + ret = regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); if (ret) return ret; @@ -1105,7 +1100,7 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw) if (ret) return ret; - ret = regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_RUN); + ret = regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN); if (ret) return ret; @@ -1114,7 +1109,7 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw) return ret; ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), - FABIA_PLL_OUT_MASK, FABIA_PLL_OUT_MASK); + PLL_OUT_MASK, PLL_OUT_MASK); if (ret) return ret; @@ -1144,13 +1139,12 @@ static void alpha_pll_fabia_disable(struct clk_hw *hw) return; /* Disable main outputs */ - ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), FABIA_PLL_OUT_MASK, - 0); + ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, 0); if (ret) return; /* Place the PLL in STANDBY */ - regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_STANDBY); + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); } static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw, @@ -1171,7 +1165,7 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, alpha_width = pll_alpha_width(pll); u64 a; - unsigned long rrate, max = rate + FABIA_PLL_RATE_MARGIN; + unsigned long rrate, max = rate + PLL_RATE_MARGIN; rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); @@ -1230,7 +1224,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw) * Due to a limited number of bits for fractional rate programming, the * rounded up rate could be marginally higher than the requested rate. */ - if (rrate > (cal_freq + FABIA_PLL_RATE_MARGIN) || rrate < cal_freq) + if (rrate > (cal_freq + PLL_RATE_MARGIN) || rrate < cal_freq) return -EINVAL; /* Setup PLL for calibration frequency */ From ee4adbbc9087eb22bca631fb6efb93c62f1761b1 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 24 Feb 2020 10:20:00 +0530 Subject: [PATCH 232/809] clk: qcom: clk-alpha-pll: Refactor trion PLL Remove duplicate function for calculating the round rate of PLL and also update the trion pll ops to use the common function. Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Vinod Koul Link: https://lkml.kernel.org/r/20200224045003.3783838-3-vkoul@kernel.org Reviewed-by: Bryan O'Donoghue Tested-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 33 ++++++-------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 0bdf6e45fac9..0adec585eb4f 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -845,33 +845,12 @@ static unsigned long clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - struct regmap *regmap = pll->clkr.regmap; - u32 l, frac; - u64 prate = parent_rate; + u32 l, frac, alpha_width = pll_alpha_width(pll); - regmap_read(regmap, PLL_L_VAL(pll), &l); - regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac); + regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); - return alpha_pll_calc_rate(prate, l, frac, ALPHA_REG_16BIT_WIDTH); -} - -static long clk_trion_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - unsigned long min_freq, max_freq; - u32 l; - u64 a; - - rate = alpha_pll_round_rate(rate, *prate, - &l, &a, ALPHA_REG_16BIT_WIDTH); - if (!pll->vco_table || alpha_pll_find_vco(pll, rate)) - return rate; - - min_freq = pll->vco_table[0].min_freq; - max_freq = pll->vco_table[pll->num_vco - 1].max_freq; - - return clamp(rate, min_freq, max_freq); + return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); } const struct clk_ops clk_alpha_pll_fixed_ops = { @@ -917,7 +896,7 @@ const struct clk_ops clk_trion_fixed_pll_ops = { .disable = clk_trion_pll_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_trion_pll_round_rate, + .round_rate = clk_alpha_pll_round_rate, }; EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops); @@ -1173,7 +1152,7 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, * Due to limited number of bits for fractional rate programming, the * rounded up rate could be marginally higher than the requested rate. */ - if (rrate > max || rrate < rate) { + if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) { pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n", clk_hw_get_name(hw), rrate, rate, max); return -EINVAL; From 59128c20a6a98ee454e5ad23fe28dc84d23b6234 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 24 Feb 2020 10:20:01 +0530 Subject: [PATCH 233/809] clk: qcom: clk-alpha-pll: Add support for controlling Lucid PLLs Add programming sequence support for managing the Lucid PLLs. Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Vinod Koul Link: https://lkml.kernel.org/r/20200224045003.3783838-4-vkoul@kernel.org Reviewed-by: Bryan O'Donoghue Tested-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 193 +++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 12 ++ 2 files changed, 205 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 0adec585eb4f..9b2dfa08acb2 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -52,6 +52,7 @@ #define PLL_CONFIG_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U1]) #define PLL_TEST_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL]) #define PLL_TEST_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U]) +#define PLL_TEST_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U1]) #define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS]) #define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE]) #define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC]) @@ -116,6 +117,22 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_ALPHA_VAL] = 0x40, [PLL_OFF_CAL_VAL] = 0x44, }, + [CLK_ALPHA_PLL_TYPE_LUCID] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_CAL_L_VAL] = 0x08, + [PLL_OFF_USER_CTL] = 0x0c, + [PLL_OFF_USER_CTL_U] = 0x10, + [PLL_OFF_USER_CTL_U1] = 0x14, + [PLL_OFF_CONFIG_CTL] = 0x18, + [PLL_OFF_CONFIG_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL_U1] = 0x20, + [PLL_OFF_TEST_CTL] = 0x24, + [PLL_OFF_TEST_CTL_U] = 0x28, + [PLL_OFF_TEST_CTL_U1] = 0x2c, + [PLL_OFF_STATUS] = 0x30, + [PLL_OFF_OPMODE] = 0x38, + [PLL_OFF_ALPHA_VAL] = 0x40, + }, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); @@ -139,6 +156,10 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define PLL_OUT_MASK 0x7 #define PLL_RATE_MARGIN 500 +/* LUCID PLL specific settings and offsets */ +#define LUCID_PLL_CAL_VAL 0x44 +#define LUCID_PCAL_DONE BIT(26) + #define pll_alpha_width(p) \ ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \ ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH) @@ -1370,3 +1391,175 @@ const struct clk_ops clk_alpha_pll_postdiv_fabia_ops = { .set_rate = clk_alpha_pll_postdiv_fabia_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops); + +/** + * clk_lucid_pll_configure - configure the lucid pll + * + * @pll: clk alpha pll + * @regmap: register map + * @config: configuration to apply for pll + */ +void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + if (config->l) + regmap_write(regmap, PLL_L_VAL(pll), config->l); + + regmap_write(regmap, PLL_CAL_L_VAL(pll), LUCID_PLL_CAL_VAL); + + if (config->alpha) + regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha); + + if (config->config_ctl_val) + regmap_write(regmap, PLL_CONFIG_CTL(pll), + config->config_ctl_val); + + if (config->config_ctl_hi_val) + regmap_write(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + + if (config->config_ctl_hi1_val) + regmap_write(regmap, PLL_CONFIG_CTL_U1(pll), + config->config_ctl_hi1_val); + + if (config->user_ctl_val) + regmap_write(regmap, PLL_USER_CTL(pll), + config->user_ctl_val); + + if (config->user_ctl_hi_val) + regmap_write(regmap, PLL_USER_CTL_U(pll), + config->user_ctl_hi_val); + + if (config->user_ctl_hi1_val) + regmap_write(regmap, PLL_USER_CTL_U1(pll), + config->user_ctl_hi1_val); + + if (config->test_ctl_val) + regmap_write(regmap, PLL_TEST_CTL(pll), + config->test_ctl_val); + + if (config->test_ctl_hi_val) + regmap_write(regmap, PLL_TEST_CTL_U(pll), + config->test_ctl_hi_val); + + if (config->test_ctl_hi1_val) + regmap_write(regmap, PLL_TEST_CTL_U1(pll), + config->test_ctl_hi1_val); + + regmap_update_bits(regmap, PLL_MODE(pll), PLL_UPDATE_BYPASS, + PLL_UPDATE_BYPASS); + + /* Disable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); + + /* Set operation mode to OFF */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); + + /* Place the PLL in STANDBY mode */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); +} +EXPORT_SYMBOL_GPL(clk_lucid_pll_configure); + +/* + * The Lucid PLL requires a power-on self-calibration which happens when the + * PLL comes out of reset. Calibrate in case it is not completed. + */ +static int alpha_pll_lucid_prepare(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 regval; + int ret; + + /* Return early if calibration is not needed. */ + regmap_read(pll->clkr.regmap, PLL_STATUS(pll), ®val); + if (regval & LUCID_PCAL_DONE) + return 0; + + /* On/off to calibrate */ + ret = clk_trion_pll_enable(hw); + if (!ret) + clk_trion_pll_disable(hw); + + return ret; +} + +static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long rrate; + u32 regval, l, alpha_width = pll_alpha_width(pll); + u64 a; + int ret; + + rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); + + /* + * Due to a limited number of bits for fractional rate programming, the + * rounded up rate could be marginally higher than the requested rate. + */ + if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) { + pr_err("Call set rate on the PLL with rounded rates!\n"); + return -EINVAL; + } + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + + /* Latch the PLL input */ + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), + PLL_UPDATE, PLL_UPDATE); + if (ret) + return ret; + + /* Wait for 2 reference cycles before checking the ACK bit. */ + udelay(1); + regmap_read(pll->clkr.regmap, PLL_MODE(pll), ®val); + if (!(regval & ALPHA_PLL_ACK_LATCH)) { + pr_err("Lucid PLL latch failed. Output may be unstable!\n"); + return -EINVAL; + } + + /* Return the latch input to 0 */ + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), + PLL_UPDATE, 0); + if (ret) + return ret; + + if (clk_hw_is_enabled(hw)) { + ret = wait_for_pll_enable_lock(pll); + if (ret) + return ret; + } + + /* Wait for PLL output to stabilize */ + udelay(100); + return 0; +} + +const struct clk_ops clk_alpha_pll_lucid_ops = { + .prepare = alpha_pll_lucid_prepare, + .enable = clk_trion_pll_enable, + .disable = clk_trion_pll_disable, + .is_enabled = clk_trion_pll_is_enabled, + .recalc_rate = clk_trion_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = alpha_pll_lucid_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops); + +const struct clk_ops clk_alpha_pll_fixed_lucid_ops = { + .enable = clk_trion_pll_enable, + .disable = clk_trion_pll_disable, + .is_enabled = clk_trion_pll_is_enabled, + .recalc_rate = clk_trion_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_ops); + +const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = { + .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, + .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, + .set_rate = clk_alpha_pll_postdiv_fabia_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index fbc1f67c7a26..704674a153b6 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -14,6 +14,7 @@ enum { CLK_ALPHA_PLL_TYPE_BRAMMO, CLK_ALPHA_PLL_TYPE_FABIA, CLK_ALPHA_PLL_TYPE_TRION, + CLK_ALPHA_PLL_TYPE_LUCID, CLK_ALPHA_PLL_TYPE_MAX, }; @@ -30,6 +31,7 @@ enum { PLL_OFF_CONFIG_CTL_U1, PLL_OFF_TEST_CTL, PLL_OFF_TEST_CTL_U, + PLL_OFF_TEST_CTL_U1, PLL_OFF_STATUS, PLL_OFF_OPMODE, PLL_OFF_FRAC, @@ -94,10 +96,13 @@ struct alpha_pll_config { u32 alpha_hi; u32 config_ctl_val; u32 config_ctl_hi_val; + u32 config_ctl_hi1_val; u32 user_ctl_val; u32 user_ctl_hi_val; + u32 user_ctl_hi1_val; u32 test_ctl_val; u32 test_ctl_hi_val; + u32 test_ctl_hi1_val; u32 main_output_mask; u32 aux_output_mask; u32 aux2_output_mask; @@ -123,10 +128,17 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops; +extern const struct clk_ops clk_alpha_pll_lucid_ops; +extern const struct clk_ops clk_alpha_pll_fixed_lucid_ops; +extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops; + void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); +void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); + extern const struct clk_ops clk_trion_fixed_pll_ops; extern const struct clk_ops clk_trion_pll_postdiv_ops; From 98394efb48f51560fda86ed12f5d4e391629755f Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 24 Feb 2020 10:20:02 +0530 Subject: [PATCH 234/809] dt-bindings: clock: Add SM8250 GCC clock bindings Add device tree bindings for global clock controller on SM8250 SoCs. Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Vinod Koul Link: https://lkml.kernel.org/r/20200224045003.3783838-5-vkoul@kernel.org Reviewed-by: Rob Herring Reviewed-by: Bryan O'Donoghue Tested-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,gcc-sm8250.yaml | 72 +++++ include/dt-bindings/clock/qcom,gcc-sm8250.h | 271 ++++++++++++++++++ 2 files changed, 343 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc-sm8250.yaml create mode 100644 include/dt-bindings/clock/qcom,gcc-sm8250.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-sm8250.yaml new file mode 100644 index 000000000000..2c40a8aa9815 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-sm8250.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,gcc-sm8250.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller Binding for SM8250 + +maintainers: + - Stephen Boyd + - Taniya Das + +description: | + Qualcomm global clock control module which supports the clocks, resets and + power domains on SM8250. + + See also: + - dt-bindings/clock/qcom,gcc-sm8250.h + +properties: + compatible: + const: qcom,gcc-sm8250 + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + + clock-names: + items: + - const: bi_tcxo + - const: sleep_clk + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + + protected-clocks: + description: + Protected clock specifier list as per common clock binding. + +required: + - compatible + - clocks + - clock-names + - reg + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,gcc-sm8250"; + reg = <0 0x00100000 0 0x1f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>; + clock-names = "bi_tcxo", "sleep_clk"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,gcc-sm8250.h b/include/dt-bindings/clock/qcom,gcc-sm8250.h new file mode 100644 index 000000000000..7b7abe327e37 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-sm8250.h @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SM8250_H +#define _DT_BINDINGS_CLK_QCOM_GCC_SM8250_H + +/* GCC clocks */ +#define GPLL0 0 +#define GPLL0_OUT_EVEN 1 +#define GPLL4 2 +#define GPLL9 3 +#define GCC_AGGRE_NOC_PCIE_TBU_CLK 4 +#define GCC_AGGRE_UFS_CARD_AXI_CLK 5 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 6 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 7 +#define GCC_AGGRE_USB3_SEC_AXI_CLK 8 +#define GCC_BOOT_ROM_AHB_CLK 9 +#define GCC_CAMERA_AHB_CLK 10 +#define GCC_CAMERA_HF_AXI_CLK 11 +#define GCC_CAMERA_SF_AXI_CLK 12 +#define GCC_CAMERA_XO_CLK 13 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 14 +#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 15 +#define GCC_CPUSS_AHB_CLK 16 +#define GCC_CPUSS_AHB_CLK_SRC 17 +#define GCC_CPUSS_AHB_POSTDIV_CLK_SRC 18 +#define GCC_CPUSS_DVM_BUS_CLK 19 +#define GCC_CPUSS_RBCPR_CLK 20 +#define GCC_DDRSS_GPU_AXI_CLK 21 +#define GCC_DDRSS_PCIE_SF_TBU_CLK 22 +#define GCC_DISP_AHB_CLK 23 +#define GCC_DISP_HF_AXI_CLK 24 +#define GCC_DISP_SF_AXI_CLK 25 +#define GCC_DISP_XO_CLK 26 +#define GCC_GP1_CLK 27 +#define GCC_GP1_CLK_SRC 28 +#define GCC_GP2_CLK 29 +#define GCC_GP2_CLK_SRC 30 +#define GCC_GP3_CLK 31 +#define GCC_GP3_CLK_SRC 32 +#define GCC_GPU_CFG_AHB_CLK 33 +#define GCC_GPU_GPLL0_CLK_SRC 34 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 35 +#define GCC_GPU_IREF_EN 36 +#define GCC_GPU_MEMNOC_GFX_CLK 37 +#define GCC_GPU_SNOC_DVM_GFX_CLK 38 +#define GCC_NPU_AXI_CLK 39 +#define GCC_NPU_BWMON_AXI_CLK 40 +#define GCC_NPU_BWMON_CFG_AHB_CLK 41 +#define GCC_NPU_CFG_AHB_CLK 42 +#define GCC_NPU_DMA_CLK 43 +#define GCC_NPU_GPLL0_CLK_SRC 44 +#define GCC_NPU_GPLL0_DIV_CLK_SRC 45 +#define GCC_PCIE0_PHY_REFGEN_CLK 46 +#define GCC_PCIE1_PHY_REFGEN_CLK 47 +#define GCC_PCIE2_PHY_REFGEN_CLK 48 +#define GCC_PCIE_0_AUX_CLK 49 +#define GCC_PCIE_0_AUX_CLK_SRC 50 +#define GCC_PCIE_0_CFG_AHB_CLK 51 +#define GCC_PCIE_0_MSTR_AXI_CLK 52 +#define GCC_PCIE_0_PIPE_CLK 53 +#define GCC_PCIE_0_SLV_AXI_CLK 54 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 55 +#define GCC_PCIE_1_AUX_CLK 56 +#define GCC_PCIE_1_AUX_CLK_SRC 57 +#define GCC_PCIE_1_CFG_AHB_CLK 58 +#define GCC_PCIE_1_MSTR_AXI_CLK 59 +#define GCC_PCIE_1_PIPE_CLK 60 +#define GCC_PCIE_1_SLV_AXI_CLK 61 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 62 +#define GCC_PCIE_2_AUX_CLK 63 +#define GCC_PCIE_2_AUX_CLK_SRC 64 +#define GCC_PCIE_2_CFG_AHB_CLK 65 +#define GCC_PCIE_2_MSTR_AXI_CLK 66 +#define GCC_PCIE_2_PIPE_CLK 67 +#define GCC_PCIE_2_SLV_AXI_CLK 68 +#define GCC_PCIE_2_SLV_Q2A_AXI_CLK 69 +#define GCC_PCIE_MDM_CLKREF_EN 70 +#define GCC_PCIE_PHY_AUX_CLK 71 +#define GCC_PCIE_PHY_REFGEN_CLK_SRC 72 +#define GCC_PCIE_WIFI_CLKREF_EN 73 +#define GCC_PCIE_WIGIG_CLKREF_EN 74 +#define GCC_PDM2_CLK 75 +#define GCC_PDM2_CLK_SRC 76 +#define GCC_PDM_AHB_CLK 77 +#define GCC_PDM_XO4_CLK 78 +#define GCC_PRNG_AHB_CLK 79 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 80 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 81 +#define GCC_QMIP_DISP_AHB_CLK 82 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 83 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 84 +#define GCC_QUPV3_WRAP0_CORE_2X_CLK 85 +#define GCC_QUPV3_WRAP0_CORE_CLK 86 +#define GCC_QUPV3_WRAP0_S0_CLK 87 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 88 +#define GCC_QUPV3_WRAP0_S1_CLK 89 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 90 +#define GCC_QUPV3_WRAP0_S2_CLK 91 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 92 +#define GCC_QUPV3_WRAP0_S3_CLK 93 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 94 +#define GCC_QUPV3_WRAP0_S4_CLK 95 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 96 +#define GCC_QUPV3_WRAP0_S5_CLK 97 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 98 +#define GCC_QUPV3_WRAP0_S6_CLK 99 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 100 +#define GCC_QUPV3_WRAP0_S7_CLK 101 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 102 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 103 +#define GCC_QUPV3_WRAP1_CORE_CLK 104 +#define GCC_QUPV3_WRAP1_S0_CLK 105 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 106 +#define GCC_QUPV3_WRAP1_S1_CLK 107 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 108 +#define GCC_QUPV3_WRAP1_S2_CLK 109 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 110 +#define GCC_QUPV3_WRAP1_S3_CLK 111 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 112 +#define GCC_QUPV3_WRAP1_S4_CLK 113 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 114 +#define GCC_QUPV3_WRAP1_S5_CLK 115 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 116 +#define GCC_QUPV3_WRAP2_CORE_2X_CLK 117 +#define GCC_QUPV3_WRAP2_CORE_CLK 118 +#define GCC_QUPV3_WRAP2_S0_CLK 119 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 120 +#define GCC_QUPV3_WRAP2_S1_CLK 121 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 122 +#define GCC_QUPV3_WRAP2_S2_CLK 123 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 124 +#define GCC_QUPV3_WRAP2_S3_CLK 125 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 126 +#define GCC_QUPV3_WRAP2_S4_CLK 127 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 128 +#define GCC_QUPV3_WRAP2_S5_CLK 129 +#define GCC_QUPV3_WRAP2_S5_CLK_SRC 130 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 131 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 132 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 133 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 134 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 135 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 136 +#define GCC_SDCC2_AHB_CLK 137 +#define GCC_SDCC2_APPS_CLK 138 +#define GCC_SDCC2_APPS_CLK_SRC 139 +#define GCC_SDCC4_AHB_CLK 140 +#define GCC_SDCC4_APPS_CLK 141 +#define GCC_SDCC4_APPS_CLK_SRC 142 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 143 +#define GCC_TSIF_AHB_CLK 144 +#define GCC_TSIF_INACTIVITY_TIMERS_CLK 145 +#define GCC_TSIF_REF_CLK 146 +#define GCC_TSIF_REF_CLK_SRC 147 +#define GCC_UFS_1X_CLKREF_EN 148 +#define GCC_UFS_CARD_AHB_CLK 149 +#define GCC_UFS_CARD_AXI_CLK 150 +#define GCC_UFS_CARD_AXI_CLK_SRC 151 +#define GCC_UFS_CARD_ICE_CORE_CLK 152 +#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 153 +#define GCC_UFS_CARD_PHY_AUX_CLK 154 +#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 155 +#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 156 +#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 157 +#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 158 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK 159 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 160 +#define GCC_UFS_PHY_AHB_CLK 161 +#define GCC_UFS_PHY_AXI_CLK 162 +#define GCC_UFS_PHY_AXI_CLK_SRC 163 +#define GCC_UFS_PHY_ICE_CORE_CLK 164 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 165 +#define GCC_UFS_PHY_PHY_AUX_CLK 166 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 167 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 168 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 169 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 170 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 171 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 172 +#define GCC_USB30_PRIM_MASTER_CLK 173 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 174 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 175 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 176 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 177 +#define GCC_USB30_PRIM_SLEEP_CLK 178 +#define GCC_USB30_SEC_MASTER_CLK 179 +#define GCC_USB30_SEC_MASTER_CLK_SRC 180 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 181 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 182 +#define GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC 183 +#define GCC_USB30_SEC_SLEEP_CLK 184 +#define GCC_USB3_PRIM_PHY_AUX_CLK 185 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 186 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 187 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 188 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 189 +#define GCC_USB3_SEC_CLKREF_EN 190 +#define GCC_USB3_SEC_PHY_AUX_CLK 191 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 192 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 193 +#define GCC_USB3_SEC_PHY_PIPE_CLK 194 +#define GCC_USB3_SEC_PHY_PIPE_CLK_SRC 195 +#define GCC_VIDEO_AHB_CLK 196 +#define GCC_VIDEO_AXI0_CLK 197 +#define GCC_VIDEO_AXI1_CLK 198 +#define GCC_VIDEO_XO_CLK 199 + +/* GCC resets */ +#define GCC_GPU_BCR 0 +#define GCC_MMSS_BCR 1 +#define GCC_NPU_BWMON_BCR 2 +#define GCC_NPU_BCR 3 +#define GCC_PCIE_0_BCR 4 +#define GCC_PCIE_0_LINK_DOWN_BCR 5 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 6 +#define GCC_PCIE_0_PHY_BCR 7 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 8 +#define GCC_PCIE_1_BCR 9 +#define GCC_PCIE_1_LINK_DOWN_BCR 10 +#define GCC_PCIE_1_NOCSR_COM_PHY_BCR 11 +#define GCC_PCIE_1_PHY_BCR 12 +#define GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR 13 +#define GCC_PCIE_2_BCR 14 +#define GCC_PCIE_2_LINK_DOWN_BCR 15 +#define GCC_PCIE_2_NOCSR_COM_PHY_BCR 16 +#define GCC_PCIE_2_PHY_BCR 17 +#define GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR 18 +#define GCC_PCIE_PHY_BCR 19 +#define GCC_PCIE_PHY_CFG_AHB_BCR 20 +#define GCC_PCIE_PHY_COM_BCR 21 +#define GCC_PDM_BCR 22 +#define GCC_PRNG_BCR 23 +#define GCC_QUPV3_WRAPPER_0_BCR 24 +#define GCC_QUPV3_WRAPPER_1_BCR 25 +#define GCC_QUPV3_WRAPPER_2_BCR 26 +#define GCC_QUSB2PHY_PRIM_BCR 27 +#define GCC_QUSB2PHY_SEC_BCR 28 +#define GCC_SDCC2_BCR 29 +#define GCC_SDCC4_BCR 30 +#define GCC_TSIF_BCR 31 +#define GCC_UFS_CARD_BCR 32 +#define GCC_UFS_PHY_BCR 33 +#define GCC_USB30_PRIM_BCR 34 +#define GCC_USB30_SEC_BCR 35 +#define GCC_USB3_DP_PHY_PRIM_BCR 36 +#define GCC_USB3_DP_PHY_SEC_BCR 37 +#define GCC_USB3_PHY_PRIM_BCR 38 +#define GCC_USB3_PHY_SEC_BCR 39 +#define GCC_USB3PHY_PHY_PRIM_BCR 40 +#define GCC_USB3PHY_PHY_SEC_BCR 41 +#define GCC_USB_PHY_CFG_AHB2PHY_BCR 42 +#define GCC_VIDEO_AXI0_CLK_ARES 43 +#define GCC_VIDEO_AXI1_CLK_ARES 44 + +/* GCC power domains */ +#define PCIE_0_GDSC 0 +#define PCIE_1_GDSC 1 +#define PCIE_2_GDSC 2 +#define UFS_CARD_GDSC 3 +#define UFS_PHY_GDSC 4 +#define USB30_PRIM_GDSC 5 +#define USB30_SEC_GDSC 6 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 7 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 8 +#define HLOS1_VOTE_MMNOC_MMU_TBU_SF0_GDSC 9 +#define HLOS1_VOTE_MMNOC_MMU_TBU_SF1_GDSC 10 + +#endif From 3e5770921a8846ed1071257398eb7cd369399412 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 24 Feb 2020 10:20:03 +0530 Subject: [PATCH 235/809] clk: qcom: gcc: Add global clock controller driver for SM8250 Add the clocks supported in global clock controller, which clock the peripherals like BLSPs, SDCC, USB, MDSS etc. Register all the clocks to the clock framework for the clients to be able to request for them. Signed-off-by: Taniya Das Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Vinod Koul Link: https://lkml.kernel.org/r/20200224045003.3783838-6-vkoul@kernel.org Reviewed-by: Bryan O'Donoghue Tested-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 7 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sm8250.c | 3690 +++++++++++++++++++++++++++++++++ 3 files changed, 3698 insertions(+) create mode 100644 drivers/clk/qcom/gcc-sm8250.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 15cdcdc9b3b8..af406a7c4aca 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -366,6 +366,13 @@ config SM_GCC_8150 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS, PCIe etc. +config SM_GCC_8250 + tristate "SM8250 Global Clock Controller" + help + Support for the global clock controller on SM8250 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on SPMI || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 656a87e629d4..bd6556b829c0 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o +obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o diff --git a/drivers/clk/qcom/gcc-sm8250.c b/drivers/clk/qcom/gcc-sm8250.c new file mode 100644 index 000000000000..6cb6617b8d88 --- /dev/null +++ b/drivers/clk/qcom/gcc-sm8250.c @@ -0,0 +1,3690 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_AUD_REF_CLK, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_EVEN, + P_GPLL0_OUT_MAIN, + P_GPLL4_OUT_MAIN, + P_GPLL9_OUT_MAIN, + P_SLEEP_CLK, +}; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0_out_even", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct clk_alpha_pll gpll4 = { + .offset = 0x76000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll9 = { + .offset = 0x1c000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gpll9", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct clk_parent_data gcc_parent_data_0_ao[] = { + { .fw_name = "bi_tcxo_ao" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .fw_name = "sleep_clk" }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .fw_name = "bi_tcxo" }, + { .fw_name = "sleep_clk" }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .fw_name = "bi_tcxo" }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL9_OUT_MAIN, 2 }, + { P_GPLL4_OUT_MAIN, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll9.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_AUD_REF_CLK, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .fw_name = "aud_ref_clk" }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { + .cmd_rcgr = 0x48010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_data = gcc_parent_data_0_ao, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x6b038, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x8d038, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_aux_clk_src = { + .cmd_rcgr = 0x6038, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_phy_refgen_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { + .cmd_rcgr = 0x6f014, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_phy_refgen_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_refgen_clk_src", + .parent_data = gcc_parent_data_0_ao, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GPLL0_OUT_EVEN, 2.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x17010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x17140, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x17270, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x173a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x174d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { + .name = "gcc_qupv3_wrap0_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x17600, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = { + .name = "gcc_qupv3_wrap0_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { + .cmd_rcgr = 0x17730, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = { + .name = "gcc_qupv3_wrap0_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x17860, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18140, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x18270, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x183a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x184d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18600, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { + .name = "gcc_qupv3_wrap2_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e140, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = { + .name = "gcc_qupv3_wrap2_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e270, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = { + .name = "gcc_qupv3_wrap2_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { + .name = "gcc_qupv3_wrap2_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e4d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = { + .name = "gcc_qupv3_wrap2_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0x1e600, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(202000000, P_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x1400c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x1600c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_tsif_ref_clk_src[] = { + F(105495, P_BI_TCXO, 2, 1, 91), + { } +}; + +static struct clk_rcg2 gcc_tsif_ref_clk_src = { + .cmd_rcgr = 0x36010, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_tsif_ref_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ref_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_card_axi_clk_src = { + .cmd_rcgr = 0x75024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_axi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_ice_core_clk_src[] = { + F(37500000, P_GPLL0_OUT_EVEN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_card_ice_core_clk_src = { + .cmd_rcgr = 0x7506c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_ice_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_phy_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_card_phy_aux_clk_src = { + .cmd_rcgr = 0x750a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_unipro_core_clk_src[] = { + F(37500000, P_GPLL0_OUT_EVEN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_card_unipro_core_clk_src = { + .cmd_rcgr = 0x75084, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_unipro_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_unipro_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(37500000, P_GPLL0_OUT_EVEN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x7706c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77084, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0), + F(66666667, P_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0xf020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0xf038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_master_clk_src = { + .cmd_rcgr = 0x10020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sec_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { + .cmd_rcgr = 0x10038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sec_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0xf064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { + .cmd_rcgr = 0x10064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div gcc_cpuss_ahb_postdiv_clk_src = { + .reg = 0x48028, + .shift = 0, + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gcc_cpuss_ahb_postdiv_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_cpuss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0xf050, + .shift = 0, + .width = 2, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_sec_mock_utmi_postdiv_clk_src = { + .reg = 0x10050, + .shift = 0, + .width = 2, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_postdiv_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_sec_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_tbu_clk = { + .halt_reg = 0x9000c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9000c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_noc_pcie_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_card_axi_clk = { + .halt_reg = 0x750cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x750cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x750cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_card_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_card_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0xf080, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xf080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_sec_axi_clk = { + .halt_reg = 0x10080, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x10080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_usb3_sec_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0xb02c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0xb030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_xo_clk = { + .halt_reg = 0xb040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camera_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0xf07c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xf07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = { + .halt_reg = 0x1007c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x1007c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cfg_noc_usb3_sec_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_ahb_clk = { + .halt_reg = 0x48000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_cpuss_ahb_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_rbcpr_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x48004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x71154, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x71154, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_pcie_sf_tbu_clk = { + .halt_reg = 0x8d058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ddrss_pcie_sf_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0xb034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_sf_axi_clk = { + .halt_reg = 0xb038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_xo_clk = { + .halt_reg = 0xb044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_gpll0_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(16), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_iref_en = { + .halt_reg = 0x8c014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_iref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x7100c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7100c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_axi_clk = { + .halt_reg = 0x4d008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4d008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_bwmon_axi_clk = { + .halt_reg = 0x73008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x73008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_bwmon_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_bwmon_cfg_ahb_clk = { + .halt_reg = 0x73004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x73004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_bwmon_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_cfg_ahb_clk = { + .halt_reg = 0x4d004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x4d004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4d004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_dma_clk = { + .halt_reg = 0x4d00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4d00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_dma_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(18), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_gpll0_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(19), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_gpll0_div_clk_src", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_phy_refgen_clk = { + .halt_reg = 0x6f02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_phy_refgen_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_phy_refgen_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_phy_refgen_clk = { + .halt_reg = 0x6f030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_phy_refgen_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_phy_refgen_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_phy_refgen_clk = { + .halt_reg = 0x6f034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie2_phy_refgen_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_phy_refgen_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x6b028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x6b024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x6b02c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x6b014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0x6b010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x8d028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(29), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0x8d024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(28), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(27), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x8d02c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(30), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x8d014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0x8d010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(25), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_aux_clk = { + .halt_reg = 0x6028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { + .halt_reg = 0x6024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_mstr_axi_clk = { + .halt_reg = 0x601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_pipe_clk = { + .halt_reg = 0x602c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_axi_clk = { + .halt_reg = 0x6014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_q2a_axi_clk = { + .halt_reg = 0x6010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_mdm_clkref_en = { + .halt_reg = 0x8c00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_mdm_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_aux_clk = { + .halt_reg = 0x6f004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_wifi_clkref_en = { + .halt_reg = 0x8c004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_wifi_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_wigig_clkref_en = { + .halt_reg = 0x8c008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_wigig_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x34004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0xb018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_ahb_clk = { + .halt_reg = 0xb020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qmip_disp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0xb010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0xb014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x23008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_clk = { + .halt_reg = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s0_clk = { + .halt_reg = 0x1700c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s1_clk = { + .halt_reg = 0x1713c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s2_clk = { + .halt_reg = 0x1726c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s3_clk = { + .halt_reg = 0x1739c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s4_clk = { + .halt_reg = 0x174cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s4_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s5_clk = { + .halt_reg = 0x175fc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s5_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s6_clk = { + .halt_reg = 0x1772c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(16), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s6_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s7_clk = { + .halt_reg = 0x1785c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s7_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap0_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x23140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(18), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x23138, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(19), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x1800c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x1813c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(23), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x1826c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(24), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x1839c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(25), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x184cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0x185fc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(27), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = { + .halt_reg = 0x23278, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_clk = { + .halt_reg = 0x23270, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0x1e00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s1_clk = { + .halt_reg = 0x1e13c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s2_clk = { + .halt_reg = 0x1e26c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s3_clk = { + .halt_reg = 0x1e39c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s4_clk = { + .halt_reg = 0x1e4cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s4_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s5_clk = { + .halt_reg = 0x1e5fc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap2_s5_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_qupv3_wrap2_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_0_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { + .halt_reg = 0x17008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x17008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_0_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(20), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x18008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x18008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_2_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = { + .halt_reg = 0x1e008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_2_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_apps_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_ahb_clk = { + .halt_reg = 0x36004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x36004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_inactivity_timers_clk = { + .halt_reg = 0x3600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_inactivity_timers_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_ref_clk = { + .halt_reg = 0x36008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ref_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_tsif_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_1x_clkref_en = { + .halt_reg = 0x8c000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_1x_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_ahb_clk = { + .halt_reg = 0x75018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x75018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x75018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_axi_clk = { + .halt_reg = 0x75010, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x75010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x75010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_card_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_ice_core_clk = { + .halt_reg = 0x75064, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x75064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x75064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_ice_core_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_card_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_phy_aux_clk = { + .halt_reg = 0x7509c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7509c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7509c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_phy_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_card_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_rx_symbol_0_clk = { + .halt_reg = 0x75020, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x75020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_rx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_rx_symbol_1_clk = { + .halt_reg = 0x750b8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x750b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_rx_symbol_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_tx_symbol_0_clk = { + .halt_reg = 0x7501c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_tx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_card_unipro_core_clk = { + .halt_reg = 0x7505c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7505c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7505c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_unipro_core_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_card_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x77010, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x77064, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x7709c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7709c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7709c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x77020, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770b8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x770b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x7701c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x7705c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7705c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7705c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0xf010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xf010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_master_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0xf01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0xf018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_master_clk = { + .halt_reg = 0x10010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x10010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sec_master_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_mock_utmi_clk = { + .halt_reg = 0x1001c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1001c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sec_mock_utmi_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = + &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_sleep_clk = { + .halt_reg = 0x10018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sec_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0xf054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0xf058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0xf05c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xf05c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_clkref_en = { + .halt_reg = 0x8c010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_aux_clk = { + .halt_reg = 0x10054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { + .halt_reg = 0x10058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_com_aux_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { + .halt_reg = 0x1005c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1005c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0xb024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0xb028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_xo_clk = { + .halt_reg = 0xb03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_video_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc pcie_0_gdsc = { + .gdscr = 0x6b004, + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie_1_gdsc = { + .gdscr = 0x8d004, + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie_2_gdsc = { + .gdscr = 0x6004, + .pd = { + .name = "pcie_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ufs_card_gdsc = { + .gdscr = 0x75004, + .pd = { + .name = "ufs_card_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ufs_phy_gdsc = { + .gdscr = 0x77004, + .pd = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc usb30_sec_gdsc = { + .gdscr = 0x10004, + .pd = { + .name = "usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { + .gdscr = 0x7d050, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { + .gdscr = 0x7d058, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc = { + .gdscr = 0x7d054, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc = { + .gdscr = 0x7d06c, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct clk_regmap *gcc_sm8250_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CAMERA_XO_CLK] = &gcc_camera_xo_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr, + [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, + [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_AHB_POSTDIV_CLK_SRC] = &gcc_cpuss_ahb_postdiv_clk_src.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_TBU_CLK] = &gcc_ddrss_pcie_sf_tbu_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_DISP_SF_AXI_CLK] = &gcc_disp_sf_axi_clk.clkr, + [GCC_DISP_XO_CLK] = &gcc_disp_xo_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_GPU_IREF_EN] = &gcc_gpu_iref_en.clkr, + [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, + [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_NPU_AXI_CLK] = &gcc_npu_axi_clk.clkr, + [GCC_NPU_BWMON_AXI_CLK] = &gcc_npu_bwmon_axi_clk.clkr, + [GCC_NPU_BWMON_CFG_AHB_CLK] = &gcc_npu_bwmon_cfg_ahb_clk.clkr, + [GCC_NPU_CFG_AHB_CLK] = &gcc_npu_cfg_ahb_clk.clkr, + [GCC_NPU_DMA_CLK] = &gcc_npu_dma_clk.clkr, + [GCC_NPU_GPLL0_CLK_SRC] = &gcc_npu_gpll0_clk_src.clkr, + [GCC_NPU_GPLL0_DIV_CLK_SRC] = &gcc_npu_gpll0_div_clk_src.clkr, + [GCC_PCIE0_PHY_REFGEN_CLK] = &gcc_pcie0_phy_refgen_clk.clkr, + [GCC_PCIE1_PHY_REFGEN_CLK] = &gcc_pcie1_phy_refgen_clk.clkr, + [GCC_PCIE2_PHY_REFGEN_CLK] = &gcc_pcie2_phy_refgen_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr, + [GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr, + [GCC_PCIE_2_AUX_CLK_SRC] = &gcc_pcie_2_aux_clk_src.clkr, + [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr, + [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr, + [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr, + [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr, + [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = &gcc_pcie_2_slv_q2a_axi_clk.clkr, + [GCC_PCIE_MDM_CLKREF_EN] = &gcc_pcie_mdm_clkref_en.clkr, + [GCC_PCIE_PHY_AUX_CLK] = &gcc_pcie_phy_aux_clk.clkr, + [GCC_PCIE_PHY_REFGEN_CLK_SRC] = &gcc_pcie_phy_refgen_clk_src.clkr, + [GCC_PCIE_WIFI_CLKREF_EN] = &gcc_pcie_wifi_clkref_en.clkr, + [GCC_PCIE_WIGIG_CLKREF_EN] = &gcc_pcie_wigig_clkref_en.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr, + [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr, + [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr, + [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr, + [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr, + [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr, + [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr, + [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr, + [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr, + [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr, + [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr, + [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr, + [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr, + [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr, + [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr, + [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr, + [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr, + [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr, + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr, + [GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr, + [GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr, + [GCC_TSIF_REF_CLK_SRC] = &gcc_tsif_ref_clk_src.clkr, + [GCC_UFS_1X_CLKREF_EN] = &gcc_ufs_1x_clkref_en.clkr, + [GCC_UFS_CARD_AHB_CLK] = &gcc_ufs_card_ahb_clk.clkr, + [GCC_UFS_CARD_AXI_CLK] = &gcc_ufs_card_axi_clk.clkr, + [GCC_UFS_CARD_AXI_CLK_SRC] = &gcc_ufs_card_axi_clk_src.clkr, + [GCC_UFS_CARD_ICE_CORE_CLK] = &gcc_ufs_card_ice_core_clk.clkr, + [GCC_UFS_CARD_ICE_CORE_CLK_SRC] = &gcc_ufs_card_ice_core_clk_src.clkr, + [GCC_UFS_CARD_PHY_AUX_CLK] = &gcc_ufs_card_phy_aux_clk.clkr, + [GCC_UFS_CARD_PHY_AUX_CLK_SRC] = &gcc_ufs_card_phy_aux_clk_src.clkr, + [GCC_UFS_CARD_RX_SYMBOL_0_CLK] = &gcc_ufs_card_rx_symbol_0_clk.clkr, + [GCC_UFS_CARD_RX_SYMBOL_1_CLK] = &gcc_ufs_card_rx_symbol_1_clk.clkr, + [GCC_UFS_CARD_TX_SYMBOL_0_CLK] = &gcc_ufs_card_tx_symbol_0_clk.clkr, + [GCC_UFS_CARD_UNIPRO_CORE_CLK] = &gcc_ufs_card_unipro_core_clk.clkr, + [GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = + &gcc_ufs_card_unipro_core_clk_src.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = + &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = + &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK] = &gcc_usb30_sec_master_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK_SRC] = &gcc_usb30_sec_master_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK] = &gcc_usb30_sec_mock_utmi_clk.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = + &gcc_usb30_sec_mock_utmi_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] = + &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_SEC_SLEEP_CLK] = &gcc_usb30_sec_sleep_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_SEC_CLKREF_EN] = &gcc_usb3_sec_clkref_en.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr, + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, + [GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL9] = &gpll9.clkr, +}; + +static struct gdsc *gcc_sm8250_gdscs[] = { + [PCIE_0_GDSC] = &pcie_0_gdsc, + [PCIE_1_GDSC] = &pcie_1_gdsc, + [PCIE_2_GDSC] = &pcie_2_gdsc, + [UFS_CARD_GDSC] = &ufs_card_gdsc, + [UFS_PHY_GDSC] = &ufs_phy_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF0_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF1_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc, +}; + +static const struct qcom_reset_map gcc_sm8250_resets[] = { + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_MMSS_BCR] = { 0xb000 }, + [GCC_NPU_BWMON_BCR] = { 0x73000 }, + [GCC_NPU_BCR] = { 0x4d000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e000 }, + [GCC_PCIE_2_BCR] = { 0x6000 }, + [GCC_PCIE_2_LINK_DOWN_BCR] = { 0x1f014 }, + [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0x1f020 }, + [GCC_PCIE_2_PHY_BCR] = { 0x1f01c }, + [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0x1f028 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_PRNG_BCR] = { 0x34000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x17000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_TSIF_BCR] = { 0x36000 }, + [GCC_UFS_CARD_BCR] = { 0x75000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB30_SEC_BCR] = { 0x10000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0xb024, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0xb028, 2 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src), +}; + +static const struct regmap_config gcc_sm8250_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9c100, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sm8250_desc = { + .config = &gcc_sm8250_regmap_config, + .clks = gcc_sm8250_clocks, + .num_clks = ARRAY_SIZE(gcc_sm8250_clocks), + .resets = gcc_sm8250_resets, + .num_resets = ARRAY_SIZE(gcc_sm8250_resets), + .gdscs = gcc_sm8250_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm8250_gdscs), +}; + +static const struct of_device_id gcc_sm8250_match_table[] = { + { .compatible = "qcom,gcc-sm8250" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sm8250_match_table); + +static int gcc_sm8250_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sm8250_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* + * Disable the GPLL0 active input to NPU and GPU + * via MISC registers. + */ + regmap_update_bits(regmap, 0x4d110, 0x3, 0x3); + regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + + /* + * Keep the clocks always-ON + * GCC_VIDEO_AHB_CLK, GCC_CAMERA_AHB_CLK, GCC_DISP_AHB_CLK, + * GCC_CPUSS_DVM_BUS_CLK, GCC_GPU_CFG_AHB_CLK, + * GCC_SYS_NOC_CPUSS_AHB_CLK + */ + regmap_update_bits(regmap, 0x0b004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b008, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b00c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x4818c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x52000, BIT(0), BIT(0)); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + return qcom_cc_really_probe(pdev, &gcc_sm8250_desc, regmap); +} + +static struct platform_driver gcc_sm8250_driver = { + .probe = gcc_sm8250_probe, + .driver = { + .name = "gcc-sm8250", + .of_match_table = gcc_sm8250_match_table, + }, +}; + +static int __init gcc_sm8250_init(void) +{ + return platform_driver_register(&gcc_sm8250_driver); +} +subsys_initcall(gcc_sm8250_init); + +static void __exit gcc_sm8250_exit(void) +{ + platform_driver_unregister(&gcc_sm8250_driver); +} +module_exit(gcc_sm8250_exit); + +MODULE_DESCRIPTION("QTI GCC SM8250 Driver"); +MODULE_LICENSE("GPL v2"); From 28b2f82e0383e27476be8a5e13d2aea07ebeb275 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 19 Feb 2020 15:59:46 +0800 Subject: [PATCH 236/809] clk: imx: Fix division by zero warning on pfdv2 Fix below division by zero warning: [ 3.176443] Division by zero in kernel. [ 3.181809] CPU: 0 PID: 88 Comm: kworker/0:2 Not tainted 5.3.0-rc2-next-20190730-63758-ge08da51-dirty #124 [ 3.191817] Hardware name: Freescale i.MX7ULP (Device Tree) [ 3.197821] Workqueue: events dbs_work_handler [ 3.202849] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 3.211058] [] (show_stack) from [] (dump_stack+0xd8/0x110) [ 3.218820] [] (dump_stack) from [] (Ldiv0_64+0x8/0x18) [ 3.226263] [] (Ldiv0_64) from [] (clk_pfdv2_set_rate+0x54/0xac) [ 3.234487] [] (clk_pfdv2_set_rate) from [] (clk_change_rate+0x1a4/0x698) [ 3.243468] [] (clk_change_rate) from [] (clk_change_rate+0x280/0x698) [ 3.252180] [] (clk_change_rate) from [] (clk_core_set_rate_nolock+0x1a0/0x278) [ 3.261679] [] (clk_core_set_rate_nolock) from [] (clk_set_rate+0x30/0x64) [ 3.270743] [] (clk_set_rate) from [] (imx7ulp_set_target+0x184/0x2a4) [ 3.279501] [] (imx7ulp_set_target) from [] (__cpufreq_driver_target+0x188/0x514) [ 3.289196] [] (__cpufreq_driver_target) from [] (od_dbs_update+0x130/0x15c) [ 3.298438] [] (od_dbs_update) from [] (dbs_work_handler+0x2c/0x5c) [ 3.306914] [] (dbs_work_handler) from [] (process_one_work+0x2ac/0x704) [ 3.315826] [] (process_one_work) from [] (worker_thread+0x2c/0x574) [ 3.324404] [] (worker_thread) from [] (kthread+0x134/0x148) [ 3.332278] [] (kthread) from [] (ret_from_fork+0x14/0x20) [ 3.339858] Exception stack(0xe82d5fb0 to 0xe82d5ff8) [ 3.345314] 5fa0: 00000000 00000000 00000000 00000000 [ 3.353926] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 3.362519] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 Signed-off-by: Anson Huang Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pfdv2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index de93ce73101b..f8707278aad9 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -139,6 +139,12 @@ static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, u32 val; u8 frac; + if (!rate) + return -EINVAL; + + /* PFD can NOT change rate without gating */ + WARN_ON(clk_pfdv2_is_enabled(hw)); + tmp = tmp * 18 + rate / 2; do_div(tmp, rate); frac = tmp; From 8ffe9c7bb9e47745b8a678629b22f57b23b8dac5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 15:59:47 +0800 Subject: [PATCH 237/809] clk: imx: pfdv2: switch to use determine_rate Per clk_ops, compared with round_rate, determine_rate could optionally support the parent clock that should be used to provide the clock rate. In this patch, the parent clock is just parent->rate as round_rate. The following patch will calculate the best parent clock. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pfdv2.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index f8707278aad9..28b5f208ced9 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -98,10 +98,11 @@ static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, return tmp; } -static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_pfdv2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - u64 tmp = *prate; + u64 tmp = req->best_parent_rate; + u64 rate = req->rate; u8 frac; tmp = tmp * 18 + rate / 2; @@ -113,11 +114,13 @@ static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, else if (frac > 35) frac = 35; - tmp = *prate; + tmp = req->best_parent_rate; tmp *= 18; do_div(tmp, frac); - return tmp; + req->rate = tmp; + + return 0; } static int clk_pfdv2_is_enabled(struct clk_hw *hw) @@ -167,7 +170,7 @@ static const struct clk_ops clk_pfdv2_ops = { .enable = clk_pfdv2_enable, .disable = clk_pfdv2_disable, .recalc_rate = clk_pfdv2_recalc_rate, - .round_rate = clk_pfdv2_round_rate, + .determine_rate = clk_pfdv2_determine_rate, .set_rate = clk_pfdv2_set_rate, .is_enabled = clk_pfdv2_is_enabled, }; From c88a4c797a50574c90ca11f72ab10dbded7d768e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 15:59:48 +0800 Subject: [PATCH 238/809] clk: imx: pfdv2: determine best parent rate pfdv2 is only used in i.MX7ULP. To get best pfd output, the i.MX7ULP Datasheet defines two best PLL rate and pfd frac. Per Datasheel All PLLs on i.MX 7ULP either have VCO base frequency of 480 MHz or 528 MHz. So when determine best rate, we also determine best parent rate which could match the requirement. For some reason the current parent might not be 480MHz or 528MHz, so we still take current parent rate as a choice. And we also enable flag CLK_SET_RATE_PARENT to let parent rate to be configured. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pfdv2.c | 44 +++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index 28b5f208ced9..78e1f7641aaa 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -101,24 +101,40 @@ static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, static int clk_pfdv2_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - u64 tmp = req->best_parent_rate; - u64 rate = req->rate; + unsigned long parent_rates[] = { + 480000000, + 528000000, + req->best_parent_rate + }; + unsigned long best_rate = -1UL, rate = req->rate; + unsigned long best_parent_rate = req->best_parent_rate; + u64 tmp; u8 frac; + int i; - tmp = tmp * 18 + rate / 2; - do_div(tmp, rate); - frac = tmp; + for (i = 0; i < ARRAY_SIZE(parent_rates); i++) { + tmp = parent_rates[i]; + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; - if (frac < 12) - frac = 12; - else if (frac > 35) - frac = 35; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; - tmp = req->best_parent_rate; - tmp *= 18; - do_div(tmp, frac); + tmp = parent_rates[i]; + tmp *= 18; + do_div(tmp, frac); - req->rate = tmp; + if (abs(tmp - req->rate) < abs(best_rate - req->rate)) { + best_rate = tmp; + best_parent_rate = parent_rates[i]; + } + } + + req->best_parent_rate = best_parent_rate; + req->rate = best_rate; return 0; } @@ -198,7 +214,7 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name, init.ops = &clk_pfdv2_ops; init.parent_names = &parent_name; init.num_parents = 1; - init.flags = CLK_SET_RATE_GATE; + init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; pfd->hw.init = &init; From d678d83c583dd6d00b7e3e0c5c78e8441e1a9131 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Feb 2020 15:59:49 +0800 Subject: [PATCH 239/809] clk: imx: pllv4: use prepare/unprepare It is not good to use enable/disable for PLLv4 which needs time to lock, because enable/disable is expected to be able run in interrupt context. So use prepare/unprepare. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pllv4.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c index f51a800c268c..a49450431855 100644 --- a/drivers/clk/imx/clk-pllv4.c +++ b/drivers/clk/imx/clk-pllv4.c @@ -54,7 +54,7 @@ static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); } -static int clk_pllv4_is_enabled(struct clk_hw *hw) +static int clk_pllv4_is_prepared(struct clk_hw *hw) { struct clk_pllv4 *pll = to_clk_pllv4(hw); @@ -175,7 +175,7 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static int clk_pllv4_enable(struct clk_hw *hw) +static int clk_pllv4_prepare(struct clk_hw *hw) { u32 val; struct clk_pllv4 *pll = to_clk_pllv4(hw); @@ -187,7 +187,7 @@ static int clk_pllv4_enable(struct clk_hw *hw) return clk_pllv4_wait_lock(pll); } -static void clk_pllv4_disable(struct clk_hw *hw) +static void clk_pllv4_unprepare(struct clk_hw *hw) { u32 val; struct clk_pllv4 *pll = to_clk_pllv4(hw); @@ -201,9 +201,9 @@ static const struct clk_ops clk_pllv4_ops = { .recalc_rate = clk_pllv4_recalc_rate, .round_rate = clk_pllv4_round_rate, .set_rate = clk_pllv4_set_rate, - .enable = clk_pllv4_enable, - .disable = clk_pllv4_disable, - .is_enabled = clk_pllv4_is_enabled, + .prepare = clk_pllv4_prepare, + .unprepare = clk_pllv4_unprepare, + .is_prepared = clk_pllv4_is_prepared, }; struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name, From 035f212fa7f21035537cf6dea620fe5653191eb6 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 10 Feb 2020 17:53:25 +0100 Subject: [PATCH 240/809] s390/pci: embedding hotplug_slot in zdev Embedding the hotplug_slot in zdev structure allows to greatly simplify the hotplug handling by eliminating the handling of the slot_list. Signed-off-by: Pierre Morel Reviewed-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pci.h | 2 + drivers/pci/hotplug/s390_pci_hpc.c | 99 +++++++++--------------------- 2 files changed, 31 insertions(+), 70 deletions(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index b05187ce5dbd..73b69a777152 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,7 @@ struct s390_domain; struct zpci_dev { struct pci_bus *bus; struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */ + struct hotplug_slot hotplug_slot; enum zpci_state state; u32 fid; /* function ID, used by sclp */ diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 30ee72268790..39295d88f670 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -19,7 +19,6 @@ #include #define SLOT_NAME_SIZE 10 -static LIST_HEAD(s390_hotplug_slot_list); static int zpci_fn_configured(enum zpci_state state) { @@ -27,97 +26,86 @@ static int zpci_fn_configured(enum zpci_state state) state == ZPCI_FN_STATE_ONLINE; } -/* - * struct slot - slot information for each *physical* slot - */ -struct slot { - struct list_head slot_list; - struct hotplug_slot hotplug_slot; - struct zpci_dev *zdev; -}; - -static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +static inline int zdev_configure(struct zpci_dev *zdev) { - return container_of(hotplug_slot, struct slot, hotplug_slot); -} + int ret = sclp_pci_configure(zdev->fid); -static inline int slot_configure(struct slot *slot) -{ - int ret = sclp_pci_configure(slot->zdev->fid); - - zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); + zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, ret); if (!ret) - slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; + zdev->state = ZPCI_FN_STATE_CONFIGURED; return ret; } -static inline int slot_deconfigure(struct slot *slot) +static inline int zdev_deconfigure(struct zpci_dev *zdev) { - int ret = sclp_pci_deconfigure(slot->zdev->fid); + int ret = sclp_pci_deconfigure(zdev->fid); - zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); + zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); if (!ret) - slot->zdev->state = ZPCI_FN_STATE_STANDBY; + zdev->state = ZPCI_FN_STATE_STANDBY; return ret; } static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = to_slot(hotplug_slot); + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, + hotplug_slot); int rc; - if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) + if (zdev->state != ZPCI_FN_STATE_STANDBY) return -EIO; - rc = slot_configure(slot); + rc = zdev_configure(zdev); if (rc) return rc; - rc = zpci_enable_device(slot->zdev); + rc = zpci_enable_device(zdev); if (rc) goto out_deconfigure; - pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); + pci_scan_slot(zdev->bus, ZPCI_DEVFN); pci_lock_rescan_remove(); - pci_bus_add_devices(slot->zdev->bus); + pci_bus_add_devices(zdev->bus); pci_unlock_rescan_remove(); return rc; out_deconfigure: - slot_deconfigure(slot); + zdev_deconfigure(zdev); return rc; } static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = to_slot(hotplug_slot); + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, + hotplug_slot); struct pci_dev *pdev; int rc; - if (!zpci_fn_configured(slot->zdev->state)) + if (!zpci_fn_configured(zdev->state)) return -EIO; - pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN); + pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN); if (pdev) { pci_stop_and_remove_bus_device_locked(pdev); pci_dev_put(pdev); } - rc = zpci_disable_device(slot->zdev); + rc = zpci_disable_device(zdev); if (rc) return rc; - return slot_deconfigure(slot); + return zdev_deconfigure(zdev); } static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = to_slot(hotplug_slot); + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, + hotplug_slot); - switch (slot->zdev->state) { + switch (zdev->state) { case ZPCI_FN_STATE_STANDBY: *value = 0; break; @@ -145,44 +133,15 @@ static const struct hotplug_slot_ops s390_hotplug_slot_ops = { int zpci_init_slot(struct zpci_dev *zdev) { char name[SLOT_NAME_SIZE]; - struct slot *slot; - int rc; - if (!zdev) - return 0; - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - goto error; - - slot->zdev = zdev; - slot->hotplug_slot.ops = &s390_hotplug_slot_ops; + zdev->hotplug_slot.ops = &s390_hotplug_slot_ops; snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); - rc = pci_hp_register(&slot->hotplug_slot, zdev->bus, - ZPCI_DEVFN, name); - if (rc) - goto error_reg; - - list_add(&slot->slot_list, &s390_hotplug_slot_list); - return 0; - -error_reg: - kfree(slot); -error: - return -ENOMEM; + return pci_hp_register(&zdev->hotplug_slot, zdev->bus, + ZPCI_DEVFN, name); } void zpci_exit_slot(struct zpci_dev *zdev) { - struct slot *slot, *next; - - list_for_each_entry_safe(slot, next, &s390_hotplug_slot_list, - slot_list) { - if (slot->zdev != zdev) - continue; - list_del(&slot->slot_list); - pci_hp_deregister(&slot->hotplug_slot); - kfree(slot); - } + pci_hp_deregister(&zdev->hotplug_slot); } From d68d5d51dc898895b4e15bea52e5668ca9e76180 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Thu, 5 Mar 2020 07:44:09 +0100 Subject: [PATCH 241/809] s390/cpum_cf: Add new extended counters for IBM z15 Add CPU measurement counter facility event description for IBM z15. Signed-off-by: Thomas Richter Reviewed-by: Sumanth Korikkar Signed-off-by: Vasily Gorbik --- arch/s390/kernel/perf_cpum_cf_events.c | 123 ++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/perf_cpum_cf_events.c b/arch/s390/kernel/perf_cpum_cf_events.c index 8b33e03e47b8..1e3df52b2b65 100644 --- a/arch/s390/kernel/perf_cpum_cf_events.c +++ b/arch/s390/kernel/perf_cpum_cf_events.c @@ -238,6 +238,64 @@ CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_SPECIAL, 0x00f5); CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0); CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1); +CPUMF_EVENT_ATTR(cf_z15, L1D_RO_EXCL_WRITES, 0x0080); +CPUMF_EVENT_ATTR(cf_z15, DTLB2_WRITES, 0x0081); +CPUMF_EVENT_ATTR(cf_z15, DTLB2_MISSES, 0x0082); +CPUMF_EVENT_ATTR(cf_z15, DTLB2_HPAGE_WRITES, 0x0083); +CPUMF_EVENT_ATTR(cf_z15, DTLB2_GPAGE_WRITES, 0x0084); +CPUMF_EVENT_ATTR(cf_z15, L1D_L2D_SOURCED_WRITES, 0x0085); +CPUMF_EVENT_ATTR(cf_z15, ITLB2_WRITES, 0x0086); +CPUMF_EVENT_ATTR(cf_z15, ITLB2_MISSES, 0x0087); +CPUMF_EVENT_ATTR(cf_z15, L1I_L2I_SOURCED_WRITES, 0x0088); +CPUMF_EVENT_ATTR(cf_z15, TLB2_PTE_WRITES, 0x0089); +CPUMF_EVENT_ATTR(cf_z15, TLB2_CRSTE_WRITES, 0x008a); +CPUMF_EVENT_ATTR(cf_z15, TLB2_ENGINES_BUSY, 0x008b); +CPUMF_EVENT_ATTR(cf_z15, TX_C_TEND, 0x008c); +CPUMF_EVENT_ATTR(cf_z15, TX_NC_TEND, 0x008d); +CPUMF_EVENT_ATTR(cf_z15, L1C_TLB2_MISSES, 0x008f); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0090); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES, 0x0091); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV, 0x0092); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES, 0x0093); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x0094); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x0095); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES, 0x0096); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x0097); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x0098); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES, 0x0099); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x009a); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x009b); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES, 0x009c); +CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES, 0x009d); +CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO, 0x009e); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES, 0x00a2); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES, 0x00a3); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV, 0x00a4); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES, 0x00a5); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x00a6); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x00a7); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES, 0x00a8); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x00a9); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x00aa); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES, 0x00ab); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x00ac); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x00ad); +CPUMF_EVENT_ATTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES, 0x00ae); +CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES, 0x00af); +CPUMF_EVENT_ATTR(cf_z15, BCD_DFP_EXECUTION_SLOTS, 0x00e0); +CPUMF_EVENT_ATTR(cf_z15, VX_BCD_EXECUTION_SLOTS, 0x00e1); +CPUMF_EVENT_ATTR(cf_z15, DECIMAL_INSTRUCTIONS, 0x00e2); +CPUMF_EVENT_ATTR(cf_z15, LAST_HOST_TRANSLATIONS, 0x00e8); +CPUMF_EVENT_ATTR(cf_z15, TX_NC_TABORT, 0x00f3); +CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_NO_SPECIAL, 0x00f4); +CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_SPECIAL, 0x00f5); +CPUMF_EVENT_ATTR(cf_z15, DFLT_ACCESS, 0x00f7); +CPUMF_EVENT_ATTR(cf_z15, DFLT_CYCLES, 0x00fc); +CPUMF_EVENT_ATTR(cf_z15, DFLT_CC, 0x00108); +CPUMF_EVENT_ATTR(cf_z15, DFLT_CCERROR, 0x00109); +CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0); +CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1); + static struct attribute *cpumcf_fvn1_pmu_event_attr[] __initdata = { CPUMF_EVENT_PTR(cf_fvn1, CPU_CYCLES), CPUMF_EVENT_PTR(cf_fvn1, INSTRUCTIONS), @@ -516,6 +574,67 @@ static struct attribute *cpumcf_z14_pmu_event_attr[] __initdata = { NULL, }; +static struct attribute *cpumcf_z15_pmu_event_attr[] __initdata = { + CPUMF_EVENT_PTR(cf_z15, L1D_RO_EXCL_WRITES), + CPUMF_EVENT_PTR(cf_z15, DTLB2_WRITES), + CPUMF_EVENT_PTR(cf_z15, DTLB2_MISSES), + CPUMF_EVENT_PTR(cf_z15, DTLB2_HPAGE_WRITES), + CPUMF_EVENT_PTR(cf_z15, DTLB2_GPAGE_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_L2D_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, ITLB2_WRITES), + CPUMF_EVENT_PTR(cf_z15, ITLB2_MISSES), + CPUMF_EVENT_PTR(cf_z15, L1I_L2I_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, TLB2_PTE_WRITES), + CPUMF_EVENT_PTR(cf_z15, TLB2_CRSTE_WRITES), + CPUMF_EVENT_PTR(cf_z15, TLB2_ENGINES_BUSY), + CPUMF_EVENT_PTR(cf_z15, TX_C_TEND), + CPUMF_EVENT_PTR(cf_z15, TX_NC_TEND), + CPUMF_EVENT_PTR(cf_z15, L1C_TLB2_MISSES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV), + CPUMF_EVENT_PTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES), + CPUMF_EVENT_PTR(cf_z15, BCD_DFP_EXECUTION_SLOTS), + CPUMF_EVENT_PTR(cf_z15, VX_BCD_EXECUTION_SLOTS), + CPUMF_EVENT_PTR(cf_z15, DECIMAL_INSTRUCTIONS), + CPUMF_EVENT_PTR(cf_z15, LAST_HOST_TRANSLATIONS), + CPUMF_EVENT_PTR(cf_z15, TX_NC_TABORT), + CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_NO_SPECIAL), + CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_SPECIAL), + CPUMF_EVENT_PTR(cf_z15, DFLT_ACCESS), + CPUMF_EVENT_PTR(cf_z15, DFLT_CYCLES), + CPUMF_EVENT_PTR(cf_z15, DFLT_CC), + CPUMF_EVENT_PTR(cf_z15, DFLT_CCERROR), + CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE), + CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE), + NULL, +}; + /* END: CPUM_CF COUNTER DEFINITIONS ===================================== */ static struct attribute_group cpumcf_pmu_events_group = { @@ -624,9 +743,11 @@ __init const struct attribute_group **cpumf_cf_event_group(void) break; case 0x3906: case 0x3907: + model = cpumcf_z14_pmu_event_attr; + break; case 0x8561: case 0x8562: - model = cpumcf_z14_pmu_event_attr; + model = cpumcf_z15_pmu_event_attr; break; default: model = none; From d2abfbe4652d2b49d30fe77548cf663e63d2d469 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 5 Mar 2020 15:01:21 +0100 Subject: [PATCH 242/809] s390: enable bpf jit by default when not built as always-on This is the s390 variant of commit 81c22041d9f1 ("bpf, x86, arm64: Enable jit by default when not built as always-on"). Acked-by: Ilya Leoshkevich Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 6b1f715dd8bb..f4ff75ff62f2 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -109,6 +109,7 @@ config S390 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_WANTS_DYNAMIC_TASK_STRUCT + select ARCH_WANT_DEFAULT_BPF_JIT select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS2 From 0b38b5e1d0e2f361e418e05c179db05bb688bbd6 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 22 Jan 2020 13:38:22 +0100 Subject: [PATCH 243/809] s390: prevent leaking kernel address in BEAR When userspace executes a syscall or gets interrupted, BEAR contains a kernel address when returning to userspace. This make it pretty easy to figure out where the kernel is mapped even with KASLR enabled. To fix this, add lpswe to lowcore and always execute it there, so userspace sees only the lowcore address of lpswe. For this we have to extend both critical_cleanup and the SWITCH_ASYNC macro to also check for lpswe addresses in lowcore. Fixes: b2d24b97b2a9 ("s390/kernel: add support for kernel address space layout randomization (KASLR)") Cc: # v5.2+ Reviewed-by: Gerald Schaefer Signed-off-by: Sven Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 4 +- arch/s390/include/asm/processor.h | 1 + arch/s390/include/asm/setup.h | 7 ++++ arch/s390/kernel/asm-offsets.c | 2 + arch/s390/kernel/entry.S | 65 ++++++++++++++++++------------- arch/s390/kernel/process.c | 1 + arch/s390/kernel/setup.c | 3 ++ arch/s390/kernel/smp.c | 2 + arch/s390/mm/vmem.c | 4 ++ 9 files changed, 62 insertions(+), 27 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 237ee0c4169f..612ed3c6d581 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -141,7 +141,9 @@ struct lowcore { /* br %r1 trampoline */ __u16 br_r1_trampoline; /* 0x0400 */ - __u8 pad_0x0402[0x0e00-0x0402]; /* 0x0402 */ + __u32 return_lpswe; /* 0x0402 */ + __u32 return_mcck_lpswe; /* 0x0406 */ + __u8 pad_0x040a[0x0e00-0x040a]; /* 0x040a */ /* * 0xe00 contains the address of the IPL Parameter Information diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 361ef5eda468..c9522346799f 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -162,6 +162,7 @@ typedef struct thread_struct thread_struct; #define INIT_THREAD { \ .ksp = sizeof(init_stack) + (unsigned long) &init_stack, \ .fpu.regs = (void *) init_task.thread.fpu.fprs, \ + .last_break = 1, \ } /* diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index b241ddb67caf..534f212753d6 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -8,6 +8,7 @@ #include #include +#include #define EP_OFFSET 0x10008 #define EP_STRING "S390EP" @@ -162,6 +163,12 @@ static inline unsigned long kaslr_offset(void) return __kaslr_offset; } +static inline u32 gen_lpswe(unsigned long addr) +{ + BUILD_BUG_ON(addr > 0xfff); + return 0xb2b20000 | addr; +} + #else /* __ASSEMBLY__ */ #define IPL_DEVICE (IPL_DEVICE_OFFSET) diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index ce33406cfe83..e80f0e6f5972 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -124,6 +124,8 @@ int main(void) OFFSET(__LC_EXT_DAMAGE_CODE, lowcore, external_damage_code); OFFSET(__LC_MCCK_FAIL_STOR_ADDR, lowcore, failing_storage_address); OFFSET(__LC_LAST_BREAK, lowcore, breaking_event_addr); + OFFSET(__LC_RETURN_LPSWE, lowcore, return_lpswe); + OFFSET(__LC_RETURN_MCCK_LPSWE, lowcore, return_mcck_lpswe); OFFSET(__LC_RST_OLD_PSW, lowcore, restart_old_psw); OFFSET(__LC_EXT_OLD_PSW, lowcore, external_old_psw); OFFSET(__LC_SVC_OLD_PSW, lowcore, svc_old_psw); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 9205add8481d..3ae64914bd14 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -115,26 +115,29 @@ _LPP_OFFSET = __LC_LPP .macro SWITCH_ASYNC savearea,timer tmhh %r8,0x0001 # interrupting from user ? - jnz 1f + jnz 2f lgr %r14,%r9 + cghi %r14,__LC_RETURN_LPSWE + je 0f slg %r14,BASED(.Lcritical_start) clg %r14,BASED(.Lcritical_length) - jhe 0f + jhe 1f +0: lghi %r11,\savearea # inside critical section, do cleanup brasl %r14,cleanup_critical tmhh %r8,0x0001 # retest problem state after cleanup - jnz 1f -0: lg %r14,__LC_ASYNC_STACK # are we already on the target stack? + jnz 2f +1: lg %r14,__LC_ASYNC_STACK # are we already on the target stack? slgr %r14,%r15 srag %r14,%r14,STACK_SHIFT - jnz 2f + jnz 3f CHECK_STACK \savearea aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) - j 3f -1: UPDATE_VTIME %r14,%r15,\timer + j 4f +2: UPDATE_VTIME %r14,%r15,\timer BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP -2: lg %r15,__LC_ASYNC_STACK # load async stack -3: la %r11,STACK_FRAME_OVERHEAD(%r15) +3: lg %r15,__LC_ASYNC_STACK # load async stack +4: la %r11,STACK_FRAME_OVERHEAD(%r15) .endm .macro UPDATE_VTIME w1,w2,enter_timer @@ -401,7 +404,7 @@ ENTRY(system_call) stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER lmg %r11,%r15,__PT_R11(%r11) - lpswe __LC_RETURN_PSW + b __LC_RETURN_LPSWE(%r0) .Lsysc_done: # @@ -608,43 +611,50 @@ ENTRY(pgm_check_handler) BPOFF stmg %r8,%r15,__LC_SAVE_AREA_SYNC lg %r10,__LC_LAST_BREAK - lg %r12,__LC_CURRENT + srag %r11,%r10,12 + jnz 0f + /* if __LC_LAST_BREAK is < 4096, it contains one of + * the lpswe addresses in lowcore. Set it to 1 (initial state) + * to prevent leaking that address to userspace. + */ + lghi %r10,1 +0: lg %r12,__LC_CURRENT lghi %r11,0 larl %r13,cleanup_critical lmg %r8,%r9,__LC_PGM_OLD_PSW tmhh %r8,0x0001 # test problem state bit - jnz 2f # -> fault in user space + jnz 3f # -> fault in user space #if IS_ENABLED(CONFIG_KVM) # cleanup critical section for program checks in sie64a lgr %r14,%r9 slg %r14,BASED(.Lsie_critical_start) clg %r14,BASED(.Lsie_critical_length) - jhe 0f + jhe 1f lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit lghi %r11,_PIF_GUEST_FAULT #endif -0: tmhh %r8,0x4000 # PER bit set in old PSW ? - jnz 1f # -> enabled, can't be a double fault +1: tmhh %r8,0x4000 # PER bit set in old PSW ? + jnz 2f # -> enabled, can't be a double fault tm __LC_PGM_ILC+3,0x80 # check for per exception jnz .Lpgm_svcper # -> single stepped svc -1: CHECK_STACK __LC_SAVE_AREA_SYNC +2: CHECK_STACK __LC_SAVE_AREA_SYNC aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) - # CHECK_VMAP_STACK branches to stack_overflow or 4f - CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f -2: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER + # CHECK_VMAP_STACK branches to stack_overflow or 5f + CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,5f +3: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP lg %r15,__LC_KERNEL_STACK lgr %r14,%r12 aghi %r14,__TASK_thread # pointer to thread_struct lghi %r13,__LC_PGM_TDB tm __LC_PGM_ILC+2,0x02 # check for transaction abort - jz 3f + jz 4f mvc __THREAD_trap_tdb(256,%r14),0(%r13) -3: stg %r10,__THREAD_last_break(%r14) -4: lgr %r13,%r11 +4: stg %r10,__THREAD_last_break(%r14) +5: lgr %r13,%r11 la %r11,STACK_FRAME_OVERHEAD(%r15) stmg %r0,%r7,__PT_R0(%r11) # clear user controlled registers to prevent speculative use @@ -663,14 +673,14 @@ ENTRY(pgm_check_handler) stg %r13,__PT_FLAGS(%r11) stg %r10,__PT_ARGS(%r11) tm __LC_PGM_ILC+3,0x80 # check for per exception - jz 5f + jz 6f tmhh %r8,0x0001 # kernel per event ? jz .Lpgm_kprobe oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE mvc __THREAD_per_paid(1,%r14),__LC_PER_ACCESS_ID -5: REENABLE_IRQS +6: REENABLE_IRQS xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) larl %r1,pgm_check_table llgh %r10,__PT_INT_CODE+2(%r11) @@ -775,7 +785,7 @@ ENTRY(io_int_handler) mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER .Lio_exit_kernel: lmg %r11,%r15,__PT_R11(%r11) - lpswe __LC_RETURN_PSW + b __LC_RETURN_LPSWE(%r0) .Lio_done: # @@ -1214,7 +1224,7 @@ ENTRY(mcck_int_handler) stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 0: lmg %r11,%r15,__PT_R11(%r11) - lpswe __LC_RETURN_MCCK_PSW + b __LC_RETURN_MCCK_LPSWE .Lmcck_panic: lg %r15,__LC_NODAT_STACK @@ -1271,6 +1281,8 @@ ENDPROC(stack_overflow) #endif ENTRY(cleanup_critical) + cghi %r9,__LC_RETURN_LPSWE + je .Lcleanup_lpswe #if IS_ENABLED(CONFIG_KVM) clg %r9,BASED(.Lcleanup_table_sie) # .Lsie_gmap jl 0f @@ -1424,6 +1436,7 @@ ENDPROC(cleanup_critical) mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) +.Lcleanup_lpswe: 1: lmg %r8,%r9,__LC_RETURN_PSW BR_EX %r14,%r11 .Lcleanup_sysc_restore_insn: diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 6ccef5f29761..eb6e23ad15a2 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -106,6 +106,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp, p->thread.system_timer = 0; p->thread.hardirq_timer = 0; p->thread.softirq_timer = 0; + p->thread.last_break = 1; frame->sf.back_chain = 0; /* new return point is ret_from_fork */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 1158a63a8e0e..26de59256466 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "entry.h" /* @@ -450,6 +451,8 @@ static void __init setup_lowcore_dat_off(void) lc->spinlock_index = 0; arch_spin_lock_setup(0); lc->br_r1_trampoline = 0x07f1; /* br %r1 */ + lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW); + lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW); set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index a08bd2522dd9..f87d4e14269c 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -212,6 +212,8 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->spinlock_lockval = arch_spin_lockval(cpu); lc->spinlock_index = 0; lc->br_r1_trampoline = 0x07f1; /* br %r1 */ + lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW); + lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW); if (nmi_alloc_per_cpu(lc)) goto out_async; if (vdso_alloc_per_cpu(lc)) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index b403fa14847d..f810930aff42 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -415,6 +415,10 @@ void __init vmem_map_init(void) SET_MEMORY_RO | SET_MEMORY_X); __set_memory(__stext_dma, (__etext_dma - __stext_dma) >> PAGE_SHIFT, SET_MEMORY_RO | SET_MEMORY_X); + + /* we need lowcore executable for our LPSWE instructions */ + set_memory_x(0, 1); + pr_info("Write protected kernel read-only data: %luk\n", (unsigned long)(__end_rodata - _stext) >> 10); } From fb83510295d7a6cdeb46242515c3180f9adafc85 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 29 Jan 2020 12:15:15 +0100 Subject: [PATCH 244/809] s390/cpuinfo: add system topology information This update adjusts /proc/cpuinfo format to meet some user level programs expectations. It also makes the layout consistent with x86 where CPU topology is presented as blocks of key-value pairs. Reviewed-by: Vasily Gorbik Signed-off-by: Alexander Gordeev Signed-off-by: Vasily Gorbik --- arch/s390/kernel/processor.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 6ebc2117c66c..2c13ca562b48 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -151,6 +151,26 @@ static void show_cpu_summary(struct seq_file *m, void *v) } } +static void show_cpu_topology(struct seq_file *m, unsigned long n) +{ +#ifdef CONFIG_SCHED_TOPOLOGY + seq_printf(m, "physical id : %d\n", topology_physical_package_id(n)); + seq_printf(m, "core id : %d\n", topology_core_id(n)); + seq_printf(m, "book id : %d\n", topology_book_id(n)); + seq_printf(m, "drawer id : %d\n", topology_drawer_id(n)); + seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n)); +#endif /* CONFIG_SCHED_TOPOLOGY */ +} + +static void show_cpu_ids(struct seq_file *m, unsigned long n) +{ + struct cpuid *id = &per_cpu(cpu_info.cpu_id, n); + + seq_printf(m, "version : %02X\n", id->version); + seq_printf(m, "identification : %06X\n", id->ident); + seq_printf(m, "machine : %04X\n", id->machine); +} + static void show_cpu_mhz(struct seq_file *m, unsigned long n) { struct cpu_info *c = per_cpu_ptr(&cpu_info, n); @@ -171,6 +191,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (!machine_has_cpu_mhz) return 0; seq_printf(m, "\ncpu number : %ld\n", n); + show_cpu_topology(m, n); + show_cpu_ids(m, n); show_cpu_mhz(m, n); return 0; } From e20703f00b1206b89edb1b4a7cabe36257242a9f Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 25 Feb 2020 16:49:11 +0800 Subject: [PATCH 245/809] clk: imx8mn: A53 core clock no need to be critical 'A53_CORE' is just a mux and no need to be critical, being critical will cause its parent clock always ON which does NOT make sense, to make sure CPU's hardware clock source NOT being disabled during clock tree setup, need to move the 'A53_SRC'/'A53_CORE' reparent operations to after critical clock 'ARM_CLK' setup finished. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 83618affca8b..0bc7070235bd 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -428,7 +428,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_GPU_SHADER_DIV] = hws[IMX8MN_CLK_GPU_SHADER]; /* CORE SEL */ - hws[IMX8MN_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels), CLK_IS_CRITICAL); + hws[IMX8MN_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels)); /* BUS */ hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800); @@ -559,15 +559,15 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); - clk_hw_set_parent(hws[IMX8MN_CLK_A53_SRC], hws[IMX8MN_SYS_PLL1_800M]); - clk_hw_set_parent(hws[IMX8MN_CLK_A53_CORE], hws[IMX8MN_ARM_PLL_OUT]); - hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", hws[IMX8MN_CLK_A53_CORE]->clk, hws[IMX8MN_CLK_A53_CORE]->clk, hws[IMX8MN_ARM_PLL_OUT]->clk, hws[IMX8MN_CLK_A53_DIV]->clk); + clk_hw_set_parent(hws[IMX8MN_CLK_A53_SRC], hws[IMX8MN_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MN_CLK_A53_CORE], hws[IMX8MN_ARM_PLL_OUT]); + imx_check_clk_hws(hws, IMX8MN_CLK_END); ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); From 81aa844bb53bc711b943db2113d7794912f047b8 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 25 Feb 2020 16:49:12 +0800 Subject: [PATCH 246/809] clk: imx8mm: A53 core clock no need to be critical 'A53_CORE' is just a mux and no need to be critical, being critical will cause its parent clock always ON which does NOT make sense, to make sure CPU's hardware clock source NOT being disabled during clock tree setup, need to move the 'A53_SRC'/'A53_CORE' reparent operations to after critical clock 'ARM_CLK' setup finished. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 9feda4f5b3d6..925670438f23 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -440,7 +440,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_GPU2D_DIV] = hws[IMX8MM_CLK_GPU2D_CORE]; /* CORE SEL */ - hws[IMX8MM_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mm_a53_core_sels, ARRAY_SIZE(imx8mm_a53_core_sels), CLK_IS_CRITICAL); + hws[IMX8MM_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mm_a53_core_sels, ARRAY_SIZE(imx8mm_a53_core_sels)); /* BUS */ hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); @@ -608,15 +608,15 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); hws[IMX8MM_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL); - clk_hw_set_parent(hws[IMX8MM_CLK_A53_SRC], hws[IMX8MM_SYS_PLL1_800M]); - clk_hw_set_parent(hws[IMX8MM_CLK_A53_CORE], hws[IMX8MM_ARM_PLL_OUT]); - hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", hws[IMX8MM_CLK_A53_CORE]->clk, hws[IMX8MM_CLK_A53_CORE]->clk, hws[IMX8MM_ARM_PLL_OUT]->clk, hws[IMX8MM_CLK_A53_DIV]->clk); + clk_hw_set_parent(hws[IMX8MM_CLK_A53_SRC], hws[IMX8MM_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MM_CLK_A53_CORE], hws[IMX8MM_ARM_PLL_OUT]); + imx_check_clk_hws(hws, IMX8MM_CLK_END); ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); From 0d77abc4fc31e038c6c5b1f08f115eb022b3c4f5 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 25 Feb 2020 16:49:13 +0800 Subject: [PATCH 247/809] clk: imx8mp: A53 core clock no need to be critical 'A53_CORE' is just a mux and no need to be critical, being critical will cause its parent clock always ON which does NOT make sense, to make sure CPU's hardware clock source NOT being disabled during clock tree setup, need to move the 'A53_SRC'/'A53_CORE' reparent operations to after critical clock 'ARM_CLK' setup finished. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index c6161a4af201..c9e204edd247 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -557,7 +557,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_MEDIA_ISP_DIV] = imx_clk_hw_divider2("media_isp_div", "media_isp_cg", ccm_base + 0x8400, 0, 3); /* CORE SEL */ - hws[IMX8MP_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", ccm_base + 0x9880, 24, 1, imx8mp_a53_core_sels, ARRAY_SIZE(imx8mp_a53_core_sels), CLK_IS_CRITICAL); + hws[IMX8MP_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", ccm_base + 0x9880, 24, 1, imx8mp_a53_core_sels, ARRAY_SIZE(imx8mp_a53_core_sels)); hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800); hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880); @@ -729,15 +729,15 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_VPU_ROOT] = imx_clk_hw_gate4("vpu_root_clk", "vpu_bus", ccm_base + 0x4630, 0); hws[IMX8MP_CLK_AUDIO_ROOT] = imx_clk_hw_gate4("audio_root_clk", "ipg_root", ccm_base + 0x4650, 0); - clk_hw_set_parent(hws[IMX8MP_CLK_A53_SRC], hws[IMX8MP_SYS_PLL1_800M]); - clk_hw_set_parent(hws[IMX8MP_CLK_A53_CORE], hws[IMX8MP_ARM_PLL_OUT]); - hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", hws[IMX8MP_CLK_A53_CORE]->clk, hws[IMX8MP_CLK_A53_CORE]->clk, hws[IMX8MP_ARM_PLL_OUT]->clk, hws[IMX8MP_CLK_A53_DIV]->clk); + clk_hw_set_parent(hws[IMX8MP_CLK_A53_SRC], hws[IMX8MP_SYS_PLL1_800M]); + clk_hw_set_parent(hws[IMX8MP_CLK_A53_CORE], hws[IMX8MP_ARM_PLL_OUT]); + imx_check_clk_hws(hws, IMX8MP_CLK_END); of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); From b4fc6f72ddc1d4a53d3367b2d473e39d5d07a083 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 25 Feb 2020 16:49:14 +0800 Subject: [PATCH 248/809] clk: imx8mq: A53 core clock no need to be critical 'A53_CORE' is just a mux and no need to be critical, being critical will cause its parent clock always ON which does NOT make sense, to make sure CPU's hardware clock source NOT being disabled during clock tree setup, need to move the 'A53_SRC'/'A53_CORE' reparent operations to after critical clock 'ARM_CLK' setup finished. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index b81f02ab7eb1..fdc68db68de5 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -428,7 +428,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_CLK_GPU_SHADER_DIV] = hws[IMX8MQ_CLK_GPU_SHADER]; /* CORE SEL */ - hws[IMX8MQ_CLK_A53_CORE] = imx_clk_hw_mux2_flags("arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels), CLK_IS_CRITICAL); + hws[IMX8MQ_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels)); /* BUS */ hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800); @@ -593,15 +593,15 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc_25m", 1, 8); hws[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4); - clk_hw_set_parent(hws[IMX8MQ_CLK_A53_SRC], hws[IMX8MQ_SYS1_PLL_800M]); - clk_hw_set_parent(hws[IMX8MQ_CLK_A53_CORE], hws[IMX8MQ_ARM_PLL_OUT]); - hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core", hws[IMX8MQ_CLK_A53_CORE]->clk, hws[IMX8MQ_CLK_A53_CORE]->clk, hws[IMX8MQ_ARM_PLL_OUT]->clk, hws[IMX8MQ_CLK_A53_DIV]->clk); + clk_hw_set_parent(hws[IMX8MQ_CLK_A53_SRC], hws[IMX8MQ_SYS1_PLL_800M]); + clk_hw_set_parent(hws[IMX8MQ_CLK_A53_CORE], hws[IMX8MQ_ARM_PLL_OUT]); + imx_check_clk_hws(hws, IMX8MQ_CLK_END); err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); From eeb40fda056ce2f914fff000525ca5a7b2ddec50 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Mar 2020 10:48:48 +0100 Subject: [PATCH 249/809] dt-bindings: clock: renesas: cpg-mssr: Convert to json-schema Convert the Renesas Clock Pulse Generator / Module Standby and Software Reset Device Tree binding documentation to json-schema. Note that #reset-cells was incorrecty marked a required property for RZ/A2 before. Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200303094848.23670-1-geert+renesas@glider.be --- .../bindings/clock/renesas,cpg-mssr.txt | 100 --------------- .../bindings/clock/renesas,cpg-mssr.yaml | 119 ++++++++++++++++++ 2 files changed, 119 insertions(+), 100 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt create mode 100644 Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt deleted file mode 100644 index f4d153f24a0f..000000000000 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt +++ /dev/null @@ -1,100 +0,0 @@ -* Renesas Clock Pulse Generator / Module Standby and Software Reset - -On Renesas ARM SoCs (SH/R-Mobile, R-Car, RZ), the CPG (Clock Pulse Generator) -and MSSR (Module Standby and Software Reset) blocks are intimately connected, -and share the same register block. - -They provide the following functionalities: - - The CPG block generates various core clocks, - - The MSSR block provides two functions: - 1. Module Standby, providing a Clock Domain to control the clock supply - to individual SoC devices, - 2. Reset Control, to perform a software reset of individual SoC devices. - -Required Properties: - - compatible: Must be one of: - - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2) - - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) - - "renesas,r8a7744-cpg-mssr" for the r8a7744 SoC (RZ/G1N) - - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) - - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C) - - "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M) - - "renesas,r8a774b1-cpg-mssr" for the r8a774b1 SoC (RZ/G2N) - - "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E) - - "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2) - - "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W) - - "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H) - - "renesas,r8a7793-cpg-mssr" for the r8a7793 SoC (R-Car M2-N) - - "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2) - - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) - - "renesas,r8a7796-cpg-mssr" for the r8a77960 SoC (R-Car M3-W) - - "renesas,r8a77961-cpg-mssr" for the r8a77961 SoC (R-Car M3-W+) - - "renesas,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N) - - "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M) - - "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H) - - "renesas,r8a77990-cpg-mssr" for the r8a77990 SoC (R-Car E3) - - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3) - - - reg: Base address and length of the memory resource used by the CPG/MSSR - block - - - clocks: References to external parent clocks, one entry for each entry in - clock-names - - clock-names: List of external parent clock names. Valid names are: - - "extal" (r7s9210, r8a7743, r8a7744, r8a7745, r8a77470, r8a774a1, - r8a774b1, r8a774c0, r8a7790, r8a7791, r8a7792, r8a7793, - r8a7794, r8a7795, r8a77960, r8a77961, r8a77965, r8a77970, - r8a77980, r8a77990, r8a77995) - - "extalr" (r8a774a1, r8a774b1, r8a7795, r8a77960, r8a77961, r8a77965, - r8a77970, r8a77980) - - "usb_extal" (r8a7743, r8a7744, r8a7745, r8a77470, r8a7790, r8a7791, - r8a7793, r8a7794) - - - #clock-cells: Must be 2 - - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" - and a core clock reference, as defined in - . - - For module clocks, the two clock specifier cells must be "CPG_MOD" and - a module number, as defined in the datasheet. - - - #power-domain-cells: Must be 0 - - SoC devices that are part of the CPG/MSSR Clock Domain and can be - power-managed through Module Standby should refer to the CPG device - node in their "power-domains" property, as documented by the generic PM - Domain bindings in - Documentation/devicetree/bindings/power/power-domain.yaml. - - - #reset-cells: Must be 1 - - The single reset specifier cell must be the module number, as defined - in the datasheet. - - -Examples --------- - - - CPG device node: - - cpg: clock-controller@e6150000 { - compatible = "renesas,r8a7795-cpg-mssr"; - reg = <0 0xe6150000 0 0x1000>; - clocks = <&extal_clk>, <&extalr_clk>; - clock-names = "extal", "extalr"; - #clock-cells = <2>; - #power-domain-cells = <0>; - #reset-cells = <1>; - }; - - - - CPG/MSSR Clock Domain member device node: - - scif2: serial@e6e88000 { - compatible = "renesas,scif-r8a7795", "renesas,scif"; - reg = <0 0xe6e88000 0 64>; - interrupts = ; - clocks = <&cpg CPG_MOD 310>; - clock-names = "fck"; - dmas = <&dmac1 0x13>, <&dmac1 0x12>; - dma-names = "tx", "rx"; - power-domains = <&cpg>; - resets = <&cpg 310>; - }; diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml new file mode 100644 index 000000000000..9cd102e5fed5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/clock/renesas,cpg-mssr.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Renesas Clock Pulse Generator / Module Standby and Software Reset + +maintainers: + - Geert Uytterhoeven + +description: | + On Renesas ARM SoCs (SH/R-Mobile, R-Car, RZ), the CPG (Clock Pulse Generator) + and MSSR (Module Standby and Software Reset) blocks are intimately connected, + and share the same register block. + + They provide the following functionalities: + - The CPG block generates various core clocks, + - The MSSR block provides two functions: + 1. Module Standby, providing a Clock Domain to control the clock supply + to individual SoC devices, + 2. Reset Control, to perform a software reset of individual SoC devices. + +properties: + compatible: + enum: + - renesas,r7s9210-cpg-mssr # RZ/A2 + - renesas,r8a7743-cpg-mssr # RZ/G1M + - renesas,r8a7744-cpg-mssr # RZ/G1N + - renesas,r8a7745-cpg-mssr # RZ/G1E + - renesas,r8a77470-cpg-mssr # RZ/G1C + - renesas,r8a774a1-cpg-mssr # RZ/G2M + - renesas,r8a774b1-cpg-mssr # RZ/G2N + - renesas,r8a774c0-cpg-mssr # RZ/G2E + - renesas,r8a7790-cpg-mssr # R-Car H2 + - renesas,r8a7791-cpg-mssr # R-Car M2-W + - renesas,r8a7792-cpg-mssr # R-Car V2H + - renesas,r8a7793-cpg-mssr # R-Car M2-N + - renesas,r8a7794-cpg-mssr # R-Car E2 + - renesas,r8a7795-cpg-mssr # R-Car H3 + - renesas,r8a7796-cpg-mssr # R-Car M3-W + - renesas,r8a77961-cpg-mssr # R-Car M3-W+ + - renesas,r8a77965-cpg-mssr # R-Car M3-N + - renesas,r8a77970-cpg-mssr # R-Car V3M + - renesas,r8a77980-cpg-mssr # R-Car V3H + - renesas,r8a77990-cpg-mssr # R-Car E3 + - renesas,r8a77995-cpg-mssr # R-Car D3 + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + items: + enum: + - extal # All + - extalr # Most R-Car Gen3 and RZ/G2 + - usb_extal # Most R-Car Gen2 and RZ/G1 + + '#clock-cells': + description: | + - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" + and a core clock reference, as defined in + + - For module clocks, the two clock specifier cells must be "CPG_MOD" and + a module number, as defined in the datasheet. + const: 2 + + '#power-domain-cells': + description: + SoC devices that are part of the CPG/MSSR Clock Domain and can be + power-managed through Module Standby should refer to the CPG device node + in their "power-domains" property, as documented by the generic PM Domain + bindings in Documentation/devicetree/bindings/power/power-domain.yaml. + const: 0 + + '#reset-cells': + description: + The single reset specifier cell must be the module number, as defined in + the datasheet. + const: 1 + +if: + not: + properties: + compatible: + items: + enum: + - renesas,r7s9210-cpg-mssr +then: + required: + - '#reset-cells' + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a7795-cpg-mssr"; + reg = <0xe6150000 0x1000>; + clocks = <&extal_clk>, <&extalr_clk>; + clock-names = "extal", "extalr"; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; From 8719b6d29d2851fa84c4074bb2e5adc022911ab8 Mon Sep 17 00:00:00 2001 From: afzal mohammed Date: Wed, 4 Mar 2020 06:20:48 +0530 Subject: [PATCH 250/809] s390/irq: replace setup_irq() by request_irq() request_irq() is preferred over setup_irq(). Invocations of setup_irq() occur after memory allocators are ready. Per tglx[1], setup_irq() existed in olden days when allocators were not ready by the time early interrupts were initialized. Hence replace setup_irq() by request_irq(). [1] https://lkml.kernel.org/r/alpine.DEB.2.20.1710191609480.1971@nanos Signed-off-by: afzal mohammed Message-Id: <20200304005049.5291-1-afzal.mohd.ma@gmail.com> [heiko.carstens@de.ibm.com: replace pr_err with panic] Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/irq.c | 8 ++------ drivers/s390/cio/airq.c | 8 ++------ drivers/s390/cio/cio.c | 8 ++------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 8371855042dc..da550cb8b31b 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -294,11 +294,6 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -static struct irqaction external_interrupt = { - .name = "EXT", - .handler = do_ext_interrupt, -}; - void __init init_ext_interrupts(void) { int idx; @@ -308,7 +303,8 @@ void __init init_ext_interrupts(void) irq_set_chip_and_handler(EXT_INTERRUPT, &dummy_irq_chip, handle_percpu_irq); - setup_irq(EXT_INTERRUPT, &external_interrupt); + if (request_irq(EXT_INTERRUPT, do_ext_interrupt, 0, "EXT", NULL)) + panic("Failed to register EXT interrupt\n"); } static DEFINE_SPINLOCK(irq_subclass_lock); diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 427b2e24a8ce..cb466ed7eb5e 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -105,16 +105,12 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -static struct irqaction airq_interrupt = { - .name = "AIO", - .handler = do_airq_interrupt, -}; - void __init init_airq_interrupts(void) { irq_set_chip_and_handler(THIN_INTERRUPT, &dummy_irq_chip, handle_percpu_irq); - setup_irq(THIN_INTERRUPT, &airq_interrupt); + if (request_irq(THIN_INTERRUPT, do_airq_interrupt, 0, "AIO", NULL)) + panic("Failed to register AIO interrupt\n"); } static inline unsigned long iv_size(unsigned long bits) diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 18f5458f90e8..6d716db2a46a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -563,16 +563,12 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -static struct irqaction io_interrupt = { - .name = "I/O", - .handler = do_cio_interrupt, -}; - void __init init_cio_interrupts(void) { irq_set_chip_and_handler(IO_INTERRUPT, &dummy_irq_chip, handle_percpu_irq); - setup_irq(IO_INTERRUPT, &io_interrupt); + if (request_irq(IO_INTERRUPT, do_cio_interrupt, 0, "I/O", NULL)) + panic("Failed to register I/O interrupt\n"); } #ifdef CONFIG_CCW_CONSOLE From 76fb118083eaf63f506fcbe695c1b12a38971b7a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 Mar 2020 10:25:51 +0100 Subject: [PATCH 251/809] s390/irq: make init_ext_interrupts static Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/hw_irq.h | 1 - arch/s390/kernel/irq.c | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/s390/include/asm/hw_irq.h b/arch/s390/include/asm/hw_irq.h index adae176757ae..9078b5b6b837 100644 --- a/arch/s390/include/asm/hw_irq.h +++ b/arch/s390/include/asm/hw_irq.h @@ -7,6 +7,5 @@ void __init init_airq_interrupts(void); void __init init_cio_interrupts(void); -void __init init_ext_interrupts(void); #endif diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index da550cb8b31b..3514420f0259 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -95,14 +95,6 @@ static const struct irq_class irqclass_sub_desc[] = { {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"}, }; -void __init init_IRQ(void) -{ - BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS); - init_cio_interrupts(); - init_airq_interrupts(); - init_ext_interrupts(); -} - void do_IRQ(struct pt_regs *regs, int irq) { struct pt_regs *old_regs; @@ -294,7 +286,7 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -void __init init_ext_interrupts(void) +static void __init init_ext_interrupts(void) { int idx; @@ -307,6 +299,14 @@ void __init init_ext_interrupts(void) panic("Failed to register EXT interrupt\n"); } +void __init init_IRQ(void) +{ + BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS); + init_cio_interrupts(); + init_airq_interrupts(); + init_ext_interrupts(); +} + static DEFINE_SPINLOCK(irq_subclass_lock); static unsigned char irq_subclass_refcount[64]; From 1d49688d2bc6406d74566bca35b3d67201a906fc Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 Mar 2020 10:29:43 +0100 Subject: [PATCH 252/809] s390/traps: mark test_monitor_call __init Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index dc75588d7894..ff9cc4c3290e 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -271,7 +271,7 @@ void kernel_stack_overflow(struct pt_regs *regs) } NOKPROBE_SYMBOL(kernel_stack_overflow); -static void test_monitor_call(void) +static void __init test_monitor_call(void) { int val = 1; From bb533ec8bacd064ee273ca3305db97938c3331ae Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 10 Mar 2020 09:01:44 +0100 Subject: [PATCH 253/809] s390/config: do not select VIRTIO_CONSOLE via Kconfig select does not ensure that dependencies are also selected. Instead of selecting VIRTIO_CONSOLE from S390_GUEST we should rather add this to the defconfigs. So we update those as well. Reported-by: Michael S. Tsirkin Signed-off-by: Christian Borntraeger Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 1 - arch/s390/configs/debug_defconfig | 1 + arch/s390/configs/defconfig | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f4ff75ff62f2..334f3f2199e8 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -953,7 +953,6 @@ config S390_GUEST select TTY select VIRTUALIZATION select VIRTIO - select VIRTIO_CONSOLE help Enabling this option adds support for virtio based paravirtual device drivers on s390. diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 2e60c80395ab..4ca5c7499cce 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -532,6 +532,7 @@ CONFIG_INPUT_EVDEV=y # CONFIG_SERIO is not set CONFIG_LEGACY_PTY_COUNT=0 CONFIG_NULL_TTY=m +CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM_VIRTIO=m CONFIG_RAW_DRIVER=m CONFIG_HANGCHECK_TIMER=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 25f799849582..c0950750fb50 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -528,6 +528,7 @@ CONFIG_INPUT_EVDEV=y # CONFIG_SERIO is not set CONFIG_LEGACY_PTY_COUNT=0 CONFIG_NULL_TTY=m +CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM_VIRTIO=m CONFIG_RAW_DRIVER=m CONFIG_HANGCHECK_TIMER=m From 583b53ece0b0268c542a1eafadb62e3d4b0aab8c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 9 Mar 2020 00:51:43 +0300 Subject: [PATCH 254/809] power: supply: bq27xxx_battery: Silence deferred-probe error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver fails to probe with -EPROBE_DEFER if battery's power supply (charger driver) isn't ready yet and this results in a bit noisy error message in KMSG during kernel's boot up. Let's silence the harmless error message. Signed-off-by: Dmitry Osipenko Reviewed-by: Andrew F. Davis Reviewed-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 195c18c2f426..664e50103eaa 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1885,7 +1885,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) { - dev_err(di->dev, "failed to register battery\n"); + if (PTR_ERR(di->bat) == -EPROBE_DEFER) + dev_dbg(di->dev, "failed to register battery, deferring probe\n"); + else + dev_err(di->dev, "failed to register battery\n"); return PTR_ERR(di->bat); } From 9027f6111ca40dcc703e1cf6129a73703ae299b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2020 10:08:18 +0100 Subject: [PATCH 255/809] power: twl4030: Use scnprintf() for avoiding potential buffer overflow Since snprintf() returns the would-be-output size instead of the actual output size, the succeeding calls may go beyond the given buffer limit. Fix it by replacing with scnprintf(). Signed-off-by: Takashi Iwai Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 648ab80288c9..1bc49b2e12e8 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -726,10 +726,10 @@ twl4030_bci_mode_show(struct device *dev, for (i = 0; i < ARRAY_SIZE(modes); i++) if (mode == i) - len += snprintf(buf+len, PAGE_SIZE-len, + len += scnprintf(buf+len, PAGE_SIZE-len, "[%s] ", modes[i]); else - len += snprintf(buf+len, PAGE_SIZE-len, + len += scnprintf(buf+len, PAGE_SIZE-len, "%s ", modes[i]); buf[len-1] = '\n'; return len; From 6cdd5b09cbe67365c42aee539f6fd00f2ecfdaab Mon Sep 17 00:00:00 2001 From: Sherry Zong Date: Mon, 9 Mar 2020 16:18:44 +0800 Subject: [PATCH 256/809] power: reset: sc27xx: Power off the external subsystems' connection When powering off the whole system, we should power off some external subsystems' connection firstly, otherwise some external subsystems will hold some power and result in powering down abnormally. Signed-off-by: Sherry Zong Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/sc27xx-poweroff.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 29fb08b8faa0..2bedd4c58ddc 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -13,6 +13,8 @@ #define SC27XX_PWR_PD_HW 0xc2c #define SC27XX_PWR_OFF_EN BIT(0) +#define SC27XX_SLP_CTRL 0xdf0 +#define SC27XX_LDO_XTL_EN BIT(3) static struct regmap *regmap; @@ -40,6 +42,9 @@ static struct syscore_ops poweroff_syscore_ops = { static void sc27xx_poweroff_do_poweroff(void) { + /* Disable the external subsys connection's power firstly */ + regmap_write(regmap, SC27XX_SLP_CTRL, SC27XX_LDO_XTL_EN); + regmap_write(regmap, SC27XX_PWR_PD_HW, SC27XX_PWR_OFF_EN); } From 274afbc3ad33136962d66447e89d02e3c142a30a Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 9 Mar 2020 16:18:45 +0800 Subject: [PATCH 257/809] power: reset: sc27xx: Change to use cpu_down() To allow the SC27XX driver can be built as a module, and the freeze_secondary_cpus() symbol is not exported, thus we can change to use the exported cpu_down() API to shut down other cpus to avoid racing, which is same as the freeze_secondary_cpus(). Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/sc27xx-poweroff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 2bedd4c58ddc..91b5eceeb810 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -29,10 +29,13 @@ static struct regmap *regmap; */ static void sc27xx_poweroff_shutdown(void) { -#ifdef CONFIG_PM_SLEEP_SMP - int cpu = smp_processor_id(); +#ifdef CONFIG_HOTPLUG_CPU + int cpu; - freeze_secondary_cpus(cpu); + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } #endif } From f78c55e3b4806974f7d590b2aab8683232b7bd25 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 9 Mar 2020 16:18:46 +0800 Subject: [PATCH 258/809] power: reset: sc27xx: Allow the SC27XX poweroff driver building into a module Change the config to 'tristate' and use module_platform_driver() to allow the SC27XX poweroff driver building into a module, as well as adding some mudule information. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 2 +- drivers/power/reset/sc27xx-poweroff.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 513efe8e7628..890380302080 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -248,7 +248,7 @@ config SYSCON_REBOOT_MODE action according to the mode. config POWER_RESET_SC27XX - bool "Spreadtrum SC27xx PMIC power-off driver" + tristate "Spreadtrum SC27xx PMIC power-off driver" depends on MFD_SC27XX_PMIC || COMPILE_TEST help This driver supports powering off a system through diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 91b5eceeb810..69863074daf6 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -71,4 +72,8 @@ static struct platform_driver sc27xx_poweroff_driver = { .name = "sc27xx-poweroff", }, }; -builtin_platform_driver(sc27xx_poweroff_driver); +module_platform_driver(sc27xx_poweroff_driver); + +MODULE_DESCRIPTION("Power off driver for SC27XX PMIC Device"); +MODULE_AUTHOR("Baolin Wang "); +MODULE_LICENSE("GPL v2"); From 9a85eb4d62425555ccdc774d906e6bbca5ffccc0 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:07 -0800 Subject: [PATCH 259/809] clk: tegra: Add support for OSC_DIV fixed clocks Tegra30 through Tegra210 has OSC_DIV2 and OSC_DIV4 fixed clocks from the OSC pads. This patch adds support for these clocks. Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-id.h | 2 ++ drivers/clk/tegra/clk-tegra-fixed.c | 16 ++++++++++++++++ drivers/clk/tegra/clk-tegra114.c | 4 ++++ drivers/clk/tegra/clk-tegra124.c | 4 ++++ drivers/clk/tegra/clk-tegra210.c | 4 ++++ drivers/clk/tegra/clk-tegra30.c | 4 ++++ 6 files changed, 34 insertions(+) diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index c4faebd32760..17d8b252cd0a 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -46,6 +46,8 @@ enum clk_id { tegra_clk_clk_m, tegra_clk_clk_m_div2, tegra_clk_clk_m_div4, + tegra_clk_osc_div2, + tegra_clk_osc_div4, tegra_clk_clk_out_1, tegra_clk_clk_out_1_mux, tegra_clk_clk_out_2, diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index 7c6c8abfcde6..990106391334 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -48,6 +48,22 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq); + /* osc_div2 */ + dt_clk = tegra_lookup_dt_id(tegra_clk_osc_div2, clks); + if (dt_clk) { + clk = clk_register_fixed_factor(NULL, "osc_div2", "osc", + 0, 1, 2); + *dt_clk = clk; + } + + /* osc_div4 */ + dt_clk = tegra_lookup_dt_id(tegra_clk_osc_div4, clks); + if (dt_clk) { + clk = clk_register_fixed_factor(NULL, "osc_div4", "osc", + 0, 1, 4); + *dt_clk = clk; + } + dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks); if (!dt_clk) return 0; diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 4efcaaf51b3a..d44cb8db0ef6 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -737,6 +737,8 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA114_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA114_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA114_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc_div2] = { .dt_id = TEGRA114_CLK_OSC_DIV2, .present = true }, + [tegra_clk_osc_div4] = { .dt_id = TEGRA114_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA114_CLK_PLL_REF, .present = true }, [tegra_clk_pll_c] = { .dt_id = TEGRA114_CLK_PLL_C, .present = true }, [tegra_clk_pll_c_out1] = { .dt_id = TEGRA114_CLK_PLL_C_OUT1, .present = true }, @@ -817,6 +819,8 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA114_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA114_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA114_CLK_CLK_M_DIV4 }, + { .con_id = "osc_div2", .dt_id = TEGRA114_CLK_OSC_DIV2 }, + { .con_id = "osc_div4", .dt_id = TEGRA114_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA114_CLK_PLL_C }, { .con_id = "pll_c_out1", .dt_id = TEGRA114_CLK_PLL_C_OUT1 }, { .con_id = "pll_c2", .dt_id = TEGRA114_CLK_PLL_C2 }, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index b3110d5b5a6c..32f3dd1ccbad 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -862,6 +862,8 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA124_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA124_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA124_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc_div2] = { .dt_id = TEGRA124_CLK_OSC_DIV2, .present = true }, + [tegra_clk_osc_div4] = { .dt_id = TEGRA124_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA124_CLK_PLL_REF, .present = true }, [tegra_clk_pll_c] = { .dt_id = TEGRA124_CLK_PLL_C, .present = true }, [tegra_clk_pll_c_out1] = { .dt_id = TEGRA124_CLK_PLL_C_OUT1, .present = true }, @@ -943,6 +945,8 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA124_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA124_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA124_CLK_CLK_M_DIV4 }, + { .con_id = "osc_div2", .dt_id = TEGRA124_CLK_OSC_DIV2 }, + { .con_id = "osc_div4", .dt_id = TEGRA124_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA124_CLK_PLL_C }, { .con_id = "pll_c_out1", .dt_id = TEGRA124_CLK_PLL_C_OUT1 }, { .con_id = "pll_c2", .dt_id = TEGRA124_CLK_PLL_C2 }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 762cd186f714..899d8ca68c4f 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2373,6 +2373,8 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc_div2] = { .dt_id = TEGRA210_CLK_OSC_DIV2, .present = true }, + [tegra_clk_osc_div4] = { .dt_id = TEGRA210_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true }, [tegra_clk_pll_c] = { .dt_id = TEGRA210_CLK_PLL_C, .present = true }, [tegra_clk_pll_c_out1] = { .dt_id = TEGRA210_CLK_PLL_C_OUT1, .present = true }, @@ -2499,6 +2501,8 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 }, + { .con_id = "osc_div2", .dt_id = TEGRA210_CLK_OSC_DIV2 }, + { .con_id = "osc_div4", .dt_id = TEGRA210_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C }, { .con_id = "pll_c_out1", .dt_id = TEGRA210_CLK_PLL_C_OUT1 }, { .con_id = "pll_c2", .dt_id = TEGRA210_CLK_PLL_C2 }, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index b20891489e11..7e62d9ae377c 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -583,6 +583,8 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA30_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA30_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA30_CLK_CLK_M_DIV4 }, + { .con_id = "osc_div2", .dt_id = TEGRA30_CLK_OSC_DIV2 }, + { .con_id = "osc_div4", .dt_id = TEGRA30_CLK_OSC_DIV4 }, { .con_id = "cml0", .dt_id = TEGRA30_CLK_CML0 }, { .con_id = "cml1", .dt_id = TEGRA30_CLK_CML1 }, { .con_id = "clk_m", .dt_id = TEGRA30_CLK_CLK_M }, @@ -685,6 +687,8 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA30_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA30_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA30_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc_div2] = { .dt_id = TEGRA30_CLK_OSC_DIV2, .present = true }, + [tegra_clk_osc_div4] = { .dt_id = TEGRA30_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA30_CLK_PLL_REF, .present = true }, [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA30_CLK_SPDIF_IN_SYNC, .present = true }, [tegra_clk_i2s0_sync] = { .dt_id = TEGRA30_CLK_I2S0_SYNC, .present = true }, From 2b50e49b093c6f4c03faaf06d6b67707fab40938 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:08 -0800 Subject: [PATCH 260/809] clk: tegra: Add Tegra OSC to clock lookup OSC is one of the parent for Tegra PMC clocks clk_out_1, clk_out_2, and clk_out_3. This patch adds Tegra OSC to clock lookup. Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-id.h | 1 + drivers/clk/tegra/clk-tegra-fixed.c | 5 +++++ drivers/clk/tegra/clk-tegra114.c | 2 ++ drivers/clk/tegra/clk-tegra124.c | 2 ++ drivers/clk/tegra/clk-tegra210.c | 2 ++ drivers/clk/tegra/clk-tegra30.c | 2 ++ 6 files changed, 14 insertions(+) diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 17d8b252cd0a..17c13d1aa6bc 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -46,6 +46,7 @@ enum clk_id { tegra_clk_clk_m, tegra_clk_clk_m_div2, tegra_clk_clk_m_div4, + tegra_clk_osc, tegra_clk_osc_div2, tegra_clk_osc_div4, tegra_clk_clk_out_1, diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index 990106391334..0dc2d5f5cfb5 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -46,7 +46,12 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, return -EINVAL; } + dt_clk = tegra_lookup_dt_id(tegra_clk_osc, clks); + if (!dt_clk) + return 0; + osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq); + *dt_clk = osc; /* osc_div2 */ dt_clk = tegra_lookup_dt_id(tegra_clk_osc_div2, clks); diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index d44cb8db0ef6..e3c68eca54b7 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -737,6 +737,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA114_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA114_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA114_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc] = { .dt_id = TEGRA114_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA114_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA114_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA114_CLK_PLL_REF, .present = true }, @@ -819,6 +820,7 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA114_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA114_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA114_CLK_CLK_M_DIV4 }, + { .con_id = "osc", .dt_id = TEGRA114_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA114_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA114_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA114_CLK_PLL_C }, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 32f3dd1ccbad..ef0f928f0259 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -862,6 +862,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA124_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA124_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA124_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc] = { .dt_id = TEGRA124_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA124_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA124_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA124_CLK_PLL_REF, .present = true }, @@ -945,6 +946,7 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA124_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA124_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA124_CLK_CLK_M_DIV4 }, + { .con_id = "osc", .dt_id = TEGRA124_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA124_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA124_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA124_CLK_PLL_C }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 899d8ca68c4f..958f5f6c894d 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2373,6 +2373,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc] = { .dt_id = TEGRA210_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA210_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA210_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true }, @@ -2501,6 +2502,7 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 }, + { .con_id = "osc", .dt_id = TEGRA210_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA210_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA210_CLK_OSC_DIV4 }, { .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C }, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 7e62d9ae377c..0ba9958724a6 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -583,6 +583,7 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_32k", .dt_id = TEGRA30_CLK_CLK_32K }, { .con_id = "clk_m_div2", .dt_id = TEGRA30_CLK_CLK_M_DIV2 }, { .con_id = "clk_m_div4", .dt_id = TEGRA30_CLK_CLK_M_DIV4 }, + { .con_id = "osc", .dt_id = TEGRA30_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA30_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA30_CLK_OSC_DIV4 }, { .con_id = "cml0", .dt_id = TEGRA30_CLK_CML0 }, @@ -687,6 +688,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_m] = { .dt_id = TEGRA30_CLK_CLK_M, .present = true }, [tegra_clk_clk_m_div2] = { .dt_id = TEGRA30_CLK_CLK_M_DIV2, .present = true }, [tegra_clk_clk_m_div4] = { .dt_id = TEGRA30_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_osc] = { .dt_id = TEGRA30_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA30_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA30_CLK_OSC_DIV4, .present = true }, [tegra_clk_pll_ref] = { .dt_id = TEGRA30_CLK_PLL_REF, .present = true }, From 6fe38aa8cac3a5db38154331742835a4d9740788 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:09 -0800 Subject: [PATCH 261/809] clk: tegra: Fix Tegra PMC clock out parents Tegra PMC clocks clk_out_1, clk_out_2, and clk_out_3 supported parents are osc, osc_div2, osc_div4 and extern clock. Clock driver is using incorrect parents clk_m, clk_m_div2, clk_m_div4 for PMC clocks. This patch fixes this. Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-pmc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c index bec3e008335f..5e044ba1ae36 100644 --- a/drivers/clk/tegra/clk-tegra-pmc.c +++ b/drivers/clk/tegra/clk-tegra-pmc.c @@ -49,16 +49,16 @@ struct pmc_clk_init_data { static DEFINE_SPINLOCK(clk_out_lock); -static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern1", +static const char *clk_out1_parents[] = { "osc", "osc_div2", + "osc_div4", "extern1", }; -static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern2", +static const char *clk_out2_parents[] = { "osc", "osc_div2", + "osc_div4", "extern2", }; -static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern3", +static const char *clk_out3_parents[] = { "osc", "osc_div2", + "osc_div4", "extern3", }; static struct pmc_clk_init_data pmc_clks[] = { From c9e28c25a0d05ff658a1abcf54b13311a3bfb960 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:10 -0800 Subject: [PATCH 262/809] clk: tegra: Remove CLK_M_DIV fixed clocks Tegra has no CLK_M_DIV2 and CLK_M_DIV4 clocks and instead it has OSC_DIV2 and OSC_DIV4 clocks from OSC pads which are the possible parents of PMC clocks for Tegra30 through Tegra210. Tegra PMC clock parents are changed to use OSC_DIV clocks. So, this patch removes CLK_M_DIV fixed clocks Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-id.h | 2 -- drivers/clk/tegra/clk-tegra-fixed.c | 16 ---------------- drivers/clk/tegra/clk-tegra114.c | 15 --------------- drivers/clk/tegra/clk-tegra124.c | 4 ---- drivers/clk/tegra/clk-tegra210.c | 4 ---- drivers/clk/tegra/clk-tegra30.c | 4 ---- 6 files changed, 45 deletions(-) diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 17c13d1aa6bc..cf42e5995794 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -44,8 +44,6 @@ enum clk_id { tegra_clk_clk72Mhz, tegra_clk_clk72Mhz_8, tegra_clk_clk_m, - tegra_clk_clk_m_div2, - tegra_clk_clk_m_div4, tegra_clk_osc, tegra_clk_osc_div2, tegra_clk_osc_div4, diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index 0dc2d5f5cfb5..77c22cef5014 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -105,22 +105,6 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768); *dt_clk = clk; } - - /* clk_m_div2 */ - dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks); - if (dt_clk) { - clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", - CLK_SET_RATE_PARENT, 1, 2); - *dt_clk = clk; - } - - /* clk_m_div4 */ - dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks); - if (dt_clk) { - clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", - CLK_SET_RATE_PARENT, 1, 4); - *dt_clk = clk; - } } void tegra_clk_osc_resume(void __iomem *clk_base) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index e3c68eca54b7..180ddc2abfd2 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -735,8 +735,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_fuse_burn] = { .dt_id = TEGRA114_CLK_FUSE_BURN, .present = true }, [tegra_clk_clk_32k] = { .dt_id = TEGRA114_CLK_CLK_32K, .present = true }, [tegra_clk_clk_m] = { .dt_id = TEGRA114_CLK_CLK_M, .present = true }, - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA114_CLK_CLK_M_DIV2, .present = true }, - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA114_CLK_CLK_M_DIV4, .present = true }, [tegra_clk_osc] = { .dt_id = TEGRA114_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA114_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA114_CLK_OSC_DIV4, .present = true }, @@ -818,8 +816,6 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_m", .dt_id = TEGRA114_CLK_CLK_M }, { .con_id = "pll_ref", .dt_id = TEGRA114_CLK_PLL_REF }, { .con_id = "clk_32k", .dt_id = TEGRA114_CLK_CLK_32K }, - { .con_id = "clk_m_div2", .dt_id = TEGRA114_CLK_CLK_M_DIV2 }, - { .con_id = "clk_m_div4", .dt_id = TEGRA114_CLK_CLK_M_DIV4 }, { .con_id = "osc", .dt_id = TEGRA114_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA114_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA114_CLK_OSC_DIV4 }, @@ -906,17 +902,6 @@ static void __init tegra114_fixed_clk_init(void __iomem *clk_base) /* clk_32k */ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768); clks[TEGRA114_CLK_CLK_32K] = clk; - - /* clk_m_div2 */ - clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", - CLK_SET_RATE_PARENT, 1, 2); - clks[TEGRA114_CLK_CLK_M_DIV2] = clk; - - /* clk_m_div4 */ - clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", - CLK_SET_RATE_PARENT, 1, 4); - clks[TEGRA114_CLK_CLK_M_DIV4] = clk; - } static void __init tegra114_pll_init(void __iomem *clk_base, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index ef0f928f0259..7a16e50eb20f 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -860,8 +860,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_fuse_burn] = { .dt_id = TEGRA124_CLK_FUSE_BURN, .present = true }, [tegra_clk_clk_32k] = { .dt_id = TEGRA124_CLK_CLK_32K, .present = true }, [tegra_clk_clk_m] = { .dt_id = TEGRA124_CLK_CLK_M, .present = true }, - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA124_CLK_CLK_M_DIV2, .present = true }, - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA124_CLK_CLK_M_DIV4, .present = true }, [tegra_clk_osc] = { .dt_id = TEGRA124_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA124_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA124_CLK_OSC_DIV4, .present = true }, @@ -944,8 +942,6 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_m", .dt_id = TEGRA124_CLK_CLK_M }, { .con_id = "pll_ref", .dt_id = TEGRA124_CLK_PLL_REF }, { .con_id = "clk_32k", .dt_id = TEGRA124_CLK_CLK_32K }, - { .con_id = "clk_m_div2", .dt_id = TEGRA124_CLK_CLK_M_DIV2 }, - { .con_id = "clk_m_div4", .dt_id = TEGRA124_CLK_CLK_M_DIV4 }, { .con_id = "osc", .dt_id = TEGRA124_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA124_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA124_CLK_OSC_DIV4 }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 958f5f6c894d..45d54ead30bc 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2371,8 +2371,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_fuse_burn] = { .dt_id = TEGRA210_CLK_FUSE_BURN, .present = true }, [tegra_clk_clk_32k] = { .dt_id = TEGRA210_CLK_CLK_32K, .present = true }, [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true }, - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true }, - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true }, [tegra_clk_osc] = { .dt_id = TEGRA210_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA210_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA210_CLK_OSC_DIV4, .present = true }, @@ -2500,8 +2498,6 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "clk_m", .dt_id = TEGRA210_CLK_CLK_M }, { .con_id = "pll_ref", .dt_id = TEGRA210_CLK_PLL_REF }, { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K }, - { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 }, - { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 }, { .con_id = "osc", .dt_id = TEGRA210_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA210_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA210_CLK_OSC_DIV4 }, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 0ba9958724a6..c54fe3d4fe99 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -581,8 +581,6 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "twd", .dt_id = TEGRA30_CLK_TWD }, { .con_id = "emc", .dt_id = TEGRA30_CLK_EMC }, { .con_id = "clk_32k", .dt_id = TEGRA30_CLK_CLK_32K }, - { .con_id = "clk_m_div2", .dt_id = TEGRA30_CLK_CLK_M_DIV2 }, - { .con_id = "clk_m_div4", .dt_id = TEGRA30_CLK_CLK_M_DIV4 }, { .con_id = "osc", .dt_id = TEGRA30_CLK_OSC }, { .con_id = "osc_div2", .dt_id = TEGRA30_CLK_OSC_DIV2 }, { .con_id = "osc_div4", .dt_id = TEGRA30_CLK_OSC_DIV4 }, @@ -686,8 +684,6 @@ static struct tegra_devclk devclks[] __initdata = { static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_32k] = { .dt_id = TEGRA30_CLK_CLK_32K, .present = true }, [tegra_clk_clk_m] = { .dt_id = TEGRA30_CLK_CLK_M, .present = true }, - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA30_CLK_CLK_M_DIV2, .present = true }, - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA30_CLK_CLK_M_DIV4, .present = true }, [tegra_clk_osc] = { .dt_id = TEGRA30_CLK_OSC, .present = true }, [tegra_clk_osc_div2] = { .dt_id = TEGRA30_CLK_OSC_DIV2, .present = true }, [tegra_clk_osc_div4] = { .dt_id = TEGRA30_CLK_OSC_DIV4, .present = true }, From acbeec3d376cb17b627a674dae049934d15c57e6 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:25 -0800 Subject: [PATCH 263/809] clk: tegra: Remove tegra_pmc_clk_init along with clk ids Current Tegra clock driver registers PMC clocks clk_out_1, clk_out_2, clk_out_3 and 32KHz blink output in tegra_pmc_init() which does direct PMC register access during clk_ops and these PMC register read and write access will not happen when PMC is in secure mode. Any direct PMC register access from non-secure world will not go through. All the PMC clocks are moved to Tegra PMC driver with PMC as a clock provider. This patch removes tegra_pmc_clk_init along with corresponding clk ids from Tegra clock driver. Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/Makefile | 1 - drivers/clk/tegra/clk-id.h | 7 -- drivers/clk/tegra/clk-tegra-pmc.c | 122 ------------------------------ drivers/clk/tegra/clk-tegra114.c | 17 +---- drivers/clk/tegra/clk-tegra124.c | 33 +++----- drivers/clk/tegra/clk-tegra20.c | 4 - drivers/clk/tegra/clk-tegra210.c | 17 +---- drivers/clk/tegra/clk-tegra30.c | 18 +---- drivers/clk/tegra/clk.h | 1 - 9 files changed, 19 insertions(+), 201 deletions(-) delete mode 100644 drivers/clk/tegra/clk-tegra-pmc.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index df966ca06788..1f7c30f87ece 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -12,7 +12,6 @@ obj-y += clk-sdmmc-mux.o obj-y += clk-super.o obj-y += clk-tegra-audio.o obj-y += clk-tegra-periph.o -obj-y += clk-tegra-pmc.o obj-y += clk-tegra-fixed.o obj-y += clk-tegra-super-gen4.o obj-$(CONFIG_TEGRA_CLK_EMC) += clk-emc.o diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index cf42e5995794..ff7da2d3e94d 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -32,7 +32,6 @@ enum clk_id { tegra_clk_audio4, tegra_clk_audio4_2x, tegra_clk_audio4_mux, - tegra_clk_blink, tegra_clk_bsea, tegra_clk_bsev, tegra_clk_cclk_g, @@ -47,12 +46,6 @@ enum clk_id { tegra_clk_osc, tegra_clk_osc_div2, tegra_clk_osc_div4, - tegra_clk_clk_out_1, - tegra_clk_clk_out_1_mux, - tegra_clk_clk_out_2, - tegra_clk_clk_out_2_mux, - tegra_clk_clk_out_3, - tegra_clk_clk_out_3_mux, tegra_clk_cml0, tegra_clk_cml1, tegra_clk_csi, diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c deleted file mode 100644 index 5e044ba1ae36..000000000000 --- a/drivers/clk/tegra/clk-tegra-pmc.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" -#include "clk-id.h" - -#define PMC_CLK_OUT_CNTRL 0x1a8 -#define PMC_DPD_PADS_ORIDE 0x1c -#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 -#define PMC_CTRL 0 -#define PMC_CTRL_BLINK_ENB 7 -#define PMC_BLINK_TIMER 0x40 - -struct pmc_clk_init_data { - char *mux_name; - char *gate_name; - const char **parents; - int num_parents; - int mux_id; - int gate_id; - char *dev_name; - u8 mux_shift; - u8 gate_shift; -}; - -#define PMC_CLK(_num, _mux_shift, _gate_shift)\ - {\ - .mux_name = "clk_out_" #_num "_mux",\ - .gate_name = "clk_out_" #_num,\ - .parents = clk_out ##_num ##_parents,\ - .num_parents = ARRAY_SIZE(clk_out ##_num ##_parents),\ - .mux_id = tegra_clk_clk_out_ ##_num ##_mux,\ - .gate_id = tegra_clk_clk_out_ ##_num,\ - .dev_name = "extern" #_num,\ - .mux_shift = _mux_shift,\ - .gate_shift = _gate_shift,\ - } - -static DEFINE_SPINLOCK(clk_out_lock); - -static const char *clk_out1_parents[] = { "osc", "osc_div2", - "osc_div4", "extern1", -}; - -static const char *clk_out2_parents[] = { "osc", "osc_div2", - "osc_div4", "extern2", -}; - -static const char *clk_out3_parents[] = { "osc", "osc_div2", - "osc_div4", "extern3", -}; - -static struct pmc_clk_init_data pmc_clks[] = { - PMC_CLK(1, 6, 2), - PMC_CLK(2, 14, 10), - PMC_CLK(3, 22, 18), -}; - -void __init tegra_pmc_clk_init(void __iomem *pmc_base, - struct tegra_clk *tegra_clks) -{ - struct clk *clk; - struct clk **dt_clk; - int i; - - for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) { - struct pmc_clk_init_data *data; - - data = pmc_clks + i; - - dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks); - if (!dt_clk) - continue; - - clk = clk_register_mux(NULL, data->mux_name, data->parents, - data->num_parents, - CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, - pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift, - 3, 0, &clk_out_lock); - *dt_clk = clk; - - - dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks); - if (!dt_clk) - continue; - - clk = clk_register_gate(NULL, data->gate_name, data->mux_name, - CLK_SET_RATE_PARENT, - pmc_base + PMC_CLK_OUT_CNTRL, - data->gate_shift, 0, &clk_out_lock); - *dt_clk = clk; - clk_register_clkdev(clk, data->dev_name, data->gate_name); - } - - /* blink */ - writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); - clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, - pmc_base + PMC_DPD_PADS_ORIDE, - PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); - - dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks); - if (!dt_clk) - return; - - clk = clk_register_gate(NULL, "blink", "blink_override", 0, - pmc_base + PMC_CTRL, - PMC_CTRL_BLINK_ENB, 0, NULL); - clk_register_clkdev(clk, "blink", NULL); - *dt_clk = clk; -} - diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 180ddc2abfd2..c138ef75480b 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -779,10 +779,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3] = { .dt_id = TEGRA114_CLK_AUDIO3, .present = true }, [tegra_clk_audio4] = { .dt_id = TEGRA114_CLK_AUDIO4, .present = true }, [tegra_clk_spdif] = { .dt_id = TEGRA114_CLK_SPDIF, .present = true }, - [tegra_clk_clk_out_1] = { .dt_id = TEGRA114_CLK_CLK_OUT_1, .present = true }, - [tegra_clk_clk_out_2] = { .dt_id = TEGRA114_CLK_CLK_OUT_2, .present = true }, - [tegra_clk_clk_out_3] = { .dt_id = TEGRA114_CLK_CLK_OUT_3, .present = true }, - [tegra_clk_blink] = { .dt_id = TEGRA114_CLK_BLINK, .present = true }, [tegra_clk_xusb_host_src] = { .dt_id = TEGRA114_CLK_XUSB_HOST_SRC, .present = true }, [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true }, [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true }, @@ -804,9 +800,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3_mux] = { .dt_id = TEGRA114_CLK_AUDIO3_MUX, .present = true }, [tegra_clk_audio4_mux] = { .dt_id = TEGRA114_CLK_AUDIO4_MUX, .present = true }, [tegra_clk_spdif_mux] = { .dt_id = TEGRA114_CLK_SPDIF_MUX, .present = true }, - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_1_MUX, .present = true }, - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_2_MUX, .present = true }, - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_3_MUX, .present = true }, [tegra_clk_dsia_mux] = { .dt_id = TEGRA114_CLK_DSIA_MUX, .present = true }, [tegra_clk_dsib_mux] = { .dt_id = TEGRA114_CLK_DSIB_MUX, .present = true }, [tegra_clk_cec] = { .dt_id = TEGRA114_CLK_CEC, .present = true }, @@ -865,10 +858,9 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "audio3_2x", .dt_id = TEGRA114_CLK_AUDIO3_2X }, { .con_id = "audio4_2x", .dt_id = TEGRA114_CLK_AUDIO4_2X }, { .con_id = "spdif_2x", .dt_id = TEGRA114_CLK_SPDIF_2X }, - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA114_CLK_EXTERN1 }, - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA114_CLK_EXTERN2 }, - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA114_CLK_EXTERN3 }, - { .con_id = "blink", .dt_id = TEGRA114_CLK_BLINK }, + { .con_id = "extern1", .dt_id = TEGRA114_CLK_EXTERN1 }, + { .con_id = "extern2", .dt_id = TEGRA114_CLK_EXTERN2 }, + { .con_id = "extern3", .dt_id = TEGRA114_CLK_EXTERN3 }, { .con_id = "cclk_g", .dt_id = TEGRA114_CLK_CCLK_G }, { .con_id = "cclk_lp", .dt_id = TEGRA114_CLK_CCLK_LP }, { .con_id = "sclk", .dt_id = TEGRA114_CLK_SCLK }, @@ -1147,8 +1139,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 }, { TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 }, { TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 }, - { TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1 }, - { TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1 }, { TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, @@ -1350,7 +1340,6 @@ static void __init tegra114_clock_init(struct device_node *np) tegra_audio_clk_init(clk_base, pmc_base, tegra114_clks, tegra114_audio_plls, ARRAY_SIZE(tegra114_audio_plls), 24000000); - tegra_pmc_clk_init(pmc_base, tegra114_clks); tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks, &pll_x_params); diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 7a16e50eb20f..54cac77deaa3 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -903,10 +903,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3] = { .dt_id = TEGRA124_CLK_AUDIO3, .present = true }, [tegra_clk_audio4] = { .dt_id = TEGRA124_CLK_AUDIO4, .present = true }, [tegra_clk_spdif] = { .dt_id = TEGRA124_CLK_SPDIF, .present = true }, - [tegra_clk_clk_out_1] = { .dt_id = TEGRA124_CLK_CLK_OUT_1, .present = true }, - [tegra_clk_clk_out_2] = { .dt_id = TEGRA124_CLK_CLK_OUT_2, .present = true }, - [tegra_clk_clk_out_3] = { .dt_id = TEGRA124_CLK_CLK_OUT_3, .present = true }, - [tegra_clk_blink] = { .dt_id = TEGRA124_CLK_BLINK, .present = true }, [tegra_clk_xusb_host_src] = { .dt_id = TEGRA124_CLK_XUSB_HOST_SRC, .present = true }, [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, @@ -932,9 +928,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3_mux] = { .dt_id = TEGRA124_CLK_AUDIO3_MUX, .present = true }, [tegra_clk_audio4_mux] = { .dt_id = TEGRA124_CLK_AUDIO4_MUX, .present = true }, [tegra_clk_spdif_mux] = { .dt_id = TEGRA124_CLK_SPDIF_MUX, .present = true }, - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true }, - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true }, - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true }, [tegra_clk_cec] = { .dt_id = TEGRA124_CLK_CEC, .present = true }, }; @@ -990,10 +983,9 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "audio3_2x", .dt_id = TEGRA124_CLK_AUDIO3_2X }, { .con_id = "audio4_2x", .dt_id = TEGRA124_CLK_AUDIO4_2X }, { .con_id = "spdif_2x", .dt_id = TEGRA124_CLK_SPDIF_2X }, - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA124_CLK_EXTERN1 }, - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA124_CLK_EXTERN2 }, - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA124_CLK_EXTERN3 }, - { .con_id = "blink", .dt_id = TEGRA124_CLK_BLINK }, + { .con_id = "extern1", .dt_id = TEGRA124_CLK_EXTERN1 }, + { .con_id = "extern2", .dt_id = TEGRA124_CLK_EXTERN2 }, + { .con_id = "extern3", .dt_id = TEGRA124_CLK_EXTERN3 }, { .con_id = "cclk_g", .dt_id = TEGRA124_CLK_CCLK_G }, { .con_id = "cclk_lp", .dt_id = TEGRA124_CLK_CCLK_LP }, { .con_id = "sclk", .dt_id = TEGRA124_CLK_SCLK }, @@ -1303,8 +1295,6 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 }, { TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 }, { TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 }, - { TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1 }, - { TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1 }, { TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, @@ -1459,11 +1449,9 @@ static void __init tegra132_clock_apply_init_table(void) * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132 * @np: struct device_node * of the DT node for the SoC CAR IP block * - * Register most of the clocks controlled by the CAR IP block, along - * with a few clocks controlled by the PMC IP block. Everything in - * this function should be common to Tegra124 and Tegra132. XXX The - * PMC clock initialization should probably be moved to PMC-specific - * driver code. No return value. + * Register most of the clocks controlled by the CAR IP block. + * Everything in this function should be common to Tegra124 and Tegra132. + * No return value. */ static void __init tegra124_132_clock_init_pre(struct device_node *np) { @@ -1506,7 +1494,6 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, tegra124_audio_plls, ARRAY_SIZE(tegra124_audio_plls), 24576000); - tegra_pmc_clk_init(pmc_base, tegra124_clks); /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */ plld_base = readl(clk_base + PLLD_BASE); @@ -1518,11 +1505,11 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) * tegra124_132_clock_init_post - clock initialization postamble for T124/T132 * @np: struct device_node * of the DT node for the SoC CAR IP block * - * Register most of the along with a few clocks controlled by the PMC - * IP block. Everything in this function should be common to Tegra124 + * Register most of the clocks controlled by the CAR IP block. + * Everything in this function should be common to Tegra124 * and Tegra132. This function must be called after - * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will - * not be set. No return value. + * tegra124_132_clock_init_pre(), otherwise clk_base will not be set. + * No return value. */ static void __init tegra124_132_clock_init_post(struct device_node *np) { diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index fff5cba87637..6882d777a7d3 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -458,7 +458,6 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "cdev1", .dt_id = TEGRA20_CLK_CDEV1 }, { .con_id = "cdev2", .dt_id = TEGRA20_CLK_CDEV2 }, { .con_id = "clk_32k", .dt_id = TEGRA20_CLK_CLK_32K }, - { .con_id = "blink", .dt_id = TEGRA20_CLK_BLINK }, { .con_id = "clk_m", .dt_id = TEGRA20_CLK_CLK_M }, { .con_id = "pll_ref", .dt_id = TEGRA20_CLK_PLL_REF }, { .dev_id = "tegra20-i2s.0", .dt_id = TEGRA20_CLK_I2S1 }, @@ -537,7 +536,6 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_csi] = { .dt_id = TEGRA20_CLK_CSI, .present = true }, [tegra_clk_isp] = { .dt_id = TEGRA20_CLK_ISP, .present = true }, [tegra_clk_clk_32k] = { .dt_id = TEGRA20_CLK_CLK_32K, .present = true }, - [tegra_clk_blink] = { .dt_id = TEGRA20_CLK_BLINK, .present = true }, [tegra_clk_hclk] = { .dt_id = TEGRA20_CLK_HCLK, .present = true }, [tegra_clk_pclk] = { .dt_id = TEGRA20_CLK_PCLK, .present = true }, [tegra_clk_pll_p_out1] = { .dt_id = TEGRA20_CLK_PLL_P_OUT1, .present = true }, @@ -1034,7 +1032,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 }, { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 }, { TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 }, { TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 }, @@ -1146,7 +1143,6 @@ static void __init tegra20_clock_init(struct device_node *np) tegra_super_clk_gen4_init(clk_base, pmc_base, tegra20_clks, NULL); tegra20_periph_clk_init(); tegra20_audio_clk_init(); - tegra_pmc_clk_init(pmc_base, tegra20_clks); tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX); diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 45d54ead30bc..d2f1e9c0ed25 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2418,10 +2418,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true }, [tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true }, [tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true }, - [tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true }, - [tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true }, - [tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true }, - [tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true }, [tegra_clk_xusb_gate] = { .dt_id = TEGRA210_CLK_XUSB_GATE, .present = true }, [tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true }, [tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true }, @@ -2453,9 +2449,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true }, [tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true }, [tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true }, - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true }, - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true }, - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true }, [tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true }, [tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true }, [tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true }, @@ -2542,10 +2535,9 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "audio4", .dt_id = TEGRA210_CLK_AUDIO4 }, { .con_id = "spdif", .dt_id = TEGRA210_CLK_SPDIF }, { .con_id = "spdif_2x", .dt_id = TEGRA210_CLK_SPDIF_2X }, - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 }, - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 }, - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 }, - { .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK }, + { .con_id = "extern1", .dt_id = TEGRA210_CLK_EXTERN1 }, + { .con_id = "extern2", .dt_id = TEGRA210_CLK_EXTERN2 }, + { .con_id = "extern3", .dt_id = TEGRA210_CLK_EXTERN3 }, { .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G }, { .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP }, { .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK }, @@ -3453,8 +3445,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 }, { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 }, { TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 }, - { TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1 }, - { TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, @@ -3695,7 +3685,6 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks, tegra210_audio_plls, ARRAY_SIZE(tegra210_audio_plls), 24576000); - tegra_pmc_clk_init(pmc_base, tegra210_clks); /* For Tegra210, PLLD is the only source for DSIA & DSIB */ value = readl(clk_base + PLLD_BASE); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index c54fe3d4fe99..5a12f55ef13b 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -569,10 +569,9 @@ static struct tegra_devclk devclks[] __initdata = { { .con_id = "audio3_2x", .dt_id = TEGRA30_CLK_AUDIO3_2X }, { .con_id = "audio4_2x", .dt_id = TEGRA30_CLK_AUDIO4_2X }, { .con_id = "spdif_2x", .dt_id = TEGRA30_CLK_SPDIF_2X }, - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA30_CLK_EXTERN1 }, - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA30_CLK_EXTERN2 }, - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA30_CLK_EXTERN3 }, - { .con_id = "blink", .dt_id = TEGRA30_CLK_BLINK }, + { .con_id = "extern1", .dt_id = TEGRA30_CLK_EXTERN1 }, + { .con_id = "extern2", .dt_id = TEGRA30_CLK_EXTERN2 }, + { .con_id = "extern3", .dt_id = TEGRA30_CLK_EXTERN3 }, { .con_id = "cclk_g", .dt_id = TEGRA30_CLK_CCLK_G }, { .con_id = "cclk_lp", .dt_id = TEGRA30_CLK_CCLK_LP }, { .con_id = "sclk", .dt_id = TEGRA30_CLK_SCLK }, @@ -713,13 +712,6 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_audio3_2x] = { .dt_id = TEGRA30_CLK_AUDIO3_2X, .present = true }, [tegra_clk_audio4_2x] = { .dt_id = TEGRA30_CLK_AUDIO4_2X, .present = true }, [tegra_clk_spdif_2x] = { .dt_id = TEGRA30_CLK_SPDIF_2X, .present = true }, - [tegra_clk_clk_out_1] = { .dt_id = TEGRA30_CLK_CLK_OUT_1, .present = true }, - [tegra_clk_clk_out_2] = { .dt_id = TEGRA30_CLK_CLK_OUT_2, .present = true }, - [tegra_clk_clk_out_3] = { .dt_id = TEGRA30_CLK_CLK_OUT_3, .present = true }, - [tegra_clk_blink] = { .dt_id = TEGRA30_CLK_BLINK, .present = true }, - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_1_MUX, .present = true }, - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_2_MUX, .present = true }, - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_3_MUX, .present = true }, [tegra_clk_hclk] = { .dt_id = TEGRA30_CLK_HCLK, .present = true }, [tegra_clk_pclk] = { .dt_id = TEGRA30_CLK_PCLK, .present = true }, [tegra_clk_i2s0] = { .dt_id = TEGRA30_CLK_I2S0, .present = true }, @@ -1232,9 +1224,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 }, { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 }, { TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 }, - { TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0 }, - { TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, @@ -1364,7 +1353,6 @@ static void __init tegra30_clock_init(struct device_node *np) tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks, tegra30_audio_plls, ARRAY_SIZE(tegra30_audio_plls), 24000000); - tegra_pmc_clk_init(pmc_base, tegra30_clks); tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 416a6b09f6a3..2c9a68302e02 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -854,7 +854,6 @@ void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base, struct tegra_clk *tegra_clks, struct tegra_clk_pll_params *pll_params); -void tegra_pmc_clk_init(void __iomem *pmc_base, struct tegra_clk *tegra_clks); void tegra_fixed_clk_init(struct tegra_clk *tegra_clks); int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, unsigned long *input_freqs, unsigned int num, From efdd205ccbfaa80bd932bc2fba498026c09db502 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 13 Jan 2020 23:24:27 -0800 Subject: [PATCH 264/809] clk: tegra: Remove audio clocks configuration from clock driver Current clock driver enables PLLA, cdev1 on Tegra20 and extern1 on Tegra30 and above as a part of clocks init and there is no need to have these audio clocks enabled by the clock driver. extern1 is used as parent for clk_out_1 and clk_out_1 is dedicated for audio mclk on Tegra30 and above Tegra platforms and these clocks are taken care by ASoC driver. So, this patch removes audio related clocks configuration from clock init of Tegra20 and above. Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra114.c | 5 ++--- drivers/clk/tegra/clk-tegra124.c | 5 ++--- drivers/clk/tegra/clk-tegra20.c | 5 ++--- drivers/clk/tegra/clk-tegra210.c | 5 ++--- drivers/clk/tegra/clk-tegra30.c | 5 ++--- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index c138ef75480b..bc9e47a4cb60 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -1136,9 +1136,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0 }, { TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0 }, { TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0 }, - { TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 }, - { TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 }, - { TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 }, + { TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 0 }, + { TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 0 }, { TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 }, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 54cac77deaa3..64e229ddf2a5 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1292,9 +1292,8 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0 }, { TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0 }, { TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0 }, - { TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 }, - { TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 }, - { TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 }, + { TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 0 }, + { TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 0 }, { TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 6882d777a7d3..085feb04e913 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1029,9 +1029,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0 }, { TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0 }, { TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0 }, - { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 }, - { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 }, - { TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 }, + { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 0 }, + { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 0 }, { TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index d2f1e9c0ed25..c6304f5e813e 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -3442,9 +3442,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0 }, { TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0 }, { TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0 }, - { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 }, - { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 }, - { TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 }, + { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 0 }, + { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 0 }, { TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 5a12f55ef13b..3255f82e61b5 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1221,9 +1221,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0 }, { TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0 }, { TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0 }, - { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 }, - { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 }, - { TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 }, + { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 0 }, + { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 0 }, { TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, From cc6f0e39000900e5dd1448103a9571f0eccd7d4e Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 7 Mar 2020 10:09:15 +0000 Subject: [PATCH 265/809] powerpc/32: Fix missing NULL pmd check in virt_to_kpte() Commit 2efc7c085f05 ("powerpc/32: drop get_pteptr()"), replaced get_pteptr() by virt_to_kpte(). But virt_to_kpte() lacks a NULL pmd check and returns an invalid non NULL pointer when there is no page table. Reported-by: Nick Desaulniers Fixes: 2efc7c085f05 ("powerpc/32: drop get_pteptr()") Signed-off-by: Christophe Leroy Tested-by: Nathan Chancellor Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/b1177cdfc6af74a3e277bba5d9e708c4b3315ebe.1583575707.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/pgtable.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index b80bfd41828d..b1f1d5339735 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -54,7 +54,9 @@ static inline pmd_t *pmd_ptr_k(unsigned long va) static inline pte_t *virt_to_kpte(unsigned long vaddr) { - return pte_offset_kernel(pmd_ptr_k(vaddr), vaddr); + pmd_t *pmd = pmd_ptr_k(vaddr); + + return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr); } #endif From ffd3eaf178b0f616a071e510e289d937330b0b35 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Mon, 24 Feb 2020 16:18:48 -0500 Subject: [PATCH 266/809] powerpc/vdso: remove deprecated VDS64_HAS_DESCRIPTORS references The original 2005 patch that introduced the powerpc vdso, pre-git ("ppc64: Implement a vDSO and use it for signal trampoline") notes that: ... symbols exposed by the vDSO aren't "normal" function symbols, apps can't be expected to link against them directly, the vDSO's are both seen as if they were linked at 0 and the symbols just contain offsets to the various functions. This is done on purpose to avoid a relocation step (ppc64 functions normally have descriptors with abs addresses in them). When glibc uses those functions, it's expected to use it's own trampolines that know how to reach them. Despite that explanation, there remains dead #ifdef VDS64_HAS_DESCRIPTORS code-blocks that provide alternate function definitions that setup function descriptors. Since VDS64_HAS_DESCRIPTORS has been unused for all these years, we might as well finally remove it from the codebase. Signed-off-by: Joe Lawrence Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200224211848.26087-1-joe.lawrence@redhat.com --- arch/powerpc/include/asm/vdso.h | 24 ------------------------ arch/powerpc/kernel/vdso.c | 5 ----- 2 files changed, 29 deletions(-) diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index b5e1f8f8a05c..2ff884853f97 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h @@ -13,9 +13,6 @@ #define VDSO_VERSION_STRING LINUX_2.6.15 -/* Define if 64 bits VDSO has procedure descriptors */ -#undef VDS64_HAS_DESCRIPTORS - #ifndef __ASSEMBLY__ /* Offsets relative to thread->vdso_base */ @@ -28,25 +25,6 @@ int vdso_getcpu_init(void); #else /* __ASSEMBLY__ */ #ifdef __VDSO64__ -#ifdef VDS64_HAS_DESCRIPTORS -#define V_FUNCTION_BEGIN(name) \ - .globl name; \ - .section ".opd","a"; \ - .align 3; \ - name: \ - .quad .name,.TOC.@tocbase,0; \ - .previous; \ - .globl .name; \ - .type .name,@function; \ - .name: \ - -#define V_FUNCTION_END(name) \ - .size .name,.-.name; - -#define V_LOCAL_FUNC(name) (.name) - -#else /* VDS64_HAS_DESCRIPTORS */ - #define V_FUNCTION_BEGIN(name) \ .globl name; \ name: \ @@ -55,8 +33,6 @@ int vdso_getcpu_init(void); .size name,.-name; #define V_LOCAL_FUNC(name) (name) - -#endif /* VDS64_HAS_DESCRIPTORS */ #endif /* __VDSO64__ */ #ifdef __VDSO32__ diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index b9a108411c0d..d3b77c15f9ce 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -391,12 +391,7 @@ static unsigned long __init find_function64(struct lib64_elfinfo *lib, symname); return 0; } -#ifdef VDS64_HAS_DESCRIPTORS - return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) - - VDSO64_LBASE; -#else return sym->st_value - VDSO64_LBASE; -#endif } static int __init vdso_do_func_patch64(struct lib32_elfinfo *v32, From d0a72efac89d1c35ac55197895201b7b94c5e6ef Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Thu, 6 Feb 2020 17:26:21 +1100 Subject: [PATCH 267/809] cpufreq: powernv: Fix use-after-free The cpufreq driver has a use-after-free that we can hit if: a) There's an OCC message pending when the notifier is registered, and b) The cpufreq driver fails to register with the core. When a) occurs the notifier schedules a workqueue item to handle the message. The backing work_struct is located on chips[].throttle and when b) happens we clean up by freeing the array. Once we get to the (now free) queued item and the kernel crashes. Fixes: c5e29ea7ac14 ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}") Cc: stable@vger.kernel.org # v4.6+ Signed-off-by: Oliver O'Halloran Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200206062622.28235-1-oohall@gmail.com --- drivers/cpufreq/powernv-cpufreq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 56f4bc0d209e..1806b1da4366 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -1080,6 +1080,12 @@ free_and_return: static inline void clean_chip_info(void) { + int i; + + /* flush any pending work items */ + if (chips) + for (i = 0; i < nr_chips; i++) + cancel_work_sync(&chips[i].throttle); kfree(chips); } From 966c08de7c2c9bcac13e2cb9e769a39582d5389f Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Thu, 6 Feb 2020 17:26:22 +1100 Subject: [PATCH 268/809] cpufreq: powernv: Fix unsafe notifiers The PowerNV cpufreq driver registers two notifiers: one to catch throttle messages from the OCC and one to bump the CPU frequency back to normal before a reboot. Both require the cpufreq driver to be registered in order to function since the notifier callbacks use various cpufreq_*() functions. Right now we register both notifiers before we've initialised the driver. This seems to work, but we should head off any protential problems by registering the notifiers after the driver is initialised. Signed-off-by: Oliver O'Halloran Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200206062622.28235-2-oohall@gmail.com --- drivers/cpufreq/powernv-cpufreq.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 1806b1da4366..03798c4326c6 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -1114,9 +1114,6 @@ static int __init powernv_cpufreq_init(void) if (rc) goto out; - register_reboot_notifier(&powernv_cpufreq_reboot_nb); - opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); - if (powernv_pstate_info.wof_enabled) powernv_cpufreq_driver.boost_enabled = true; else @@ -1125,15 +1122,17 @@ static int __init powernv_cpufreq_init(void) rc = cpufreq_register_driver(&powernv_cpufreq_driver); if (rc) { pr_info("Failed to register the cpufreq driver (%d)\n", rc); - goto cleanup_notifiers; + goto cleanup; } if (powernv_pstate_info.wof_enabled) cpufreq_enable_boost_support(); + register_reboot_notifier(&powernv_cpufreq_reboot_nb); + opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); + return 0; -cleanup_notifiers: - unregister_all_notifiers(); +cleanup: clean_chip_info(); out: pr_info("Platform driver disabled. System does not support PState control\n"); From eec152734be10c72d2d413a27ca9d282c28cdb61 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Tue, 10 Mar 2020 15:37:56 +0100 Subject: [PATCH 269/809] clk: qcom: clk-rpm: add missing rpm clk for ipq806x Add missing definition of rpm clk for ipq806x soc Signed-off-by: John Crispin Signed-off-by: Ansuel Smith Acked-by: John Crispin Reviewed-by: Rob Herring Link: https://lkml.kernel.org/r/20200310143756.244-1-ansuelsmth@gmail.com Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + drivers/clk/qcom/clk-rpm.c | 35 +++++++++++++++++++ include/dt-bindings/clock/qcom,rpmcc.h | 4 +++ 3 files changed, 40 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt index 356cabcd844d..90a1349bc713 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt @@ -16,6 +16,7 @@ Required properties : "qcom,rpmcc-msm8974", "qcom,rpmcc" "qcom,rpmcc-msm8976", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc" + "qcom,rpmcc-ipq806x", "qcom,rpmcc" "qcom,rpmcc-msm8996", "qcom,rpmcc" "qcom,rpmcc-msm8998", "qcom,rpmcc" "qcom,rpmcc-qcs404", "qcom,rpmcc" diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index 9e3110a71f12..f71d228fd6bd 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -543,10 +543,45 @@ static const struct rpm_clk_desc rpm_clk_apq8064 = { .num_clks = ARRAY_SIZE(apq8064_clks), }; +/* ipq806x */ +DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); +DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); +DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); +DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); +DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); +DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); +DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK); +DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK); + +static struct clk_rpm *ipq806x_clks[] = { + [RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk, + [RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk, + [RPM_CFPB_CLK] = &ipq806x_cfpb_clk, + [RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk, + [RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk, + [RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk, + [RPM_EBI1_CLK] = &ipq806x_ebi1_clk, + [RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk, + [RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk, + [RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk, + [RPM_SFPB_CLK] = &ipq806x_sfpb_clk, + [RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk, + [RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk, + [RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk, + [RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk, + [RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk, +}; + +static const struct rpm_clk_desc rpm_clk_ipq806x = { + .clks = ipq806x_clks, + .num_clks = ARRAY_SIZE(ipq806x_clks), +}; + static const struct of_device_id rpm_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 }, { .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 }, { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, + { .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x }, { } }; MODULE_DEVICE_TABLE(of, rpm_clk_match_table); diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 8e3095720552..ae74c43c485d 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -37,6 +37,10 @@ #define RPM_XO_A0 27 #define RPM_XO_A1 28 #define RPM_XO_A2 29 +#define RPM_NSS_FABRIC_0_CLK 30 +#define RPM_NSS_FABRIC_0_A_CLK 31 +#define RPM_NSS_FABRIC_1_CLK 32 +#define RPM_NSS_FABRIC_1_A_CLK 33 /* SMD RPM clocks */ #define RPM_SMD_XO_CLK_SRC 0 From 6386722a329824e005c3fd1b4a8cc37db367c76a Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:54 +0530 Subject: [PATCH 270/809] ext4: add IOMAP_F_MERGED for non-extent based mapping IOMAP_F_MERGED needs to be set in case of non-extent based mapping. This is needed in later patches for conversion of ext4_fiemap to use iomap. Reviewed-by: Darrick J. Wong Reviewed-by: Jan Kara Signed-off-by: Ritesh Harjani Link: https://lore.kernel.org/r/a4764c91c08c16d4d4a4b36defb2a08625b0e9b3.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 27d009bf183f..db3ba140351e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3333,6 +3333,10 @@ static void ext4_set_iomap(struct inode *inode, struct iomap *iomap, iomap->offset = (u64) map->m_lblk << blkbits; iomap->length = (u64) map->m_len << blkbits; + if ((map->m_flags & EXT4_MAP_MAPPED) && + !ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + iomap->flags |= IOMAP_F_MERGED; + /* * Flags passed to ext4_map_blocks() for direct I/O writes can result * in m_flags having both EXT4_MAP_MAPPED and EXT4_MAP_UNWRITTEN bits From 2f424a5a09a506e1a6ad432e50bca3000a767d5a Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:55 +0530 Subject: [PATCH 271/809] ext4: optimize ext4_ext_precache for 0 depth This patch avoids the memory alloc & free path when depth is 0, since anyway there is no extra caching done in that case. So on checking depth 0, simply return early. Signed-off-by: Ritesh Harjani Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/93da0d0f073c73358e85bb9849d8a5378d1da539.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index bc96529d1509..2ebc858fd392 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -549,6 +549,12 @@ int ext4_ext_precache(struct inode *inode) down_read(&ei->i_data_sem); depth = ext_depth(inode); + /* Don't cache anything if there are no external extent blocks */ + if (!depth) { + up_read(&ei->i_data_sem); + return ret; + } + path = kcalloc(depth + 1, sizeof(struct ext4_ext_path), GFP_NOFS); if (path == NULL) { @@ -556,9 +562,6 @@ int ext4_ext_precache(struct inode *inode) return -ENOMEM; } - /* Don't cache anything if there are no external extent blocks */ - if (depth == 0) - goto out; path[0].p_hdr = ext_inode_hdr(inode); ret = ext4_ext_check(inode, path[0].p_hdr, depth, 0); if (ret) From ac58e4fb03f9d111d733a4ad379d06eef3a24705 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:56 +0530 Subject: [PATCH 272/809] ext4: move ext4 bmap to use iomap infrastructure ext4_iomap_begin is already implemented which provides ext4_map_blocks, so just move the API from generic_block_bmap to iomap_bmap for iomap conversion. Reviewed-by: Jan Kara Reviewed-by: Darrick J. Wong Signed-off-by: Ritesh Harjani Link: https://lore.kernel.org/r/8bbd53bd719d5ccfecafcce93f2bf1d7955a44af.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index db3ba140351e..07ca260b30ab 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3212,7 +3212,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) return 0; } - return generic_block_bmap(mapping, block, ext4_get_block); + return iomap_bmap(mapping, block, &ext4_iomap_ops); } static int ext4_readpage(struct file *file, struct page *page) From b2c5764262edded1b1cfff5a6ca82c3d61bb4a4a Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:57 +0530 Subject: [PATCH 273/809] ext4: make ext4_ind_map_blocks work with fiemap For indirect block mapping if the i_block > max supported block in inode then ext4_ind_map_blocks() returns a -EIO error. But in case of fiemap this could be a valid query to ->iomap_begin call. So check if the offset >= s_bitmap_maxbytes in ext4_iomap_begin_report(), then simply skip calling ext4_map_blocks(). Signed-off-by: Ritesh Harjani Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/87fa0ddc5967fa707656212a3b66a7233425325c.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 07ca260b30ab..f6aebb792178 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3546,12 +3546,28 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset, map.m_len = min_t(loff_t, (offset + length - 1) >> blkbits, EXT4_MAX_LOGICAL_BLOCK) - map.m_lblk + 1; + /* + * Fiemap callers may call for offset beyond s_bitmap_maxbytes. + * So handle it here itself instead of querying ext4_map_blocks(). + * Since ext4_map_blocks() will warn about it and will return + * -EIO error. + */ + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + + if (offset >= sbi->s_bitmap_maxbytes) { + map.m_flags = 0; + goto set_iomap; + } + } + ret = ext4_map_blocks(NULL, inode, &map, 0); if (ret < 0) return ret; if (ret == 0) delalloc = ext4_iomap_is_delalloc(inode, &map); +set_iomap: ext4_set_iomap(inode, iomap, &map, offset, length); if (delalloc && iomap->type == IOMAP_HOLE) iomap->type = IOMAP_DELALLOC; From d3b6f23f71670007817a5d59f3fbafab2b794e8c Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:58 +0530 Subject: [PATCH 274/809] ext4: move ext4_fiemap to use iomap framework This patch moves ext4_fiemap to use iomap framework. For xattr a new 'ext4_iomap_xattr_ops' is added. Reported-by: kbuild test robot Reviewed-by: Jan Kara Reviewed-by: Darrick J. Wong Link: https://lore.kernel.org/r/b9f45c885814fcdd0631747ff0fe08886270828c.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Ritesh Harjani Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 292 ++++++++-------------------------------------- fs/ext4/inline.c | 41 ------- 2 files changed, 49 insertions(+), 284 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2ebc858fd392..5b2cac0208fe 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "ext4_jbd2.h" #include "ext4_extents.h" #include "xattr.h" @@ -90,9 +91,6 @@ static int ext4_split_extent_at(handle_t *handle, int split_flag, int flags); -static int ext4_find_delayed_extent(struct inode *inode, - struct extent_status *newes); - static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped) { /* @@ -2130,155 +2128,6 @@ cleanup: return err; } -static int ext4_fill_fiemap_extents(struct inode *inode, - ext4_lblk_t block, ext4_lblk_t num, - struct fiemap_extent_info *fieinfo) -{ - struct ext4_ext_path *path = NULL; - struct ext4_extent *ex; - struct extent_status es; - ext4_lblk_t next, next_del, start = 0, end = 0; - ext4_lblk_t last = block + num; - int exists, depth = 0, err = 0; - unsigned int flags = 0; - unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; - - while (block < last && block != EXT_MAX_BLOCKS) { - num = last - block; - /* find extent for this block */ - down_read(&EXT4_I(inode)->i_data_sem); - - path = ext4_find_extent(inode, block, &path, 0); - if (IS_ERR(path)) { - up_read(&EXT4_I(inode)->i_data_sem); - err = PTR_ERR(path); - path = NULL; - break; - } - - depth = ext_depth(inode); - if (unlikely(path[depth].p_hdr == NULL)) { - up_read(&EXT4_I(inode)->i_data_sem); - EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); - err = -EFSCORRUPTED; - break; - } - ex = path[depth].p_ext; - next = ext4_ext_next_allocated_block(path); - - flags = 0; - exists = 0; - if (!ex) { - /* there is no extent yet, so try to allocate - * all requested space */ - start = block; - end = block + num; - } else if (le32_to_cpu(ex->ee_block) > block) { - /* need to allocate space before found extent */ - start = block; - end = le32_to_cpu(ex->ee_block); - if (block + num < end) - end = block + num; - } else if (block >= le32_to_cpu(ex->ee_block) - + ext4_ext_get_actual_len(ex)) { - /* need to allocate space after found extent */ - start = block; - end = block + num; - if (end >= next) - end = next; - } else if (block >= le32_to_cpu(ex->ee_block)) { - /* - * some part of requested space is covered - * by found extent - */ - start = block; - end = le32_to_cpu(ex->ee_block) - + ext4_ext_get_actual_len(ex); - if (block + num < end) - end = block + num; - exists = 1; - } else { - BUG(); - } - BUG_ON(end <= start); - - if (!exists) { - es.es_lblk = start; - es.es_len = end - start; - es.es_pblk = 0; - } else { - es.es_lblk = le32_to_cpu(ex->ee_block); - es.es_len = ext4_ext_get_actual_len(ex); - es.es_pblk = ext4_ext_pblock(ex); - if (ext4_ext_is_unwritten(ex)) - flags |= FIEMAP_EXTENT_UNWRITTEN; - } - - /* - * Find delayed extent and update es accordingly. We call - * it even in !exists case to find out whether es is the - * last existing extent or not. - */ - next_del = ext4_find_delayed_extent(inode, &es); - if (!exists && next_del) { - exists = 1; - flags |= (FIEMAP_EXTENT_DELALLOC | - FIEMAP_EXTENT_UNKNOWN); - } - up_read(&EXT4_I(inode)->i_data_sem); - - if (unlikely(es.es_len == 0)) { - EXT4_ERROR_INODE(inode, "es.es_len == 0"); - err = -EFSCORRUPTED; - break; - } - - /* - * This is possible iff next == next_del == EXT_MAX_BLOCKS. - * we need to check next == EXT_MAX_BLOCKS because it is - * possible that an extent is with unwritten and delayed - * status due to when an extent is delayed allocated and - * is allocated by fallocate status tree will track both of - * them in a extent. - * - * So we could return a unwritten and delayed extent, and - * its block is equal to 'next'. - */ - if (next == next_del && next == EXT_MAX_BLOCKS) { - flags |= FIEMAP_EXTENT_LAST; - if (unlikely(next_del != EXT_MAX_BLOCKS || - next != EXT_MAX_BLOCKS)) { - EXT4_ERROR_INODE(inode, - "next extent == %u, next " - "delalloc extent = %u", - next, next_del); - err = -EFSCORRUPTED; - break; - } - } - - if (exists) { - err = fiemap_fill_next_extent(fieinfo, - (__u64)es.es_lblk << blksize_bits, - (__u64)es.es_pblk << blksize_bits, - (__u64)es.es_len << blksize_bits, - flags); - if (err < 0) - break; - if (err == 1) { - err = 0; - break; - } - } - - block = es.es_lblk + es.es_len; - } - - ext4_ext_drop_refs(path); - kfree(path); - return err; -} - static int ext4_fill_es_cache_info(struct inode *inode, ext4_lblk_t block, ext4_lblk_t num, struct fiemap_extent_info *fieinfo) @@ -4927,64 +4776,13 @@ int ext4_convert_unwritten_io_end_vec(handle_t *handle, ext4_io_end_t *io_end) return ret < 0 ? ret : err; } -/* - * If newes is not existing extent (newes->ec_pblk equals zero) find - * delayed extent at start of newes and update newes accordingly and - * return start of the next delayed extent. - * - * If newes is existing extent (newes->ec_pblk is not equal zero) - * return start of next delayed extent or EXT_MAX_BLOCKS if no delayed - * extent found. Leave newes unmodified. - */ -static int ext4_find_delayed_extent(struct inode *inode, - struct extent_status *newes) -{ - struct extent_status es; - ext4_lblk_t block, next_del; - - if (newes->es_pblk == 0) { - ext4_es_find_extent_range(inode, &ext4_es_is_delayed, - newes->es_lblk, - newes->es_lblk + newes->es_len - 1, - &es); - - /* - * No extent in extent-tree contains block @newes->es_pblk, - * then the block may stay in 1)a hole or 2)delayed-extent. - */ - if (es.es_len == 0) - /* A hole found. */ - return 0; - - if (es.es_lblk > newes->es_lblk) { - /* A hole found. */ - newes->es_len = min(es.es_lblk - newes->es_lblk, - newes->es_len); - return 0; - } - - newes->es_len = es.es_lblk + es.es_len - newes->es_lblk; - } - - block = newes->es_lblk + newes->es_len; - ext4_es_find_extent_range(inode, &ext4_es_is_delayed, block, - EXT_MAX_BLOCKS, &es); - if (es.es_len == 0) - next_del = EXT_MAX_BLOCKS; - else - next_del = es.es_lblk; - - return next_del; -} - -static int ext4_xattr_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo) +static int ext4_iomap_xattr_fiemap(struct inode *inode, struct iomap *iomap) { __u64 physical = 0; - __u64 length; - __u32 flags = FIEMAP_EXTENT_LAST; + __u64 length = 0; int blockbits = inode->i_sb->s_blocksize_bits; int error = 0; + u16 iomap_type; /* in-inode? */ if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { @@ -4999,41 +4797,50 @@ static int ext4_xattr_fiemap(struct inode *inode, EXT4_I(inode)->i_extra_isize; physical += offset; length = EXT4_SB(inode->i_sb)->s_inode_size - offset; - flags |= FIEMAP_EXTENT_DATA_INLINE; brelse(iloc.bh); - } else { /* external block */ + iomap_type = IOMAP_INLINE; + } else if (EXT4_I(inode)->i_file_acl) { /* external block */ physical = (__u64)EXT4_I(inode)->i_file_acl << blockbits; length = inode->i_sb->s_blocksize; + iomap_type = IOMAP_MAPPED; + } else { + /* no in-inode or external block for xattr, so return -ENOENT */ + error = -ENOENT; + goto out; } - if (physical) - error = fiemap_fill_next_extent(fieinfo, 0, physical, - length, flags); - return (error < 0 ? error : 0); + iomap->addr = physical; + iomap->offset = 0; + iomap->length = length; + iomap->type = iomap_type; + iomap->flags = 0; +out: + return error; } -static int _ext4_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len, - int (*fill)(struct inode *, ext4_lblk_t, - ext4_lblk_t, - struct fiemap_extent_info *)) +static int ext4_iomap_xattr_begin(struct inode *inode, loff_t offset, + loff_t length, unsigned flags, + struct iomap *iomap, struct iomap *srcmap) +{ + int error; + + error = ext4_iomap_xattr_fiemap(inode, iomap); + if (error == 0 && (offset >= iomap->length)) + error = -ENOENT; + return error; +} + +static const struct iomap_ops ext4_iomap_xattr_ops = { + .iomap_begin = ext4_iomap_xattr_begin, +}; + +static int _ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + __u64 start, __u64 len, bool from_es_cache) { ext4_lblk_t start_blk; - u32 ext4_fiemap_flags = FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR; - + u32 ext4_fiemap_flags = FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR; int error = 0; - if (ext4_has_inline_data(inode)) { - int has_inline = 1; - - error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline, - start, len); - - if (has_inline) - return error; - } - if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) { error = ext4_ext_precache(inode); if (error) @@ -5041,19 +4848,19 @@ static int _ext4_fiemap(struct inode *inode, fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE; } - /* fallback to generic here if not in extents fmt */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) && - fill == ext4_fill_fiemap_extents) - return generic_block_fiemap(inode, fieinfo, start, len, - ext4_get_block); - - if (fill == ext4_fill_es_cache_info) + if (from_es_cache) ext4_fiemap_flags &= FIEMAP_FLAG_XATTR; + if (fiemap_check_flags(fieinfo, ext4_fiemap_flags)) return -EBADR; if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { - error = ext4_xattr_fiemap(inode, fieinfo); + fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR; + error = iomap_fiemap(inode, fieinfo, start, len, + &ext4_iomap_xattr_ops); + } else if (!from_es_cache) { + error = iomap_fiemap(inode, fieinfo, start, len, + &ext4_iomap_report_ops); } else { ext4_lblk_t len_blks; __u64 last_blk; @@ -5068,7 +4875,8 @@ static int _ext4_fiemap(struct inode *inode, * Walk the extent tree gathering extent information * and pushing extents back to the user. */ - error = fill(inode, start_blk, len_blks, fieinfo); + error = ext4_fill_es_cache_info(inode, start_blk, len_blks, + fieinfo); } return error; } @@ -5076,8 +4884,7 @@ static int _ext4_fiemap(struct inode *inode, int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { - return _ext4_fiemap(inode, fieinfo, start, len, - ext4_fill_fiemap_extents); + return _ext4_fiemap(inode, fieinfo, start, len, false); } int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, @@ -5093,8 +4900,7 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, return 0; } - return _ext4_fiemap(inode, fieinfo, start, len, - ext4_fill_es_cache_info); + return _ext4_fiemap(inode, fieinfo, start, len, true); } diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index fad82d08fca5..e7db6ee23277 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1857,47 +1857,6 @@ out: return error; } -int ext4_inline_data_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, - int *has_inline, __u64 start, __u64 len) -{ - __u64 physical = 0; - __u64 inline_len; - __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | - FIEMAP_EXTENT_LAST; - int error = 0; - struct ext4_iloc iloc; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - *has_inline = 0; - goto out; - } - inline_len = min_t(size_t, ext4_get_inline_size(inode), - i_size_read(inode)); - if (start >= inline_len) - goto out; - if (start + len < inline_len) - inline_len = start + len; - inline_len -= start; - - error = ext4_get_inode_loc(inode, &iloc); - if (error) - goto out; - - physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; - physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; - physical += offsetof(struct ext4_inode, i_block); - - brelse(iloc.bh); -out: - up_read(&EXT4_I(inode)->xattr_sem); - if (physical) - error = fiemap_fill_next_extent(fieinfo, start, physical, - inline_len, flags); - return (error < 0 ? error : 0); -} - int ext4_inline_data_truncate(struct inode *inode, int *has_inline) { handle_t *handle; From 7af44c42df37094fd95897653fdaaa7b76c0539a Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Fri, 28 Feb 2020 14:56:59 +0530 Subject: [PATCH 275/809] Documentation: correct the description of FIEMAP_EXTENT_LAST Currently FIEMAP_EXTENT_LAST is not working consistently across different filesystem's fiemap implementations. So add more information about how else this flag could set in other implementation. Signed-off-by: Ritesh Harjani Link: https://lore.kernel.org/r/5a00e8d4283d6849e0b8f408c8365b31fbc1d153.1582880246.git.riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- Documentation/filesystems/fiemap.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/fiemap.txt b/Documentation/filesystems/fiemap.txt index f6d9c99103a4..ac87e6fda842 100644 --- a/Documentation/filesystems/fiemap.txt +++ b/Documentation/filesystems/fiemap.txt @@ -115,8 +115,10 @@ data. Note that the opposite is not true - it would be valid for FIEMAP_EXTENT_NOT_ALIGNED to appear alone. * FIEMAP_EXTENT_LAST -This is the last extent in the file. A mapping attempt past this -extent will return nothing. +This is generally the last extent in the file. A mapping attempt past +this extent may return nothing. Some implementations set this flag to +indicate this extent is the last one in the range queried by the user +(via fiemap->fm_length). * FIEMAP_EXTENT_UNKNOWN The location of this extent is currently unknown. This may indicate From e32ac2459cdac01f9b177eed526a3ffa1797039d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Mar 2020 10:48:38 -0500 Subject: [PATCH 276/809] ext4: use flexible-array member in struct fname The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200309154838.GA31559@embeddedor Signed-off-by: Theodore Ts'o --- fs/ext4/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 9aa1f75409b0..c654205f648d 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -392,7 +392,7 @@ struct fname { __u32 inode; __u8 name_len; __u8 file_type; - char name[0]; + char name[]; }; /* From 47b1030612f4382a976be6aa2369cf5d973ca154 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Mar 2020 13:08:13 -0500 Subject: [PATCH 277/809] ext4: use flexible-array member for xattr structs The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200309180813.GA3347@embeddedor Signed-off-by: Theodore Ts'o --- fs/ext4/xattr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index f39cad2abe2a..ffe21ac77f78 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -48,7 +48,7 @@ struct ext4_xattr_entry { __le32 e_value_inum; /* inode in which the value is stored */ __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ + char e_name[]; /* attribute name */ }; #define EXT4_XATTR_PAD_BITS 2 @@ -118,7 +118,7 @@ struct ext4_xattr_ibody_find { struct ext4_xattr_inode_array { unsigned int count; /* # of used items in the array */ - struct inode *inodes[0]; + struct inode *inodes[]; }; extern const struct xattr_handler ext4_xattr_user_handler; From eb5760863fc28feab28b567ddcda7e667e638da0 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Tue, 10 Mar 2020 15:01:56 +0000 Subject: [PATCH 278/809] ext4: mark block bitmap corrupted when found instead of BUGON We already has similar code in ext4_mb_complex_scan_group(), but ext4_mb_simple_scan_group() still affected. Other reports: https://www.spinics.net/lists/linux-ext4/msg60231.html Reviewed-by: Andreas Dilger Signed-off-by: Dmitry Monakhov Link: https://lore.kernel.org/r/20200310150156.641-1-dmonakhov@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/mballoc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 1027e01c9011..97cd1a2201a2 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1901,8 +1901,15 @@ void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, BUG_ON(buddy == NULL); k = mb_find_next_zero_bit(buddy, max, 0); - BUG_ON(k >= max); - + if (k >= max) { + ext4_grp_locked_error(ac->ac_sb, e4b->bd_group, 0, 0, + "%d free clusters of order %d. But found 0", + grp->bb_counters[i], i); + ext4_mark_group_bitmap_corrupted(ac->ac_sb, + e4b->bd_group, + EXT4_GROUP_INFO_BBITMAP_CORRUPT); + break; + } ac->ac_found++; ac->ac_b_ex.fe_len = 1 << i; From 34990461342fc9aba806bd941653b72c89dd73a2 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Wed, 11 Mar 2020 16:50:33 -0400 Subject: [PATCH 279/809] ext4: clean up ext4_ext_insert_extent() call in ext4_ext_map_blocks() Now that the eofblocks code has been removed, we don't need to assign 0 to err before calling ext4_ext_insert_extent() since it will assign a return value to ret anyway. The variable free_on_err can be eliminated and replaced by a reference to allocated_clusters which clearly conveys the idea that newly allocated blocks should be freed when recovering from an extent insertion failure. The error handling code itself should be restructured so that it errors out immediately on an insertion failure in the case where no new blocks have been allocated (bigalloc) rather than proceeding further into the mapping code. The initializer for fb_flags can also be rearranged for improved readability. Finally, insert a missing space in nearby code. No known bugs are addressed by this patch - it's simply a cleanup. Reviewed-by: Ritesh Harjani Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200311205033.25013-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 5b2cac0208fe..a1342caad01d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4028,7 +4028,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, struct ext4_extent newex, *ex, *ex2; struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); ext4_fsblk_t newblock = 0; - int free_on_err = 0, err = 0, depth, ret; + int err = 0, depth, ret; unsigned int allocated = 0, offset = 0; unsigned int allocated_clusters = 0; struct ext4_allocation_request ar; @@ -4226,7 +4226,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, goto out2; ext_debug("allocate new block: goal %llu, found %llu/%u\n", ar.goal, newblock, allocated); - free_on_err = 1; allocated_clusters = ar.len; ar.len = EXT4_C2B(sbi, ar.len) - offset; if (ar.len > allocated) @@ -4237,23 +4236,28 @@ got_allocated_blocks: ext4_ext_store_pblock(&newex, newblock + offset); newex.ee_len = cpu_to_le16(ar.len); /* Mark unwritten */ - if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){ + if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) { ext4_ext_mark_unwritten(&newex); map->m_flags |= EXT4_MAP_UNWRITTEN; } - err = 0; err = ext4_ext_insert_extent(handle, inode, &path, &newex, flags); + if (err) { + if (allocated_clusters) { + int fb_flags = 0; - if (err && free_on_err) { - int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? - EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; - /* free data blocks we just allocated */ - /* not a good idea to call discard here directly, - * but otherwise we'd need to call it every free() */ - ext4_discard_preallocations(inode); - ext4_free_blocks(handle, inode, NULL, newblock, - EXT4_C2B(sbi, allocated_clusters), fb_flags); + /* + * free data blocks we just allocated. + * not a good idea to call discard here directly, + * but otherwise we'd need to call it every free(). + */ + ext4_discard_preallocations(inode); + if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) + fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE; + ext4_free_blocks(handle, inode, NULL, newblock, + EXT4_C2B(sbi, allocated_clusters), + fb_flags); + } goto out2; } From 2971148d0fecedcbd594ff2f2784496bdc7a7ffa Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Wed, 11 Mar 2020 16:51:25 -0400 Subject: [PATCH 280/809] ext4: remove map_from_cluster from ext4_ext_map_blocks We can use the variable allocated_clusters rather than map_from_clusters to control reserved block/cluster accounting in ext4_ext_map_blocks. This eliminates a variable and associated code and improves readability a little. Reviewed-by: Ritesh Harjani Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200311205125.25061-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a1342caad01d..0e86bc611f07 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4033,7 +4033,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, unsigned int allocated_clusters = 0; struct ext4_allocation_request ar; ext4_lblk_t cluster_offset; - bool map_from_cluster = false; ext_debug("blocks %u/%u requested for inode %lu\n", map->m_lblk, map->m_len, inode->i_ino); @@ -4148,7 +4147,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, get_implied_cluster_alloc(inode->i_sb, map, ex, path)) { ar.len = allocated = map->m_len; newblock = map->m_pblk; - map_from_cluster = true; goto got_allocated_blocks; } @@ -4169,7 +4167,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, get_implied_cluster_alloc(inode->i_sb, map, ex2, path)) { ar.len = allocated = map->m_len; newblock = map->m_pblk; - map_from_cluster = true; goto got_allocated_blocks; } @@ -4274,7 +4271,7 @@ got_allocated_blocks: * clusters discovered to be delayed allocated. Once allocated, a * cluster is not included in the reserved count. */ - if (test_opt(inode->i_sb, DELALLOC) && !map_from_cluster) { + if (test_opt(inode->i_sb, DELALLOC) && allocated_clusters) { if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { /* * When allocating delayed allocated clusters, simply From 4ae9afbaaeb9bd939ac2bb8d53828fdebca5ec1b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 9 Mar 2020 18:17:09 +0200 Subject: [PATCH 281/809] clk: imx7d: Add PXP clock The PXP has a single CCGR clock gate, gating both the IPG_CLK_ROOT and the MAIN_AXI_CLK_ROOT. Add a single clock to cover both. Signed-off-by: Laurent Pinchart Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx7d.c | 1 + include/dt-bindings/clock/imx7d-clock.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 0c9f7adb41ae..b2057bd42e25 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -802,6 +802,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0); hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0); hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0); + hws[IMX7D_PXP_CLK] = imx_clk_hw_gate4("pxp_clk", "main_axi_root_clk", base + 0x44c0, 0); hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0); hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0); hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0); diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h index e6a670e1a3f8..1d4c0dfe0202 100644 --- a/include/dt-bindings/clock/imx7d-clock.h +++ b/include/dt-bindings/clock/imx7d-clock.h @@ -451,5 +451,6 @@ #define IMX7D_SNVS_CLK 442 #define IMX7D_CAAM_CLK 443 #define IMX7D_KPP_ROOT_CLK 444 -#define IMX7D_CLK_END 445 +#define IMX7D_PXP_CLK 445 +#define IMX7D_CLK_END 446 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */ From b5881e8019e0d39c43a2da56c4ae616a50615e00 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 13 Mar 2020 18:10:19 +0200 Subject: [PATCH 282/809] clk: imx: clk-gate2: Pass the device to the register function The device needs to be passed on to the clk_hw_register. Fixes: 1f9aec9662566189 ("clk: imx: clk-gate2: Switch to clk_hw based API") Signed-off-by: Abel Vesa Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 72a7698be791..ce0060e8873e 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -154,7 +154,7 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, gate->hw.init = &init; hw = &gate->hw; - ret = clk_hw_register(NULL, hw); + ret = clk_hw_register(dev, hw); if (ret) { kfree(gate); return ERR_PTR(ret); From 286c21de32b904131f8cf6a36ce40b8b0c9c5da3 Mon Sep 17 00:00:00 2001 From: Kevin Grandemange Date: Thu, 12 Mar 2020 15:41:45 +0000 Subject: [PATCH 283/809] dma-coherent: fix integer overflow in the reserved-memory dma allocation pageno is an int and the PAGE_SHIFT shift is done on an int, overflowing if the memory is bigger than 2G This can be reproduced using for example a reserved-memory of 4G reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; reserved_dma: buffer@0 { compatible = "shared-dma-pool"; no-map; reg = <0x5 0x00000000 0x1 0x0>; }; }; Signed-off-by: Kevin Grandemange Signed-off-by: Christoph Hellwig --- kernel/dma/coherent.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c index 551b0eb7028a..2a0c4985f38e 100644 --- a/kernel/dma/coherent.c +++ b/kernel/dma/coherent.c @@ -134,7 +134,7 @@ static void *__dma_alloc_from_coherent(struct device *dev, spin_lock_irqsave(&mem->spinlock, flags); - if (unlikely(size > (mem->size << PAGE_SHIFT))) + if (unlikely(size > ((dma_addr_t)mem->size << PAGE_SHIFT))) goto err; pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); @@ -144,8 +144,9 @@ static void *__dma_alloc_from_coherent(struct device *dev, /* * Memory was found in the coherent area. */ - *dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT); - ret = mem->virt_base + (pageno << PAGE_SHIFT); + *dma_handle = dma_get_device_base(dev, mem) + + ((dma_addr_t)pageno << PAGE_SHIFT); + ret = mem->virt_base + ((dma_addr_t)pageno << PAGE_SHIFT); spin_unlock_irqrestore(&mem->spinlock, flags); memset(ret, 0, size); return ret; @@ -194,7 +195,7 @@ static int __dma_release_from_coherent(struct dma_coherent_mem *mem, int order, void *vaddr) { if (mem && vaddr >= mem->virt_base && vaddr < - (mem->virt_base + (mem->size << PAGE_SHIFT))) { + (mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; unsigned long flags; @@ -238,10 +239,10 @@ static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem, struct vm_area_struct *vma, void *vaddr, size_t size, int *ret) { if (mem && vaddr >= mem->virt_base && vaddr + size <= - (mem->virt_base + (mem->size << PAGE_SHIFT))) { + (mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) { unsigned long off = vma->vm_pgoff; int start = (vaddr - mem->virt_base) >> PAGE_SHIFT; - int user_count = vma_pages(vma); + unsigned long user_count = vma_pages(vma); int count = PAGE_ALIGN(size) >> PAGE_SHIFT; *ret = -ENXIO; From 4f8232bbf887123f78bcdca3dfd2b3dfa52a0112 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 21 Feb 2020 12:24:02 -0800 Subject: [PATCH 284/809] dma-direct: remove the cached_kernel_address hook dma-direct now finds the kernel address for coherent allocations based on the dma address, so the cached_kernel_address hooks is unused and can be removed entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Robin Murphy --- arch/Kconfig | 2 +- arch/microblaze/mm/consistent.c | 7 ------- arch/mips/mm/dma-noncoherent.c | 5 ----- arch/nios2/mm/dma-mapping.c | 10 ---------- arch/xtensa/kernel/pci-dma.c | 10 ++-------- include/linux/dma-noncoherent.h | 1 - 6 files changed, 3 insertions(+), 32 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 98de654b79b3..7994b239f155 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -249,7 +249,7 @@ config ARCH_HAS_SET_DIRECT_MAP # # Select if arch has an uncached kernel segment and provides the -# uncached_kernel_address / cached_kernel_address symbols to use it +# uncached_kernel_address symbol to use it # config ARCH_HAS_UNCACHED_SEGMENT select ARCH_HAS_DMA_PREP_COHERENT diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c index 8c5f0c332d8b..cede7c5e8135 100644 --- a/arch/microblaze/mm/consistent.c +++ b/arch/microblaze/mm/consistent.c @@ -49,11 +49,4 @@ void *uncached_kernel_address(void *ptr) pr_warn("ERROR: Your cache coherent area is CACHED!!!\n"); return (void *)addr; } - -void *cached_kernel_address(void *ptr) -{ - unsigned long addr = (unsigned long)ptr; - - return (void *)(addr & ~UNCACHED_SHADOW_MASK); -} #endif /* CONFIG_MMU */ diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index dc42ffc83825..77dce28ad0a0 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -54,11 +54,6 @@ void *uncached_kernel_address(void *addr) return (void *)(__pa(addr) + UNCAC_BASE); } -void *cached_kernel_address(void *addr) -{ - return __va(addr) - UNCAC_BASE; -} - static inline void dma_sync_virt(void *addr, size_t size, enum dma_data_direction dir) { diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c index 0ed711e37902..f30f2749257c 100644 --- a/arch/nios2/mm/dma-mapping.c +++ b/arch/nios2/mm/dma-mapping.c @@ -75,13 +75,3 @@ void *uncached_kernel_address(void *ptr) return (void *)ptr; } - -void *cached_kernel_address(void *ptr) -{ - unsigned long addr = (unsigned long)ptr; - - addr &= ~CONFIG_NIOS2_IO_REGION_BASE; - addr |= CONFIG_NIOS2_KERNEL_REGION_BASE; - - return (void *)ptr; -} diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 72b6222daa0b..6a685545d5c9 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -88,18 +88,12 @@ void arch_dma_prep_coherent(struct page *page, size_t size) /* * Memory caching is platform-dependent in noMMU xtensa configurations. - * The following two functions should be implemented in platform code - * in order to enable coherent DMA memory operations when CONFIG_MMU is not - * enabled. + * This function should be implemented in platform code in order to enable + * coherent DMA memory operations when CONFIG_MMU is not enabled. */ #ifdef CONFIG_MMU void *uncached_kernel_address(void *p) { return p + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR; } - -void *cached_kernel_address(void *p) -{ - return p + XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; -} #endif /* CONFIG_MMU */ diff --git a/include/linux/dma-noncoherent.h b/include/linux/dma-noncoherent.h index ca9b5770caee..b6b72e19b0cd 100644 --- a/include/linux/dma-noncoherent.h +++ b/include/linux/dma-noncoherent.h @@ -109,6 +109,5 @@ static inline void arch_dma_prep_coherent(struct page *page, size_t size) #endif /* CONFIG_ARCH_HAS_DMA_PREP_COHERENT */ void *uncached_kernel_address(void *addr); -void *cached_kernel_address(void *addr); #endif /* _LINUX_DMA_NONCOHERENT_H */ From 3d0fc341c4bb66b2c41c0d1ec954a6d300e100b7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 21 Feb 2020 12:26:00 -0800 Subject: [PATCH 285/809] dma-direct: consolidate the error handling in dma_direct_alloc_pages Use a goto label to merge two error return cases. Signed-off-by: Christoph Hellwig Reviewed-by: Robin Murphy --- kernel/dma/direct.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 6af7ae83c4ad..650580fbbff3 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -169,11 +169,8 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size, ret = dma_common_contiguous_remap(page, PAGE_ALIGN(size), dma_pgprot(dev, PAGE_KERNEL, attrs), __builtin_return_address(0)); - if (!ret) { - dma_free_contiguous(dev, page, size); - return ret; - } - + if (!ret) + goto out_free_pages; memset(ret, 0, size); goto done; } @@ -186,8 +183,7 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size, * so log an error and fail. */ dev_info(dev, "Rejecting highmem page from CMA.\n"); - dma_free_contiguous(dev, page, size); - return NULL; + goto out_free_pages; } ret = page_address(page); @@ -207,6 +203,9 @@ done: else *dma_handle = phys_to_dma(dev, page_to_phys(page)); return ret; +out_free_pages: + dma_free_contiguous(dev, page, size); + return NULL; } void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr, From fa7e2247c5729f990c7456fe09f3af99c8f2571b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 21 Feb 2020 15:55:43 -0800 Subject: [PATCH 286/809] dma-direct: make uncached_kernel_address more general Rename the symbol to arch_dma_set_uncached, and pass a size to it as well as allow an error return. That will allow reusing this hook for in-place pagetable remapping. As the in-place remap doesn't always require an explicit cache flush, also detangle ARCH_HAS_DMA_PREP_COHERENT from ARCH_HAS_DMA_SET_UNCACHED. Signed-off-by: Christoph Hellwig Reviewed-by: Robin Murphy --- arch/Kconfig | 8 ++++---- arch/microblaze/Kconfig | 2 +- arch/microblaze/mm/consistent.c | 2 +- arch/mips/Kconfig | 3 ++- arch/mips/mm/dma-noncoherent.c | 2 +- arch/nios2/Kconfig | 3 ++- arch/nios2/mm/dma-mapping.c | 2 +- arch/xtensa/Kconfig | 2 +- arch/xtensa/kernel/pci-dma.c | 2 +- include/linux/dma-noncoherent.h | 2 +- kernel/dma/direct.c | 10 ++++++---- 11 files changed, 21 insertions(+), 17 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 7994b239f155..090cfe0c82a7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -248,11 +248,11 @@ config ARCH_HAS_SET_DIRECT_MAP bool # -# Select if arch has an uncached kernel segment and provides the -# uncached_kernel_address symbol to use it +# Select if the architecture provides the arch_dma_set_uncached symbol to +# either provide an uncached segement alias for a DMA allocation, or +# to remap the page tables in place. # -config ARCH_HAS_UNCACHED_SEGMENT - select ARCH_HAS_DMA_PREP_COHERENT +config ARCH_HAS_DMA_SET_UNCACHED bool # Select if arch init_task must go in the __init_task_data section diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 6a331bd57ea8..9606c244b5b8 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -8,7 +8,7 @@ config MICROBLAZE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE - select ARCH_HAS_UNCACHED_SEGMENT if !MMU + select ARCH_HAS_DMA_SET_UNCACHED if !MMU select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_TABLE_SORT diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c index cede7c5e8135..e09b66e43cb6 100644 --- a/arch/microblaze/mm/consistent.c +++ b/arch/microblaze/mm/consistent.c @@ -40,7 +40,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) #define UNCACHED_SHADOW_MASK 0 #endif /* CONFIG_XILINX_UNCACHED_SHADOW */ -void *uncached_kernel_address(void *ptr) +void *arch_dma_set_uncached(void *ptr, size_t size) { unsigned long addr = (unsigned long)ptr; diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 797d7f1ad5fe..489185db501e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1187,8 +1187,9 @@ config DMA_NONCOHERENT # significant advantages. # select ARCH_HAS_DMA_WRITE_COMBINE + select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_SYNC_DMA_FOR_DEVICE - select ARCH_HAS_UNCACHED_SEGMENT + select ARCH_HAS_DMA_SET_UNCACHED select DMA_NONCOHERENT_MMAP select DMA_NONCOHERENT_CACHE_SYNC select NEED_DMA_MAP_STATE diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index 77dce28ad0a0..fcea92d95d86 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -49,7 +49,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) dma_cache_wback_inv((unsigned long)page_address(page), size); } -void *uncached_kernel_address(void *addr) +void *arch_dma_set_uncached(void *addr, size_t size) { return (void *)(__pa(addr) + UNCAC_BASE); } diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index 44b5da37e8bd..2fc4ed210b5f 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -2,9 +2,10 @@ config NIOS2 def_bool y select ARCH_32BIT_OFF_T + select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE - select ARCH_HAS_UNCACHED_SEGMENT + select ARCH_HAS_DMA_SET_UNCACHED select ARCH_NO_SWAP select TIMER_OF select GENERIC_ATOMIC64 diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c index f30f2749257c..fd887d5f3f9a 100644 --- a/arch/nios2/mm/dma-mapping.c +++ b/arch/nios2/mm/dma-mapping.c @@ -67,7 +67,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) flush_dcache_range(start, start + size); } -void *uncached_kernel_address(void *ptr) +void *arch_dma_set_uncached(void *ptr, size_t size) { unsigned long addr = (unsigned long)ptr; diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 32ee759a3fda..de229424b659 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -6,7 +6,7 @@ config XTENSA select ARCH_HAS_DMA_PREP_COHERENT if MMU select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU - select ARCH_HAS_UNCACHED_SEGMENT if MMU + select ARCH_HAS_DMA_SET_UNCACHED if MMU select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_FRAME_POINTERS diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 6a685545d5c9..17c4384f8495 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -92,7 +92,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) * coherent DMA memory operations when CONFIG_MMU is not enabled. */ #ifdef CONFIG_MMU -void *uncached_kernel_address(void *p) +void *arch_dma_set_uncached(void *p, size_t size) { return p + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR; } diff --git a/include/linux/dma-noncoherent.h b/include/linux/dma-noncoherent.h index b6b72e19b0cd..1a4039506673 100644 --- a/include/linux/dma-noncoherent.h +++ b/include/linux/dma-noncoherent.h @@ -108,6 +108,6 @@ static inline void arch_dma_prep_coherent(struct page *page, size_t size) } #endif /* CONFIG_ARCH_HAS_DMA_PREP_COHERENT */ -void *uncached_kernel_address(void *addr); +void *arch_dma_set_uncached(void *addr, size_t size); #endif /* _LINUX_DMA_NONCOHERENT_H */ diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 650580fbbff3..baf4e93735c3 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -192,10 +192,12 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size, memset(ret, 0, size); - if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) && + if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED) && dma_alloc_need_uncached(dev, attrs)) { arch_dma_prep_coherent(page, size); - ret = uncached_kernel_address(ret); + ret = arch_dma_set_uncached(ret, size); + if (IS_ERR(ret)) + goto out_free_pages; } done: if (force_dma_unencrypted(dev)) @@ -236,7 +238,7 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr, void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { - if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) && + if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED) && !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && dma_alloc_need_uncached(dev, attrs)) return arch_dma_alloc(dev, size, dma_handle, gfp, attrs); @@ -246,7 +248,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, void dma_direct_free(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr, unsigned long attrs) { - if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) && + if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED) && !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && dma_alloc_need_uncached(dev, attrs)) arch_dma_free(dev, size, cpu_addr, dma_addr, attrs); From 999a5d1203baa7cff00586361feae263ee3f23a5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 21 Feb 2020 12:35:05 -0800 Subject: [PATCH 287/809] dma-direct: provide a arch_dma_clear_uncached hook This allows the arch code to reset the page tables to cached access when freeing a dma coherent allocation that was set to uncached using arch_dma_set_uncached. Signed-off-by: Christoph Hellwig Reviewed-by: Robin Murphy --- arch/Kconfig | 7 +++++++ include/linux/dma-noncoherent.h | 1 + kernel/dma/direct.c | 2 ++ 3 files changed, 10 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 090cfe0c82a7..c26302f90c96 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -255,6 +255,13 @@ config ARCH_HAS_SET_DIRECT_MAP config ARCH_HAS_DMA_SET_UNCACHED bool +# +# Select if the architectures provides the arch_dma_clear_uncached symbol +# to undo an in-place page table remap for uncached access. +# +config ARCH_HAS_DMA_CLEAR_UNCACHED + bool + # Select if arch init_task must go in the __init_task_data section config ARCH_TASK_STRUCT_ON_STACK bool diff --git a/include/linux/dma-noncoherent.h b/include/linux/dma-noncoherent.h index 1a4039506673..b59f1b6be3e9 100644 --- a/include/linux/dma-noncoherent.h +++ b/include/linux/dma-noncoherent.h @@ -109,5 +109,6 @@ static inline void arch_dma_prep_coherent(struct page *page, size_t size) #endif /* CONFIG_ARCH_HAS_DMA_PREP_COHERENT */ void *arch_dma_set_uncached(void *addr, size_t size); +void arch_dma_clear_uncached(void *addr, size_t size); #endif /* _LINUX_DMA_NONCOHERENT_H */ diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index baf4e93735c3..412f560dc69f 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -231,6 +231,8 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr, if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) vunmap(cpu_addr); + else if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED)) + arch_dma_clear_uncached(cpu_addr, size); dma_free_contiguous(dev, dma_direct_to_page(dev, dma_addr), size); } From a4a4d11a22ee89d0e94bd8640ec190d81b4c8134 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 7 Nov 2019 18:08:39 +0100 Subject: [PATCH 288/809] openrisc: use the generic in-place uncached DMA allocator Switch openrisc to use the dma-direct allocator and just provide the hooks for setting memory uncached or cached. Signed-off-by: Christoph Hellwig Reviewed-by: Stafford Horne Reviewed-by: Robin Murphy --- arch/openrisc/Kconfig | 2 ++ arch/openrisc/kernel/dma.c | 55 +++++++------------------------------- 2 files changed, 12 insertions(+), 45 deletions(-) diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 1928e061ff96..7e94fe37cb2f 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -7,6 +7,8 @@ config OPENRISC def_bool y select ARCH_32BIT_OFF_T + select ARCH_HAS_DMA_SET_UNCACHED + select ARCH_HAS_DMA_CLEAR_UNCACHED select ARCH_HAS_SYNC_DMA_FOR_DEVICE select OF select OF_EARLY_FLATTREE diff --git a/arch/openrisc/kernel/dma.c b/arch/openrisc/kernel/dma.c index adec711ad39d..c152a68811dd 100644 --- a/arch/openrisc/kernel/dma.c +++ b/arch/openrisc/kernel/dma.c @@ -11,8 +11,6 @@ * Copyright (C) 2010-2011 Jonas Bonn * * DMA mapping callbacks... - * As alloc_coherent is the only DMA callback being used currently, that's - * the only thing implemented properly. The rest need looking into... */ #include @@ -67,62 +65,29 @@ static const struct mm_walk_ops clear_nocache_walk_ops = { .pte_entry = page_clear_nocache, }; -/* - * Alloc "coherent" memory, which for OpenRISC means simply uncached. - * - * This function effectively just calls __get_free_pages, sets the - * cache-inhibit bit on those pages, and makes sure that the pages are - * flushed out of the cache before they are used. - * - * If the NON_CONSISTENT attribute is set, then this function just - * returns "normal", cachable memory. - * - * There are additional flags WEAK_ORDERING and WRITE_COMBINE to take - * into consideration here, too. All current known implementations of - * the OR1K support only strongly ordered memory accesses, so that flag - * is being ignored for now; uncached but write-combined memory is a - * missing feature of the OR1K. - */ -void * -arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp, unsigned long attrs) +void *arch_dma_set_uncached(void *cpu_addr, size_t size) { - unsigned long va; - void *page; - - page = alloc_pages_exact(size, gfp | __GFP_ZERO); - if (!page) - return NULL; - - /* This gives us the real physical address of the first page. */ - *dma_handle = __pa(page); - - va = (unsigned long)page; + unsigned long va = (unsigned long)cpu_addr; + int error; /* * We need to iterate through the pages, clearing the dcache for * them and setting the cache-inhibit bit. */ - if (walk_page_range(&init_mm, va, va + size, &set_nocache_walk_ops, - NULL)) { - free_pages_exact(page, size); - return NULL; - } - - return (void *)va; + error = walk_page_range(&init_mm, va, va + size, &set_nocache_walk_ops, + NULL); + if (error) + return ERR_PTR(error); + return cpu_addr; } -void -arch_dma_free(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle, unsigned long attrs) +void arch_dma_clear_uncached(void *cpu_addr, size_t size) { - unsigned long va = (unsigned long)vaddr; + unsigned long va = (unsigned long)cpu_addr; /* walk_page_range shouldn't be able to fail here */ WARN_ON(walk_page_range(&init_mm, va, va + size, &clear_nocache_walk_ops, NULL)); - - free_pages_exact(vaddr, size); } void arch_sync_dma_for_device(phys_addr_t addr, size_t size, From ae243ef0afbcbf2e68e2afd5e33753eb2e03d5d6 Mon Sep 17 00:00:00 2001 From: suguosong Date: Tue, 25 Feb 2020 10:19:23 +0800 Subject: [PATCH 289/809] rtc: sysfs: use kobj_to_dev use kobj_to_dev instead of open-conding it Signed-off-by: suguosong Link: https://lore.kernel.org/r/20200225021923.8570-1-guosongsu@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c index b7ca7d79fb28..950fac0d41ff 100644 --- a/drivers/rtc/sysfs.c +++ b/drivers/rtc/sysfs.c @@ -279,7 +279,7 @@ static bool rtc_does_wakealarm(struct rtc_device *rtc) static umode_t rtc_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct rtc_device *rtc = to_rtc_device(dev); umode_t mode = attr->mode; From b427ca8c663ea32c67702b2ff5fb19aabd57fa7f Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 2 Mar 2020 16:13:05 +0800 Subject: [PATCH 290/809] rtc: snvs: Improve Kconfig dependency i.MX SNVS RTC should depend on ARCH_MXC or COMPILE_TEST. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1583136785-4973-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 34c8b6c7e095..acaf6f98b54e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1761,6 +1761,7 @@ config RTC_DRV_MXC_V2 config RTC_DRV_SNVS tristate "Freescale SNVS RTC support" select REGMAP_MMIO + depends on ARCH_MXC || COMPILE_TEST depends on HAS_IOMEM depends on OF help From 2911ee9e60d9013dae0abc86719e884b5dfb4fda Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 17:04:50 +0100 Subject: [PATCH 291/809] rtc: sirfsoc: convert to devm_rtc_allocate_device This allows further improvement of the driver. Also remove the unnecessary error string as the core will already display error messages. Link: https://lore.kernel.org/r/20200305160452.27808-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sirfsoc.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index a2c9c55667cd..b2e72597eee8 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -341,28 +341,21 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) rtcdrv->overflow_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); - rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &sirfsoc_rtc_ops, THIS_MODULE); - if (IS_ERR(rtcdrv->rtc)) { - err = PTR_ERR(rtcdrv->rtc); - dev_err(&pdev->dev, "can't register RTC device\n"); - return err; - } + rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtcdrv->rtc)) + return PTR_ERR(rtcdrv->rtc); + + rtcdrv->rtc->ops = &sirfsoc_rtc_ops; rtcdrv->irq = platform_get_irq(pdev, 0); - err = devm_request_irq( - &pdev->dev, - rtcdrv->irq, - sirfsoc_rtc_irq_handler, - IRQF_SHARED, - pdev->name, - rtcdrv); + err = devm_request_irq(&pdev->dev, rtcdrv->irq, sirfsoc_rtc_irq_handler, + IRQF_SHARED, pdev->name, rtcdrv); if (err) { dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n"); return err; } - return 0; + return rtc_register_device(rtcdrv->rtc); } #ifdef CONFIG_PM_SLEEP From cd65dd4180df66f5b469e2a52caae3bfe38d5526 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 17:04:51 +0100 Subject: [PATCH 292/809] rtc: sirfsoc: set range This RTC is a 32bit counter running at 16Hz. This overflows every eight years and a half. However, the driver uses the SW_VALUE register to store the overflow, extending the counter to 64bit as long as the update happens before the overflow. Link: https://lore.kernel.org/r/20200305160452.27808-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sirfsoc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index b2e72597eee8..8b3c88fb9793 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -346,6 +346,7 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtcdrv->rtc); rtcdrv->rtc->ops = &sirfsoc_rtc_ops; + rtcdrv->rtc->range_max = (1ULL << 60) - 1; rtcdrv->irq = platform_get_irq(pdev, 0); err = devm_request_irq(&pdev->dev, rtcdrv->irq, sirfsoc_rtc_irq_handler, From 09b875a426c97bd6b2e6a56b8ca37680965524fb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 17:04:52 +0100 Subject: [PATCH 293/809] rtc: sirfsoc: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion to avoid the y2106 issue. Link: https://lore.kernel.org/r/20200305160452.27808-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sirfsoc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 8b3c88fb9793..abf19435dbad 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -90,13 +90,13 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, */ /* if alarm is in next overflow cycle */ if (rtc_count > rtc_alarm) - rtc_time_to_tm((rtcdrv->overflow_rtc + 1) - << (BITS_PER_LONG - RTC_SHIFT) - | rtc_alarm >> RTC_SHIFT, &(alrm->time)); + rtc_time64_to_tm((rtcdrv->overflow_rtc + 1) + << (BITS_PER_LONG - RTC_SHIFT) + | rtc_alarm >> RTC_SHIFT, &alrm->time); else - rtc_time_to_tm(rtcdrv->overflow_rtc - << (BITS_PER_LONG - RTC_SHIFT) - | rtc_alarm >> RTC_SHIFT, &(alrm->time)); + rtc_time64_to_tm(rtcdrv->overflow_rtc + << (BITS_PER_LONG - RTC_SHIFT) + | rtc_alarm >> RTC_SHIFT, &alrm->time); if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E) alrm->enabled = 1; @@ -113,7 +113,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, rtcdrv = dev_get_drvdata(dev); if (alrm->enabled) { - rtc_tm_to_time(&(alrm->time), &rtc_alarm); + rtc_alarm = rtc_tm_to_time64(&alrm->time); spin_lock_irq(&rtcdrv->lock); @@ -181,8 +181,8 @@ static int sirfsoc_rtc_read_time(struct device *dev, cpu_relax(); } while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN)); - rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | - tmp_rtc >> RTC_SHIFT, tm); + rtc_time64_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) + | tmp_rtc >> RTC_SHIFT, tm); return 0; } @@ -193,7 +193,7 @@ static int sirfsoc_rtc_set_time(struct device *dev, struct sirfsoc_rtc_drv *rtcdrv; rtcdrv = dev_get_drvdata(dev); - rtc_tm_to_time(tm, &rtc_time); + rtc_time = rtc_tm_to_time64(tm); rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); From b1c67e0b07c5613bb7e2ad20eee9a6e5d1504fd1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 22:50:19 +0100 Subject: [PATCH 294/809] rtc: davinci: convert to devm_rtc_allocate_device This allows further improvement of the driver. Also remove the unnecessary error string as the core will already display error messages. Link: https://lore.kernel.org/r/20200305215022.32533-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-davinci.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 390b7351e0fe..d620d147c604 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -485,13 +485,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, davinci_rtc); - davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &davinci_rtc_ops, THIS_MODULE); - if (IS_ERR(davinci_rtc->rtc)) { - dev_err(dev, "unable to register RTC device, err %d\n", - ret); + davinci_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(davinci_rtc->rtc)) return PTR_ERR(davinci_rtc->rtc); - } + + davinci_rtc->rtc->ops = &davinci_rtc_ops; rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); @@ -516,7 +514,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); - return 0; + return rtc_register_device(davinci_rtc->rtc); } static int __exit davinci_rtc_remove(struct platform_device *pdev) From dc924ce9a1848cf5c86c878f0df16c725788e8d3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 22:50:20 +0100 Subject: [PATCH 295/809] rtc: davinci: remove useless 24h alarm handling The code handling invalid alarms meaning the alarm is in the next 24 hours is not necessary since commit f8245c26886c ("rtc: remove "RTC_ALM_SET mode" bugs") which actually predates this driver. Since then, .set_alarm is never called with an invalid alarm and this handling is not necessary in the driver. Link: https://lore.kernel.org/r/20200305215022.32533-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-davinci.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index d620d147c604..3043ffea8f7c 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -413,27 +413,6 @@ static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) unsigned long flags; u16 days; - if (alm->time.tm_mday <= 0 && alm->time.tm_mon < 0 - && alm->time.tm_year < 0) { - struct rtc_time tm; - unsigned long now, then; - - davinci_rtc_read_time(dev, &tm); - rtc_tm_to_time(&tm, &now); - - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - rtc_tm_to_time(&alm->time, &then); - - if (then < now) { - rtc_time_to_tm(now + 24 * 60 * 60, &tm); - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - } - } - if (convert2days(&days, &alm->time) < 0) return -EINVAL; From b6d8f589204802ec531a9de69abd8563f4640d30 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 22:50:21 +0100 Subject: [PATCH 296/809] rtc: davinci: let the core handle rtc range Let the core handle offsetting and windowing the RTC range. This rtc has hours, minutes, seconds and 16bit days. As the driver has the RTC epoch set to year 2000, this means that the end of the range is 2^16 days minus one second later. This is Sun Jun 6 23:59:59 UTC 2179. This is better than the currently set year 2099. Link: https://lore.kernel.org/r/20200305215022.32533-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-davinci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 3043ffea8f7c..55d826dafe1d 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -258,10 +258,6 @@ static int convert2days(u16 *days, struct rtc_time *tm) int i; *days = 0; - /* epoch == 1900 */ - if (tm->tm_year < 100 || tm->tm_year > 199) - return -EINVAL; - for (i = 2000; i < 1900 + tm->tm_year; i++) *days += rtc_year_days(1, 12, i); @@ -313,8 +309,7 @@ static int davinci_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 rtc_cctrl; unsigned long flags; - if (convert2days(&days, tm) < 0) - return -EINVAL; + convert2days(&days, tm); spin_lock_irqsave(&davinci_rtc_lock, flags); @@ -413,8 +408,7 @@ static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) unsigned long flags; u16 days; - if (convert2days(&days, &alm->time) < 0) - return -EINVAL; + convert2days(&days, &alm->time); spin_lock_irqsave(&davinci_rtc_lock, flags); @@ -469,6 +463,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) return PTR_ERR(davinci_rtc->rtc); davinci_rtc->rtc->ops = &davinci_rtc_ops; + davinci_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + davinci_rtc->rtc->range_max = RTC_TIMESTAMP_BEGIN_2000 + (1 << 16) * 86400ULL - 1; rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); From 6a5bbad5869132ca1d0ada05fd0c6278d7450928 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 5 Mar 2020 22:50:22 +0100 Subject: [PATCH 297/809] rtc: davinci: remove useless error handling convertfromdays and convert2days never return errors, stop handling non existent errors. Link: https://lore.kernel.org/r/20200305215022.32533-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-davinci.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 55d826dafe1d..73f87a17cdf3 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -227,7 +227,7 @@ davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return ret; } -static int convertfromdays(u16 days, struct rtc_time *tm) +static void convertfromdays(u16 days, struct rtc_time *tm) { int tmp_days, year, mon; @@ -250,10 +250,9 @@ static int convertfromdays(u16 days, struct rtc_time *tm) break; } } - return 0; } -static int convert2days(u16 *days, struct rtc_time *tm) +static void convert2days(u16 *days, struct rtc_time *tm) { int i; *days = 0; @@ -262,8 +261,6 @@ static int convert2days(u16 *days, struct rtc_time *tm) *days += rtc_year_days(1, 12, i); *days += rtc_year_days(tm->tm_mday, tm->tm_mon, 1900 + tm->tm_year); - - return 0; } static int davinci_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -296,8 +293,7 @@ static int davinci_rtc_read_time(struct device *dev, struct rtc_time *tm) days <<= 8; days |= day0; - if (convertfromdays(days, tm) < 0) - return -EINVAL; + convertfromdays(days, tm); return 0; } @@ -391,8 +387,7 @@ static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) days <<= 8; days |= day0; - if (convertfromdays(days, &alm->time) < 0) - return -EINVAL; + convertfromdays(days, &alm->time); alm->pending = !!(rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) & From 9896169a1222a8db725fa70b3bad0d813cc3b144 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:57:28 +0100 Subject: [PATCH 298/809] rtc: pl030: set range This RTC is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306005730.38268-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl030.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index d4a5f8afafbc..30aa813f96c0 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -116,6 +116,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) } rtc->rtc->ops = &pl030_ops; + rtc->rtc->range_max = U32_MAX; rtc->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!rtc->base) { ret = -ENOMEM; From b303b2fe5d972807407214b766c21d335414fc4b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:57:29 +0100 Subject: [PATCH 299/809] rtc: pl030: remove useless invalid alarm handling The core will never pass an invalid alarm to .set_alarm, it is not necessary to check for its validity. Link: https://lore.kernel.org/r/20200306005730.38268-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl030.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 30aa813f96c0..55776e8fa87c 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -46,12 +46,7 @@ static int pl030_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned long time; int ret; - /* - * At the moment, we can only deal with non-wildcarded alarm times. - */ - ret = rtc_valid_tm(&alrm->time); - if (ret == 0) - ret = rtc_tm_to_time(&alrm->time, &time); + ret = rtc_tm_to_time(&alrm->time, &time); if (ret == 0) writel(time, rtc->base + RTC_MR); return ret; From c33c4713cd6bacafa27de2882e14008c4d9cc756 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:57:30 +0100 Subject: [PATCH 300/809] rtc: pl030: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion to avoid the y2106 issue. Link: https://lore.kernel.org/r/20200306005730.38268-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl030.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 55776e8fa87c..ebe03eba8f5f 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -36,27 +36,24 @@ static int pl030_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pl030_rtc *rtc = dev_get_drvdata(dev); - rtc_time_to_tm(readl(rtc->base + RTC_MR), &alrm->time); + rtc_time64_to_tm(readl(rtc->base + RTC_MR), &alrm->time); return 0; } static int pl030_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pl030_rtc *rtc = dev_get_drvdata(dev); - unsigned long time; - int ret; - ret = rtc_tm_to_time(&alrm->time, &time); - if (ret == 0) - writel(time, rtc->base + RTC_MR); - return ret; + writel(rtc_tm_to_time64(&alrm->time), rtc->base + RTC_MR); + + return 0; } static int pl030_read_time(struct device *dev, struct rtc_time *tm) { struct pl030_rtc *rtc = dev_get_drvdata(dev); - rtc_time_to_tm(readl(rtc->base + RTC_DR), tm); + rtc_time64_to_tm(readl(rtc->base + RTC_DR), tm); return 0; } @@ -72,14 +69,10 @@ static int pl030_read_time(struct device *dev, struct rtc_time *tm) static int pl030_set_time(struct device *dev, struct rtc_time *tm) { struct pl030_rtc *rtc = dev_get_drvdata(dev); - unsigned long time; - int ret; - ret = rtc_tm_to_time(tm, &time); - if (ret == 0) - writel(time + 1, rtc->base + RTC_LR); + writel(rtc_tm_to_time64(tm) + 1, rtc->base + RTC_LR); - return ret; + return 0; } static const struct rtc_class_ops pl030_ops = { From 166b13325c5b9cfcd58954a12a0734f316d55b60 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:09 +0100 Subject: [PATCH 301/809] rtc: starfire: set range The starfire RTC is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306005910.38939-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-starfire.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index a7d49329d626..f21f4f961f3a 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -39,14 +39,16 @@ static int __init starfire_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - rtc = devm_rtc_device_register(&pdev->dev, "starfire", - &starfire_rtc_ops, THIS_MODULE); + rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); + rtc->ops = &starfire_rtc_ops; + rtc->range_max = U32_MAX; + platform_set_drvdata(pdev, rtc); - return 0; + return rtc_register_device(rtc); } static struct platform_driver starfire_rtc_driver = { From 326bce078a6a8b04266a816e63f6f9e74ed98457 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:10 +0100 Subject: [PATCH 302/809] rtc: starfire: switch to rtc_time64_to_tm Call the 64bit version of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306005910.38939-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-starfire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index f21f4f961f3a..37a26279e107 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -27,7 +27,7 @@ static u32 starfire_get_time(void) static int starfire_read_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(starfire_get_time(), tm); + rtc_time64_to_tm(starfire_get_time(), tm); return 0; } From 7fc9790aa38f22372c449b48ff25c71fbdd8e755 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:55 +0100 Subject: [PATCH 303/809] rtc: au1xxx: convert to devm_rtc_allocate_device This allows further improvement of the driver. Link: https://lore.kernel.org/r/20200306005958.39203-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-au1xxx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index 7c5530c71285..a13ac73aa2b7 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -99,16 +99,15 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev) while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C0S) msleep(1); - rtcdev = devm_rtc_device_register(&pdev->dev, "rtc-au1xxx", - &au1xtoy_rtc_ops, THIS_MODULE); - if (IS_ERR(rtcdev)) { - ret = PTR_ERR(rtcdev); - goto out_err; - } + rtcdev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtcdev)) + return PTR_ERR(rtcdev); + + rtcdev->ops = &au1xtoy_rtc_ops; platform_set_drvdata(pdev, rtcdev); - return 0; + return rtc_register_device(rtcdev); out_err: return ret; From 9cf71edb024a919a8ed8957748885d1e1e8d231a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:56 +0100 Subject: [PATCH 304/809] rtc: au1xxx: remove goto label Simplify the driver by removing the goto label as it only does return ret. Link: https://lore.kernel.org/r/20200306005958.39203-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-au1xxx.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index a13ac73aa2b7..73aeb15f9491 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -65,17 +65,13 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtcdev; unsigned long t; - int ret; t = alchemy_rdsys(AU1000_SYS_CNTRCTRL); if (!(t & CNTR_OK)) { dev_err(&pdev->dev, "counters not working; aborting.\n"); - ret = -ENODEV; - goto out_err; + return -ENODEV; } - ret = -ETIMEDOUT; - /* set counter0 tickrate to 1Hz if necessary */ if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767) { /* wait until hardware gives access to TRIM register */ @@ -88,7 +84,7 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev) * counters are unusable. */ dev_err(&pdev->dev, "timeout waiting for access\n"); - goto out_err; + return -ETIMEDOUT; } /* set 1Hz TOY tick rate */ @@ -108,9 +104,6 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtcdev); return rtc_register_device(rtcdev); - -out_err: - return ret; } static struct platform_driver au1xrtc_driver = { From b1b686e4b0d165ae7c1e356ecf8da790ee8f8dcf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:57 +0100 Subject: [PATCH 305/809] rtc: au1xxx: set range The Alchemy counter0 is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306005958.39203-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-au1xxx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index 73aeb15f9491..e186fb5cfffd 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -100,6 +100,7 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtcdev); rtcdev->ops = &au1xtoy_rtc_ops; + rtcdev->range_max = U32_MAX; platform_set_drvdata(pdev, rtcdev); From 0a22bd6fe46db507b4e9d3ea2db3dc8ed480b0b3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:59:58 +0100 Subject: [PATCH 306/809] rtc: au1xxx: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306005958.39203-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-au1xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index e186fb5cfffd..791bebcb6f47 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -34,7 +34,7 @@ static int au1xtoy_rtc_read_time(struct device *dev, struct rtc_time *tm) t = alchemy_rdsys(AU1000_SYS_TOYREAD); - rtc_time_to_tm(t, tm); + rtc_time64_to_tm(t, tm); return 0; } @@ -43,7 +43,7 @@ static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned long t; - rtc_tm_to_time(tm, &t); + t = rtc_tm_to_time64(tm); alchemy_wrsys(t, AU1000_SYS_TOYWRITE); From f2997775b111c6d660c32a18d5d44d37cb7361b1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:01:44 +0100 Subject: [PATCH 307/809] rtc: sa1100: fix possible race condition Both RTC IRQs are requested before the struct rtc_device is allocated, this may lead to a NULL pointer dereference in the IRQ handler. To fix this issue, allocating the rtc_device struct before requesting the IRQs using devm_rtc_allocate_device, and use rtc_register_device to register the RTC device. Link: https://lore.kernel.org/r/20200306010146.39762-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index d37893f6eaee..97c352594033 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -182,7 +182,6 @@ static const struct rtc_class_ops sa1100_rtc_ops = { int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) { - struct rtc_device *rtc; int ret; spin_lock_init(&info->lock); @@ -211,15 +210,14 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) writel_relaxed(0, info->rcnr); } - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) { - clk_disable_unprepare(info->clk); - return PTR_ERR(rtc); - } - info->rtc = rtc; + info->rtc->ops = &sa1100_rtc_ops; + info->rtc->max_user_freq = RTC_FREQ; - rtc->max_user_freq = RTC_FREQ; + ret = rtc_register_device(info->rtc); + if (ret) { + clk_disable_unprepare(info->clk); + return ret; + } /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). @@ -267,6 +265,10 @@ static int sa1100_rtc_probe(struct platform_device *pdev) info->irq_1hz = irq_1hz; info->irq_alarm = irq_alarm; + info->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(info->rtc)) + return PTR_ERR(info->rtc); + ret = devm_request_irq(&pdev->dev, irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", &pdev->dev); if (ret) { From e877ab73028f783f5b0ce09b9bbcaaa30e1bebbe Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:01:45 +0100 Subject: [PATCH 308/809] rtc: sa1100: set range The SA1100 RTC is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306010146.39762-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 97c352594033..82a9d4ab368f 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -212,6 +212,7 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) info->rtc->ops = &sa1100_rtc_ops; info->rtc->max_user_freq = RTC_FREQ; + info->rtc->range_max = U32_MAX; ret = rtc_register_device(info->rtc); if (ret) { From eb8d94203292c9d7be2dacd97e80b4d128e9f6a2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:01:46 +0100 Subject: [PATCH 309/809] rtc: sa1100: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306010146.39762-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 82a9d4ab368f..9ccc97cf5e09 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -111,20 +111,17 @@ static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct sa1100_rtc *info = dev_get_drvdata(dev); - rtc_time_to_tm(readl_relaxed(info->rcnr), tm); + rtc_time64_to_tm(readl_relaxed(info->rcnr), tm); return 0; } static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct sa1100_rtc *info = dev_get_drvdata(dev); - unsigned long time; - int ret; - ret = rtc_tm_to_time(tm, &time); - if (ret == 0) - writel_relaxed(time, info->rcnr); - return ret; + writel_relaxed(rtc_tm_to_time64(tm), info->rcnr); + + return 0; } static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -141,24 +138,18 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct sa1100_rtc *info = dev_get_drvdata(dev); - unsigned long time; - int ret; spin_lock_irq(&info->lock); - ret = rtc_tm_to_time(&alrm->time, &time); - if (ret != 0) - goto out; writel_relaxed(readl_relaxed(info->rtsr) & (RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr); - writel_relaxed(time, info->rtar); + writel_relaxed(rtc_tm_to_time64(&alrm->time), info->rtar); if (alrm->enabled) writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr); else writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr); -out: spin_unlock_irq(&info->lock); - return ret; + return 0; } static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) From 05b38d182c5deeadb1b7eeb3e35c35b7652dc0e8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:57:01 +0100 Subject: [PATCH 310/809] rtc: cpcap: convert to devm_rtc_allocate_device This allows further improvement of the driver. Link: https://lore.kernel.org/r/20200306015703.42101-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cpcap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c index 6a3b70fd7e1f..35f0717661b3 100644 --- a/drivers/rtc/rtc-cpcap.c +++ b/drivers/rtc/rtc-cpcap.c @@ -256,12 +256,12 @@ static int cpcap_rtc_probe(struct platform_device *pdev) return -ENODEV; platform_set_drvdata(pdev, rtc); - rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc", - &cpcap_rtc_ops, THIS_MODULE); - + rtc->rtc_dev = devm_rtc_allocate_device(dev); if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); + rtc->rtc_dev->ops = &cpcap_rtc_ops; + err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor); if (err) return err; @@ -298,7 +298,7 @@ static int cpcap_rtc_probe(struct platform_device *pdev) /* ignore error and continue without wakeup support */ } - return 0; + return rtc_register_device(rtc->rtc_dev); } static const struct of_device_id cpcap_rtc_of_match[] = { From d2377f8cc5a7add7ba78db8122cf33e83c47d525 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:57:02 +0100 Subject: [PATCH 311/809] rtc: cpcap: set range The CPCAP rtc is a 14bit day counter plus a 17bit seconds counter. Note that this failed on Nov 10 2014 so it is very likely this driver as never been used since. Link: https://lore.kernel.org/r/20200306015703.42101-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cpcap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c index 35f0717661b3..38f949730b1b 100644 --- a/drivers/rtc/rtc-cpcap.c +++ b/drivers/rtc/rtc-cpcap.c @@ -261,6 +261,7 @@ static int cpcap_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc->rtc_dev); rtc->rtc_dev->ops = &cpcap_rtc_ops; + rtc->rtc_dev->range_max = (1 << 14) * SECS_PER_DAY - 1; err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor); if (err) From d238df15e5cdfae54688ed9c1b33e19ed747dcda Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:57:03 +0100 Subject: [PATCH 312/809] rtc: cpcap: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306015703.42101-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cpcap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c index 38f949730b1b..a603f1f21125 100644 --- a/drivers/rtc/rtc-cpcap.c +++ b/drivers/rtc/rtc-cpcap.c @@ -56,14 +56,14 @@ static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap) tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8); time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY); - rtc_time_to_tm(time, rtc); + rtc_time64_to_tm(time, rtc); } static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc) { unsigned long time; - rtc_tm_to_time(rtc, &time); + time = rtc_tm_to_time64(rtc); cpcap->day = time / SECS_PER_DAY; time %= SECS_PER_DAY; From c11af8131a4e7ba1960faed731ee7e84c2c13c94 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:34:01 +0100 Subject: [PATCH 313/809] rtc: ds1374: fix possible race condition The RTC IRQ is requested before the struct rtc_device is allocated, this may lead to a NULL pointer dereference in the IRQ handler. To fix this issue, allocating the rtc_device struct before requesting the RTC IRQ using devm_rtc_allocate_device, and use rtc_register_device to register the RTC device. Link: https://lore.kernel.org/r/20200306073404.56921-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 6e9ddcd03992..cb18a11a3c76 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -620,6 +620,10 @@ static int ds1374_probe(struct i2c_client *client, if (!ds1374) return -ENOMEM; + ds1374->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(ds1374->rtc)) + return PTR_ERR(ds1374->rtc); + ds1374->client = client; i2c_set_clientdata(client, ds1374); @@ -641,12 +645,11 @@ static int ds1374_probe(struct i2c_client *client, device_set_wakeup_capable(&client->dev, 1); } - ds1374->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds1374_rtc_ops, THIS_MODULE); - if (IS_ERR(ds1374->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); - return PTR_ERR(ds1374->rtc); - } + ds1374->rtc->ops = &ds1374_rtc_ops; + + ret = rtc_register_device(ds1374->rtc); + if (ret) + return ret; #ifdef CONFIG_RTC_DRV_DS1374_WDT save_client = client; From 4136ff3a515752327baad3b78e3452af13bfdd05 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:34:02 +0100 Subject: [PATCH 314/809] rtc: ds1374: set range The ds1374 is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306073404.56921-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index cb18a11a3c76..843fcbf5e940 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -646,6 +646,7 @@ static int ds1374_probe(struct i2c_client *client, } ds1374->rtc->ops = &ds1374_rtc_ops; + ds1374->rtc->range_max = U32_MAX; ret = rtc_register_device(ds1374->rtc); if (ret) From ca824be9b394a7bab7e01269bde7e7986ca81ccc Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:34:03 +0100 Subject: [PATCH 315/809] rtc: ds1374: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306073404.56921-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 843fcbf5e940..9c51a12cf70f 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -164,7 +164,7 @@ static int ds1374_read_time(struct device *dev, struct rtc_time *time) ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4); if (!ret) - rtc_time_to_tm(itime, time); + rtc_time64_to_tm(itime, time); return ret; } @@ -172,9 +172,8 @@ static int ds1374_read_time(struct device *dev, struct rtc_time *time) static int ds1374_set_time(struct device *dev, struct rtc_time *time) { struct i2c_client *client = to_i2c_client(dev); - unsigned long itime; + unsigned long itime = rtc_tm_to_time64(time); - rtc_tm_to_time(time, &itime); return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); } @@ -212,7 +211,7 @@ static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (ret) goto out; - rtc_time_to_tm(now + cur_alarm, &alarm->time); + rtc_time64_to_tm(now + cur_alarm, &alarm->time); alarm->enabled = !!(cr & DS1374_REG_CR_WACE); alarm->pending = !!(sr & DS1374_REG_SR_AF); @@ -237,8 +236,8 @@ static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (ret < 0) return ret; - rtc_tm_to_time(&alarm->time, &new_alarm); - rtc_tm_to_time(&now, &itime); + new_alarm = rtc_tm_to_time64(&alarm->time); + itime = rtc_tm_to_time64(&now); /* This can happen due to races, in addition to dates that are * truly in the past. To avoid requiring the caller to check for From 9869a93c823bc7fe2fba7407ea25f400c8f98e61 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:34:58 +0100 Subject: [PATCH 316/809] rtc: ds1305: set range The ds1305 is a BCD rtc valid from 2000 to 2099. Link: https://lore.kernel.org/r/20200306073459.57197-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 4420fbf2f8fe..ca55ebab24fb 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -694,6 +694,8 @@ static int ds1305_probe(struct spi_device *spi) return PTR_ERR(ds1305->rtc); ds1305->rtc->ops = &ds1305_ops; + ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099; ds1305_nvmem_cfg.priv = ds1305; ds1305->rtc->nvram_old_abi = true; From f2adcb9c3abde5470c0cfbd74e40dec820a40153 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:34:59 +0100 Subject: [PATCH 317/809] rtc: ds1305: switch to rtc_tm_to_time64 Call the 64bit version of rtc_tm to time conversion. Link: https://lore.kernel.org/r/20200306073459.57197-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index ca55ebab24fb..a3d790889eea 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -325,17 +325,13 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm) u8 buf[1 + DS1305_ALM_LEN]; /* convert desired alarm to time_t */ - status = rtc_tm_to_time(&alm->time, &later); - if (status < 0) - return status; + later = rtc_tm_to_time64(&alm->time); /* Read current time as time_t */ status = ds1305_get_time(dev, &tm); if (status < 0) return status; - status = rtc_tm_to_time(&tm, &now); - if (status < 0) - return status; + now = rtc_tm_to_time64(&tm); /* make sure alarm fires within the next 24 hours */ if (later <= now) From d5d55b70984086bffe7a6321c0d28d3c7f41b9fa Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:37:55 +0100 Subject: [PATCH 318/809] rtc: pm8xxx: convert to devm_rtc_allocate_device This allows further improvement of the driver. Also remove the unnecessary error string as the core will already display error messages. Link: https://lore.kernel.org/r/20200306073758.58050-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 07ea1be3abb9..b97333c95e53 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -486,13 +486,11 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); /* Register the RTC device */ - rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc", - &pm8xxx_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc_dd->rtc)) { - dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n", - __func__, PTR_ERR(rtc_dd->rtc)); + rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc_dd->rtc)) return PTR_ERR(rtc_dd->rtc); - } + + rtc_dd->rtc->ops = &pm8xxx_rtc_ops; /* Request the alarm IRQ */ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq, @@ -504,9 +502,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return rc; } - dev_dbg(&pdev->dev, "Probe success !!\n"); - - return 0; + return rtc_register_device(rtc_dd->rtc); } #ifdef CONFIG_PM_SLEEP From 3cfe52607779a5c3752a73033a86385789ceb742 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:37:56 +0100 Subject: [PATCH 319/809] rtc: pm8xxx: set range The pm8xxx are 32bit seconds counter. Link: https://lore.kernel.org/r/20200306073758.58050-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index b97333c95e53..71bd56d32c90 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -491,6 +491,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc_dd->rtc); rtc_dd->rtc->ops = &pm8xxx_rtc_ops; + rtc_dd->rtc->range_max = U32_MAX; /* Request the alarm IRQ */ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq, From 4c470b2f121365800972b71e787aae359ff186a7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:37:57 +0100 Subject: [PATCH 320/809] rtc: pm8xxx: : switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306073758.58050-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 71bd56d32c90..2da0d80224c3 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -84,7 +84,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) if (!rtc_dd->allow_set_time) return -EACCES; - rtc_tm_to_time(tm, &secs); + secs = rtc_tm_to_time64(tm); dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); @@ -208,7 +208,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) secs = value[0] | (value[1] << 8) | (value[2] << 16) | ((unsigned long)value[3] << 24); - rtc_time_to_tm(secs, tm); + rtc_time64_to_tm(secs, tm); dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm); @@ -224,7 +224,7 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; - rtc_tm_to_time(&alarm->time, &secs); + secs = rtc_tm_to_time64(&alarm->time); for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { value[i] = secs & 0xFF; @@ -280,7 +280,7 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) secs = value[0] | (value[1] << 8) | (value[2] << 16) | ((unsigned long)value[3] << 24); - rtc_time_to_tm(secs, &alarm->time); + rtc_time64_to_tm(secs, &alarm->time); rc = rtc_valid_tm(&alarm->time); if (rc < 0) { From c47cf9d6bb7bc0c2ca917602c60bd79bcb0d35df Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:37:58 +0100 Subject: [PATCH 321/809] rtc: pm8xxx: stop validating valid alarm time rtc_time64_to_tm never generates an invalid rtc_tm, stop validating it. Link: https://lore.kernel.org/r/20200306073758.58050-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 2da0d80224c3..e3d9abb2134e 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -282,12 +282,6 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_time64_to_tm(secs, &alarm->time); - rc = rtc_valid_tm(&alarm->time); - if (rc < 0) { - dev_err(dev, "Invalid alarm time read from RTC\n"); - return rc; - } - dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n", &alarm->time, &alarm->time); From d53d4ae981d065a63423b0fe64d18827ed540349 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:44:00 +0100 Subject: [PATCH 322/809] rtc: mpc5121: simplify probe Use devm managed function to simplify probe and remove. Link: https://lore.kernel.org/r/20200306074404.58909-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mpc5121.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 15a9d0278778..9e4454d35352 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -315,8 +315,8 @@ static int mpc5121_rtc_probe(struct platform_device *op) if (!rtc) return -ENOMEM; - rtc->regs = of_iomap(op->dev.of_node, 0); - if (!rtc->regs) { + rtc->regs = devm_platform_ioremap_resource(op, 0); + if (IS_ERR(rtc->regs)) { dev_err(&op->dev, "%s: couldn't map io space\n", __func__); return -ENOSYS; } @@ -326,8 +326,8 @@ static int mpc5121_rtc_probe(struct platform_device *op) platform_set_drvdata(op, rtc); rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1); - err = request_irq(rtc->irq, mpc5121_rtc_handler, 0, - "mpc5121-rtc", &op->dev); + err = devm_request_irq(&op->dev, rtc->irq, mpc5121_rtc_handler, 0, + "mpc5121-rtc", &op->dev); if (err) { dev_err(&op->dev, "%s: could not request irq: %i\n", __func__, rtc->irq); @@ -335,8 +335,9 @@ static int mpc5121_rtc_probe(struct platform_device *op) } rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0); - err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd, - 0, "mpc5121-rtc_upd", &op->dev); + err = devm_request_irq(&op->dev, rtc->irq_periodic, + mpc5121_rtc_handler_upd, 0, "mpc5121-rtc_upd", + &op->dev); if (err) { dev_err(&op->dev, "%s: could not request irq: %i\n", __func__, rtc->irq_periodic); @@ -361,20 +362,16 @@ static int mpc5121_rtc_probe(struct platform_device *op) if (IS_ERR(rtc->rtc)) { err = PTR_ERR(rtc->rtc); - goto out_free_irq; + goto out_dispose2; } rtc->rtc->uie_unsupported = 1; return 0; -out_free_irq: - free_irq(rtc->irq_periodic, &op->dev); out_dispose2: irq_dispose_mapping(rtc->irq_periodic); - free_irq(rtc->irq, &op->dev); out_dispose: irq_dispose_mapping(rtc->irq); - iounmap(rtc->regs); return err; } @@ -388,9 +385,6 @@ static int mpc5121_rtc_remove(struct platform_device *op) out_8(®s->alm_enable, 0); out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1); - iounmap(rtc->regs); - free_irq(rtc->irq, &op->dev); - free_irq(rtc->irq_periodic, &op->dev); irq_dispose_mapping(rtc->irq); irq_dispose_mapping(rtc->irq_periodic); From fffbe10e2fd3a92a401cbcbb77da7f67fe900eeb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:44:01 +0100 Subject: [PATCH 323/809] rtc: mpc5121: convert to devm_rtc_allocate_device This simplifies the path for the rtc_ops selection. Link: https://lore.kernel.org/r/20200306074404.58909-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mpc5121.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 9e4454d35352..845212fd1e33 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -344,6 +344,15 @@ static int mpc5121_rtc_probe(struct platform_device *op) goto out_dispose2; } + rtc->rtc = devm_rtc_allocate_device(&op->dev); + if (IS_ERR(rtc->rtc)) { + err = PTR_ERR(rtc->rtc); + goto out_dispose2; + } + + rtc->rtc->ops = &mpc5200_rtc_ops; + rtc->rtc->uie_unsupported = 1; + if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) { u32 ka; ka = in_be32(&rtc->regs->keep_alive); @@ -352,19 +361,12 @@ static int mpc5121_rtc_probe(struct platform_device *op) "mpc5121-rtc: Battery or oscillator failure!\n"); out_be32(&rtc->regs->keep_alive, ka); } - - rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5121-rtc", - &mpc5121_rtc_ops, THIS_MODULE); - } else { - rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5200-rtc", - &mpc5200_rtc_ops, THIS_MODULE); + rtc->rtc->ops = &mpc5121_rtc_ops; } - if (IS_ERR(rtc->rtc)) { - err = PTR_ERR(rtc->rtc); + err = rtc_register_device(rtc->rtc); + if (err) goto out_dispose2; - } - rtc->rtc->uie_unsupported = 1; return 0; From 3905d1c02dc9dd0b498567f52380bcd9ce6420af Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:44:02 +0100 Subject: [PATCH 324/809] rtc: mpc5121: set range The datasheet states that 4052 is the maximum value for year. However, the mpc5121 read_time and set_time function abuse the target time register instead of using the broken down time so it is limited to 2106. Link: https://lore.kernel.org/r/20200306074404.58909-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mpc5121.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 845212fd1e33..5507f1847f7c 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -352,6 +352,8 @@ static int mpc5121_rtc_probe(struct platform_device *op) rtc->rtc->ops = &mpc5200_rtc_ops; rtc->rtc->uie_unsupported = 1; + rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000; + rtc->rtc->range_max = 65733206399ULL; /* 4052-12-31 23:59:59 */ if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) { u32 ka; @@ -362,6 +364,13 @@ static int mpc5121_rtc_probe(struct platform_device *op) out_be32(&rtc->regs->keep_alive, ka); } rtc->rtc->ops = &mpc5121_rtc_ops; + /* + * This is a limitation of the driver that abuses the target + * time register, the actual maximum year for the mpc5121 is + * also 4052. + */ + rtc->rtc->range_min = 0; + rtc->rtc->range_max = U32_MAX; } err = rtc_register_device(rtc->rtc); From 3d5a49545ac549c122b24c2af730ad00093e5d1f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 08:44:03 +0100 Subject: [PATCH 325/809] rtc: mpc5121: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306074404.58909-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mpc5121.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 5507f1847f7c..3040844129ce 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -111,7 +111,7 @@ static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm) */ now = in_be32(®s->actual_time) + in_be32(®s->target_time); - rtc_time_to_tm(now, tm); + rtc_time64_to_tm(now, tm); /* * update second minute hour registers @@ -126,16 +126,14 @@ static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); struct mpc5121_rtc_regs __iomem *regs = rtc->regs; - int ret; unsigned long now; /* * The actual_time register is read only so we write the offset * between it and linux time to the target_time register. */ - ret = rtc_tm_to_time(tm, &now); - if (ret == 0) - out_be32(®s->target_time, now - in_be32(®s->actual_time)); + now = rtc_tm_to_time64(tm); + out_be32(®s->target_time, now - in_be32(®s->actual_time)); /* * update second minute hour registers From 7098f5368268800a65cc45d91b42281dd0572514 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 14:16:28 +0100 Subject: [PATCH 326/809] rtc: fsl-ftm-alarm: allow COMPILE_TEST Allow building building the driver with COMPILE_TEST. Link: https://lore.kernel.org/r/20200306131629.18837-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index acaf6f98b54e..777047620ec7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1334,7 +1334,7 @@ config RTC_DRV_IMXDI config RTC_DRV_FSL_FTM_ALARM tristate "Freescale FlexTimer alarm timer" - depends on ARCH_LAYERSCAPE || SOC_LS1021A + depends on ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST help For the FlexTimer in LS1012A, LS1021A, LS1028A, LS1043A, LS1046A, LS1088A, LS208xA, we can use FTM as the wakeup source. From 61c9fbff9d62e1de214f15c0f9c692a81430f4ff Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:58:07 +0100 Subject: [PATCH 327/809] rtc: pl031: remove useless invalid alarm handling The core will never pass an invalid alarm to .set_alarm, it is not necessary to check for its validity. Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20200306005809.38530-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 180caebbd355..2e8e019a6e4c 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -210,17 +210,13 @@ static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long bcd_year; int ret; - /* At the moment, we can only deal with non-wildcarded alarm times. */ - ret = rtc_valid_tm(&alarm->time); + ret = pl031_stv2_tm_to_time(dev, &alarm->time, + &time, &bcd_year); if (ret == 0) { - ret = pl031_stv2_tm_to_time(dev, &alarm->time, - &time, &bcd_year); - if (ret == 0) { - writel(bcd_year, ldata->base + RTC_YMR); - writel(time, ldata->base + RTC_MR); + writel(bcd_year, ldata->base + RTC_YMR); + writel(time, ldata->base + RTC_MR); - pl031_alarm_irq_enable(dev, alarm->enabled); - } + pl031_alarm_irq_enable(dev, alarm->enabled); } return ret; @@ -285,14 +281,10 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long time; int ret; - /* At the moment, we can only deal with non-wildcarded alarm times. */ - ret = rtc_valid_tm(&alarm->time); + ret = rtc_tm_to_time(&alarm->time, &time); if (ret == 0) { - ret = rtc_tm_to_time(&alarm->time, &time); - if (ret == 0) { - writel(time, ldata->base + RTC_MR); - pl031_alarm_irq_enable(dev, alarm->enabled); - } + writel(time, ldata->base + RTC_MR); + pl031_alarm_irq_enable(dev, alarm->enabled); } return ret; From 03f2a0e45f395bc34b0a44105bc7e935bfd40c27 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:58:08 +0100 Subject: [PATCH 328/809] rtc: pl031: set range The PL031 and ST v1 RTC are 32bit seconds counters. STv2 is a BCD RTC apparently going from 0000 to 9999, hopefully handling the leap days properly until then. Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20200306005809.38530-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 2e8e019a6e4c..07dc0f264100 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -80,6 +80,8 @@ struct pl031_vendor_data { bool clockwatch; bool st_weekday; unsigned long irqflags; + time64_t range_min; + timeu64_t range_max; }; struct pl031_local { @@ -375,6 +377,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) return PTR_ERR(ldata->rtc); ldata->rtc->ops = ops; + ldata->rtc->range_min = vendor->range_min; + ldata->rtc->range_max = vendor->range_max; ret = rtc_register_device(ldata->rtc); if (ret) @@ -405,6 +409,7 @@ static struct pl031_vendor_data arm_pl031 = { .set_alarm = pl031_set_alarm, .alarm_irq_enable = pl031_alarm_irq_enable, }, + .range_max = U32_MAX, }; /* The First ST derivative */ @@ -418,6 +423,7 @@ static struct pl031_vendor_data stv1_pl031 = { }, .clockwatch = true, .st_weekday = true, + .range_max = U32_MAX, }; /* And the second ST derivative */ @@ -438,6 +444,8 @@ static struct pl031_vendor_data stv2_pl031 = { * remove IRQF_COND_SUSPEND */ .irqflags = IRQF_SHARED | IRQF_COND_SUSPEND, + .range_min = RTC_TIMESTAMP_BEGIN_0000, + .range_max = RTC_TIMESTAMP_END_9999, }; static const struct amba_id pl031_ids[] = { From c8ff5841a90bdd99f28f7062c99b3058005c1c32 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 01:58:09 +0100 Subject: [PATCH 329/809] rtc: pl031: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion to allow extending support after 2106 and properly supporting the STv2 range. Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20200306005809.38530-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 07dc0f264100..40d7450a1ce4 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -125,11 +125,9 @@ static int pl031_stv2_tm_to_time(struct device *dev, return -EINVAL; } else if (wday == -1) { /* wday is not provided, calculate it here */ - unsigned long time; struct rtc_time calc_tm; - rtc_tm_to_time(tm, &time); - rtc_time_to_tm(time, &calc_tm); + rtc_time64_to_tm(rtc_tm_to_time64(tm), &calc_tm); wday = calc_tm.tm_wday; } @@ -246,30 +244,25 @@ static int pl031_read_time(struct device *dev, struct rtc_time *tm) { struct pl031_local *ldata = dev_get_drvdata(dev); - rtc_time_to_tm(readl(ldata->base + RTC_DR), tm); + rtc_time64_to_tm(readl(ldata->base + RTC_DR), tm); return 0; } static int pl031_set_time(struct device *dev, struct rtc_time *tm) { - unsigned long time; struct pl031_local *ldata = dev_get_drvdata(dev); - int ret; - ret = rtc_tm_to_time(tm, &time); + writel(rtc_tm_to_time64(tm), ldata->base + RTC_LR); - if (ret == 0) - writel(time, ldata->base + RTC_LR); - - return ret; + return 0; } static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct pl031_local *ldata = dev_get_drvdata(dev); - rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time); + rtc_time64_to_tm(readl(ldata->base + RTC_MR), &alarm->time); alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI; alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI; @@ -280,16 +273,10 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct pl031_local *ldata = dev_get_drvdata(dev); - unsigned long time; - int ret; - ret = rtc_tm_to_time(&alarm->time, &time); - if (ret == 0) { - writel(time, ldata->base + RTC_MR); - pl031_alarm_irq_enable(dev, alarm->enabled); - } + writel(rtc_tm_to_time64(&alarm->time), ldata->base + RTC_MR); - return ret; + return 0; } static int pl031_remove(struct amba_device *adev) From a5965a31012f3e80105eb759fa69eded6a813a4b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:01:01 +0100 Subject: [PATCH 330/809] rtc: ab8500: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20200306010101.39517-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 8492ffed4ca6..3d60f3283f11 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -100,7 +100,7 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) secs = secs / COUNTS_PER_SEC; secs = secs + (mins * 60); - rtc_time_to_tm(secs, tm); + rtc_time64_to_tm(secs, tm); return 0; } @@ -110,7 +110,7 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; unsigned long no_secs, no_mins, secs = 0; - rtc_tm_to_time(tm, &secs); + secs = rtc_tm_to_time64(tm); no_mins = secs / 60; @@ -168,7 +168,7 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); secs = mins * 60; - rtc_time_to_tm(secs, &alarm->time); + rtc_time64_to_tm(secs, &alarm->time); return 0; } @@ -188,7 +188,7 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct rtc_time curtm; /* Get the number of seconds since 1970 */ - rtc_tm_to_time(&alarm->time, &secs); + secs = rtc_tm_to_time64(&alarm->time); /* * Check whether alarm is set less than 1min. @@ -196,7 +196,7 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON */ ab8500_rtc_read_time(dev, &curtm); /* Read current time */ - rtc_tm_to_time(&curtm, &cursec); + cursec = rtc_tm_to_time64(&curtm); if ((secs - cursec) < 59) { dev_dbg(dev, "Alarm less than 1 minute not supported\r\n"); return -EINVAL; From a04b3b965f3d5a1b0b00c2b546b30ee09ce112db Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:02:38 +0100 Subject: [PATCH 331/809] rtc: puv3: set range This RTC is a 32bit seconds counter. Link: https://lore.kernel.org/r/20200306010240.40056-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-puv3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 89ff713163dd..3029a52a501e 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -234,6 +234,7 @@ static int puv3_rtc_probe(struct platform_device *pdev) /* register RTC and exit */ rtc->ops = &puv3_rtcops; + rtc->range_max = U32_MAX; ret = rtc_register_device(rtc); if (ret) goto err_nortc; From 0155b547746fefbe2e0e7938785309d63725e1ba Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Mar 2020 02:02:39 +0100 Subject: [PATCH 332/809] rtc: puv3: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200306010240.40056-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-puv3.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 3029a52a501e..954b88d2485f 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -85,7 +85,7 @@ static int puv3_rtc_setpie(struct device *dev, int enabled) /* Time read/write */ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { - rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); + rtc_time64_to_tm(readl(RTC_RCNR), rtc_tm); dev_dbg(dev, "read time %ptRr\n", rtc_tm); @@ -94,12 +94,9 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) { - unsigned long rtc_count = 0; - dev_dbg(dev, "set time %ptRr\n", tm); - rtc_tm_to_time(tm, &rtc_count); - writel(rtc_count, RTC_RCNR); + writel(rtc_tm_to_time64(tm), RTC_RCNR); return 0; } @@ -108,7 +105,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_time *alm_tm = &alrm->time; - rtc_time_to_tm(readl(RTC_RTAR), alm_tm); + rtc_time64_to_tm(readl(RTC_RTAR), alm_tm); alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; @@ -120,12 +117,10 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_time *tm = &alrm->time; - unsigned long rtcalarm_count = 0; dev_dbg(dev, "set alarm: %d, %ptRr\n", alrm->enabled, tm); - rtc_tm_to_time(tm, &rtcalarm_count); - writel(rtcalarm_count, RTC_RTAR); + writel(rtc_tm_to_time64(tm), RTC_RTAR); puv3_rtc_setaie(dev, alrm->enabled); From ec98a87509f40324807dc179a7e3163d40709eba Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 8 Mar 2020 14:58:48 +0100 Subject: [PATCH 333/809] rtc: sun6i: Make external 32k oscillator optional Some boards, like OrangePi PC2 (H5), OrangePi Plus 2E (H3) and Tanix TX6 (H6) don't have external 32kHz oscillator. Till H6, it didn't really matter if external oscillator was enabled because HW detected error and fall back to internal one. H6 has same functionality but it's the first SoC which have "auto switch bypass" bit documented and always enabled in driver. This prevents RTC to work correctly if external crystal is not present on board. There are other side effects - all peripherals which depends on this clock also don't work (HDMI CEC for example). Make clocks property optional. If it is present, select external oscillator. If not, stay on internal. Signed-off-by: Jernej Skrabec Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20200308135849.106333-2-jernej.skrabec@siol.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 852f5f3b3592..415a20a936e4 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -250,19 +250,17 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, writel(reg, rtc->base + SUN6I_LOSC_CTRL); } - /* Switch to the external, more precise, oscillator */ - reg |= SUN6I_LOSC_CTRL_EXT_OSC; - if (rtc->data->has_losc_en) - reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN; + /* Switch to the external, more precise, oscillator, if present */ + if (of_get_property(node, "clocks", NULL)) { + reg |= SUN6I_LOSC_CTRL_EXT_OSC; + if (rtc->data->has_losc_en) + reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN; + } writel(reg, rtc->base + SUN6I_LOSC_CTRL); /* Yes, I know, this is ugly. */ sun6i_rtc = rtc; - /* Deal with old DTs */ - if (!of_get_property(node, "clocks", NULL)) - goto err; - /* Only read IOSC name from device tree if it is exported */ if (rtc->data->export_iosc) of_property_read_string_index(node, "clock-output-names", 2, @@ -279,11 +277,13 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, } parents[0] = clk_hw_get_name(rtc->int_osc); + /* If there is no external oscillator, this will be NULL and ... */ parents[1] = of_clk_get_parent_name(node, 0); rtc->hw.init = &init; init.parent_names = parents; + /* ... number of clock parents will be 1. */ init.num_parents = of_clk_get_parent_count(node) + 1; of_property_read_string_index(node, "clock-output-names", 0, &init.name); From eac1c3fc55f8744c0b2a4459f52f3761c1e588ab Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 9 Mar 2020 13:35:14 +0100 Subject: [PATCH 334/809] rtc: m48t35: remove SGI-IP27 kludge With the IOC3 MFD driver it's no longer necessary to special case SGI-IP27. Signed-off-by: Thomas Bogendoerfer Link: https://lore.kernel.org/r/20200309123514.15543-1-tsbogend@alpha.franken.de Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t35.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index e8194f1f01a8..92f19bf997b2 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -160,15 +160,10 @@ static int m48t35_probe(struct platform_device *pdev) return -ENOMEM; priv->size = resource_size(res); - /* - * kludge: remove the #ifndef after ioc3 resource - * conflicts are resolved - */ -#ifndef CONFIG_SGI_IP27 if (!devm_request_mem_region(&pdev->dev, res->start, priv->size, pdev->name)) return -EBUSY; -#endif + priv->baseaddr = res->start; priv->reg = devm_ioremap(&pdev->dev, priv->baseaddr, priv->size); if (!priv->reg) From bfb8c3b464f1fdb38b66c730e1f033902682ade6 Mon Sep 17 00:00:00 2001 From: Ran Bi Date: Wed, 26 Feb 2020 13:13:00 +0800 Subject: [PATCH 335/809] dt-bindings: rtc: add bindings for MT2712 RTC Document the binding for MT2712 RTC implemented by rtc-mt2712. Reviewed-by: Rob Herring Signed-off-by: Ran Bi Link: https://lore.kernel.org/r/20200226051303.22560-2-ran.bi@mediatek.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/rtc-mt2712.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/rtc-mt2712.txt diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt2712.txt b/Documentation/devicetree/bindings/rtc/rtc-mt2712.txt new file mode 100644 index 000000000000..c33d87e5e753 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-mt2712.txt @@ -0,0 +1,14 @@ +Device-Tree bindings for MediaTek SoC based RTC + +Required properties: +- compatible : Should be "mediatek,mt2712-rtc" : for MT2712 SoC +- reg : Specifies base physical address and size of the registers; +- interrupts : Should contain the interrupt for RTC alarm; + +Example: + +rtc: rtc@10011000 { + compatible = "mediatek,mt2712-rtc"; + reg = <0 0x10011000 0 0x1000>; + interrupts = ; +}; From 64823360a82939db212bc763443c990cbd99fa7c Mon Sep 17 00:00:00 2001 From: Ran Bi Date: Wed, 26 Feb 2020 13:13:01 +0800 Subject: [PATCH 336/809] rtc: add support for the MediaTek MT2712 RTC This add support for the MediaTek MT2712 RTC. It was SoC based RTC, but had different architecture compared with MT7622 RTC. Signed-off-by: Ran Bi Link: https://lore.kernel.org/r/20200226051303.22560-3-ran.bi@mediatek.com Link: https://lore.kernel.org/r/20200316104701.209293-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-mt2712.c | 421 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 432 insertions(+) create mode 100644 drivers/rtc/rtc-mt2712.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 777047620ec7..7d6cb60ee010 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1807,6 +1807,16 @@ config RTC_DRV_MOXART This driver can also be built as a module. If so, the module will be called rtc-moxart +config RTC_DRV_MT2712 + tristate "MediaTek MT2712 SoC based RTC" + depends on ARCH_MEDIATEK || COMPILE_TEST + help + This enables support for the real time clock built in the MediaTek + SoCs for MT2712. + + This drive can also be built as a module. If so, the module + will be called rtc-mt2712. + config RTC_DRV_MT6397 tristate "MediaTek PMIC based RTC" depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN) diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 4ac8f19fb631..6c3e93aa36dc 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o +obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o diff --git a/drivers/rtc/rtc-mt2712.c b/drivers/rtc/rtc-mt2712.c new file mode 100644 index 000000000000..62c20241426d --- /dev/null +++ b/drivers/rtc/rtc-mt2712.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Ran Bi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT2712_BBPU 0x0000 +#define MT2712_BBPU_CLRPKY BIT(4) +#define MT2712_BBPU_RELOAD BIT(5) +#define MT2712_BBPU_CBUSY BIT(6) +#define MT2712_BBPU_KEY (0x43 << 8) + +#define MT2712_IRQ_STA 0x0004 +#define MT2712_IRQ_STA_AL BIT(0) +#define MT2712_IRQ_STA_TC BIT(1) + +#define MT2712_IRQ_EN 0x0008 +#define MT2712_IRQ_EN_AL BIT(0) +#define MT2712_IRQ_EN_TC BIT(1) +#define MT2712_IRQ_EN_ONESHOT BIT(2) + +#define MT2712_CII_EN 0x000c + +#define MT2712_AL_MASK 0x0010 +#define MT2712_AL_MASK_DOW BIT(4) + +#define MT2712_TC_SEC 0x0014 +#define MT2712_TC_MIN 0x0018 +#define MT2712_TC_HOU 0x001c +#define MT2712_TC_DOM 0x0020 +#define MT2712_TC_DOW 0x0024 +#define MT2712_TC_MTH 0x0028 +#define MT2712_TC_YEA 0x002c + +#define MT2712_AL_SEC 0x0030 +#define MT2712_AL_MIN 0x0034 +#define MT2712_AL_HOU 0x0038 +#define MT2712_AL_DOM 0x003c +#define MT2712_AL_DOW 0x0040 +#define MT2712_AL_MTH 0x0044 +#define MT2712_AL_YEA 0x0048 + +#define MT2712_SEC_MASK 0x003f +#define MT2712_MIN_MASK 0x003f +#define MT2712_HOU_MASK 0x001f +#define MT2712_DOM_MASK 0x001f +#define MT2712_DOW_MASK 0x0007 +#define MT2712_MTH_MASK 0x000f +#define MT2712_YEA_MASK 0x007f + +#define MT2712_POWERKEY1 0x004c +#define MT2712_POWERKEY2 0x0050 +#define MT2712_POWERKEY1_KEY 0xa357 +#define MT2712_POWERKEY2_KEY 0x67d2 + +#define MT2712_CON0 0x005c +#define MT2712_CON1 0x0060 + +#define MT2712_PROT 0x0070 +#define MT2712_PROT_UNLOCK1 0x9136 +#define MT2712_PROT_UNLOCK2 0x586a + +#define MT2712_WRTGR 0x0078 + +#define MT2712_RTC_TIMESTAMP_END_2127 4985971199LL + +struct mt2712_rtc { + struct rtc_device *rtc; + void __iomem *base; + int irq; + u8 irq_wake_enabled; + u8 powerlost; +}; + +static inline u32 mt2712_readl(struct mt2712_rtc *mt2712_rtc, u32 reg) +{ + return readl(mt2712_rtc->base + reg); +} + +static inline void mt2712_writel(struct mt2712_rtc *mt2712_rtc, + u32 reg, u32 val) +{ + writel(val, mt2712_rtc->base + reg); +} + +static void mt2712_rtc_write_trigger(struct mt2712_rtc *mt2712_rtc) +{ + unsigned long timeout = jiffies + HZ / 10; + + mt2712_writel(mt2712_rtc, MT2712_WRTGR, 1); + while (1) { + if (!(mt2712_readl(mt2712_rtc, MT2712_BBPU) + & MT2712_BBPU_CBUSY)) + break; + + if (time_after(jiffies, timeout)) { + dev_err(&mt2712_rtc->rtc->dev, + "%s time out!\n", __func__); + break; + } + cpu_relax(); + } +} + +static void mt2712_rtc_writeif_unlock(struct mt2712_rtc *mt2712_rtc) +{ + mt2712_writel(mt2712_rtc, MT2712_PROT, MT2712_PROT_UNLOCK1); + mt2712_rtc_write_trigger(mt2712_rtc); + mt2712_writel(mt2712_rtc, MT2712_PROT, MT2712_PROT_UNLOCK2); + mt2712_rtc_write_trigger(mt2712_rtc); +} + +static irqreturn_t rtc_irq_handler_thread(int irq, void *data) +{ + struct mt2712_rtc *mt2712_rtc = data; + u16 irqsta; + + /* Clear interrupt */ + irqsta = mt2712_readl(mt2712_rtc, MT2712_IRQ_STA); + if (irqsta & MT2712_IRQ_STA_AL) { + rtc_update_irq(mt2712_rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void __mt2712_rtc_read_time(struct mt2712_rtc *mt2712_rtc, + struct rtc_time *tm, int *sec) +{ + tm->tm_sec = mt2712_readl(mt2712_rtc, MT2712_TC_SEC) + & MT2712_SEC_MASK; + tm->tm_min = mt2712_readl(mt2712_rtc, MT2712_TC_MIN) + & MT2712_MIN_MASK; + tm->tm_hour = mt2712_readl(mt2712_rtc, MT2712_TC_HOU) + & MT2712_HOU_MASK; + tm->tm_mday = mt2712_readl(mt2712_rtc, MT2712_TC_DOM) + & MT2712_DOM_MASK; + tm->tm_mon = (mt2712_readl(mt2712_rtc, MT2712_TC_MTH) - 1) + & MT2712_MTH_MASK; + tm->tm_year = (mt2712_readl(mt2712_rtc, MT2712_TC_YEA) + 100) + & MT2712_YEA_MASK; + + *sec = mt2712_readl(mt2712_rtc, MT2712_TC_SEC) & MT2712_SEC_MASK; +} + +static int mt2712_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + int sec; + + if (mt2712_rtc->powerlost) + return -EINVAL; + + do { + __mt2712_rtc_read_time(mt2712_rtc, tm, &sec); + } while (sec < tm->tm_sec); /* SEC has carried */ + + return 0; +} + +static int mt2712_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + + mt2712_writel(mt2712_rtc, MT2712_TC_SEC, tm->tm_sec & MT2712_SEC_MASK); + mt2712_writel(mt2712_rtc, MT2712_TC_MIN, tm->tm_min & MT2712_MIN_MASK); + mt2712_writel(mt2712_rtc, MT2712_TC_HOU, tm->tm_hour & MT2712_HOU_MASK); + mt2712_writel(mt2712_rtc, MT2712_TC_DOM, tm->tm_mday & MT2712_DOM_MASK); + mt2712_writel(mt2712_rtc, MT2712_TC_MTH, + (tm->tm_mon + 1) & MT2712_MTH_MASK); + mt2712_writel(mt2712_rtc, MT2712_TC_YEA, + (tm->tm_year - 100) & MT2712_YEA_MASK); + + mt2712_rtc_write_trigger(mt2712_rtc); + + if (mt2712_rtc->powerlost) + mt2712_rtc->powerlost = false; + + return 0; +} + +static int mt2712_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alm->time; + u16 irqen; + + irqen = mt2712_readl(mt2712_rtc, MT2712_IRQ_EN); + alm->enabled = !!(irqen & MT2712_IRQ_EN_AL); + + tm->tm_sec = mt2712_readl(mt2712_rtc, MT2712_AL_SEC) & MT2712_SEC_MASK; + tm->tm_min = mt2712_readl(mt2712_rtc, MT2712_AL_MIN) & MT2712_MIN_MASK; + tm->tm_hour = mt2712_readl(mt2712_rtc, MT2712_AL_HOU) & MT2712_HOU_MASK; + tm->tm_mday = mt2712_readl(mt2712_rtc, MT2712_AL_DOM) & MT2712_DOM_MASK; + tm->tm_mon = (mt2712_readl(mt2712_rtc, MT2712_AL_MTH) - 1) + & MT2712_MTH_MASK; + tm->tm_year = (mt2712_readl(mt2712_rtc, MT2712_AL_YEA) + 100) + & MT2712_YEA_MASK; + + return 0; +} + +static int mt2712_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + u16 irqen; + + irqen = mt2712_readl(mt2712_rtc, MT2712_IRQ_EN); + if (enabled) + irqen |= MT2712_IRQ_EN_AL; + else + irqen &= ~MT2712_IRQ_EN_AL; + mt2712_writel(mt2712_rtc, MT2712_IRQ_EN, irqen); + mt2712_rtc_write_trigger(mt2712_rtc); + + return 0; +} + +static int mt2712_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alm->time; + + dev_dbg(&mt2712_rtc->rtc->dev, "set al time: %ptR, alm en: %d\n", + tm, alm->enabled); + + mt2712_writel(mt2712_rtc, MT2712_AL_SEC, + (mt2712_readl(mt2712_rtc, MT2712_AL_SEC) + & ~(MT2712_SEC_MASK)) | (tm->tm_sec & MT2712_SEC_MASK)); + mt2712_writel(mt2712_rtc, MT2712_AL_MIN, + (mt2712_readl(mt2712_rtc, MT2712_AL_MIN) + & ~(MT2712_MIN_MASK)) | (tm->tm_min & MT2712_MIN_MASK)); + mt2712_writel(mt2712_rtc, MT2712_AL_HOU, + (mt2712_readl(mt2712_rtc, MT2712_AL_HOU) + & ~(MT2712_HOU_MASK)) | (tm->tm_hour & MT2712_HOU_MASK)); + mt2712_writel(mt2712_rtc, MT2712_AL_DOM, + (mt2712_readl(mt2712_rtc, MT2712_AL_DOM) + & ~(MT2712_DOM_MASK)) | (tm->tm_mday & MT2712_DOM_MASK)); + mt2712_writel(mt2712_rtc, MT2712_AL_MTH, + (mt2712_readl(mt2712_rtc, MT2712_AL_MTH) + & ~(MT2712_MTH_MASK)) + | ((tm->tm_mon + 1) & MT2712_MTH_MASK)); + mt2712_writel(mt2712_rtc, MT2712_AL_YEA, + (mt2712_readl(mt2712_rtc, MT2712_AL_YEA) + & ~(MT2712_YEA_MASK)) + | ((tm->tm_year - 100) & MT2712_YEA_MASK)); + + /* mask day of week */ + mt2712_writel(mt2712_rtc, MT2712_AL_MASK, MT2712_AL_MASK_DOW); + mt2712_rtc_write_trigger(mt2712_rtc); + + mt2712_rtc_alarm_irq_enable(dev, alm->enabled); + + return 0; +} + +/* Init RTC register */ +static void mt2712_rtc_hw_init(struct mt2712_rtc *mt2712_rtc) +{ + u32 p1, p2; + + mt2712_writel(mt2712_rtc, MT2712_BBPU, + MT2712_BBPU_KEY | MT2712_BBPU_RELOAD); + + mt2712_writel(mt2712_rtc, MT2712_CII_EN, 0); + mt2712_writel(mt2712_rtc, MT2712_AL_MASK, 0); + /* necessary before set MT2712_POWERKEY */ + mt2712_writel(mt2712_rtc, MT2712_CON0, 0x4848); + mt2712_writel(mt2712_rtc, MT2712_CON1, 0x0048); + + mt2712_rtc_write_trigger(mt2712_rtc); + + p1 = mt2712_readl(mt2712_rtc, MT2712_POWERKEY1); + p2 = mt2712_readl(mt2712_rtc, MT2712_POWERKEY2); + if (p1 != MT2712_POWERKEY1_KEY || p2 != MT2712_POWERKEY2_KEY) { + mt2712_rtc->powerlost = true; + dev_dbg(&mt2712_rtc->rtc->dev, + "powerkey not set (lost power)\n"); + } else { + mt2712_rtc->powerlost = false; + } + + /* RTC need POWERKEY1/2 match, then goto normal work mode */ + mt2712_writel(mt2712_rtc, MT2712_POWERKEY1, MT2712_POWERKEY1_KEY); + mt2712_writel(mt2712_rtc, MT2712_POWERKEY2, MT2712_POWERKEY2_KEY); + mt2712_rtc_write_trigger(mt2712_rtc); + + mt2712_rtc_writeif_unlock(mt2712_rtc); +} + +static const struct rtc_class_ops mt2712_rtc_ops = { + .read_time = mt2712_rtc_read_time, + .set_time = mt2712_rtc_set_time, + .read_alarm = mt2712_rtc_read_alarm, + .set_alarm = mt2712_rtc_set_alarm, + .alarm_irq_enable = mt2712_rtc_alarm_irq_enable, +}; + +static int mt2712_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mt2712_rtc *mt2712_rtc; + int ret; + + mt2712_rtc = devm_kzalloc(&pdev->dev, + sizeof(struct mt2712_rtc), GFP_KERNEL); + if (!mt2712_rtc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mt2712_rtc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mt2712_rtc->base)) + return PTR_ERR(mt2712_rtc->base); + + /* rtc hw init */ + mt2712_rtc_hw_init(mt2712_rtc); + + mt2712_rtc->irq = platform_get_irq(pdev, 0); + if (mt2712_rtc->irq < 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return mt2712_rtc->irq; + } + + platform_set_drvdata(pdev, mt2712_rtc); + + mt2712_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(mt2712_rtc->rtc)) + return PTR_ERR(mt2712_rtc->rtc); + + ret = devm_request_threaded_irq(&pdev->dev, mt2712_rtc->irq, NULL, + rtc_irq_handler_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + dev_name(&mt2712_rtc->rtc->dev), + mt2712_rtc); + if (ret) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + mt2712_rtc->irq, ret); + return ret; + } + + device_init_wakeup(&pdev->dev, true); + + mt2712_rtc->rtc->ops = &mt2712_rtc_ops; + mt2712_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + mt2712_rtc->rtc->range_max = MT2712_RTC_TIMESTAMP_END_2127; + + ret = rtc_register_device(mt2712_rtc->rtc); + if (ret) { + dev_err(&pdev->dev, "register rtc device failed\n"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mt2712_rtc_suspend(struct device *dev) +{ + int wake_status = 0; + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) { + wake_status = enable_irq_wake(mt2712_rtc->irq); + if (!wake_status) + mt2712_rtc->irq_wake_enabled = true; + } + + return 0; +} + +static int mt2712_rtc_resume(struct device *dev) +{ + int wake_status = 0; + struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev) && mt2712_rtc->irq_wake_enabled) { + wake_status = disable_irq_wake(mt2712_rtc->irq); + if (!wake_status) + mt2712_rtc->irq_wake_enabled = false; + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(mt2712_pm_ops, mt2712_rtc_suspend, + mt2712_rtc_resume); +#endif + +static const struct of_device_id mt2712_rtc_of_match[] = { + { .compatible = "mediatek,mt2712-rtc", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, mt2712_rtc_of_match); + +static struct platform_driver mt2712_rtc_driver = { + .driver = { + .name = "mt2712-rtc", + .of_match_table = mt2712_rtc_of_match, + .pm = &mt2712_pm_ops, + }, + .probe = mt2712_rtc_probe, +}; + +module_platform_driver(mt2712_rtc_driver); + +MODULE_DESCRIPTION("MediaTek MT2712 SoC based RTC Driver"); +MODULE_AUTHOR("Ran Bi "); +MODULE_LICENSE("GPL"); From 21cbe810941501098e30c28df5cfa947ef04ee79 Mon Sep 17 00:00:00 2001 From: Ran Bi Date: Wed, 26 Feb 2020 13:13:03 +0800 Subject: [PATCH 337/809] MAINTAINERS: add MT2712 RTC files This patch add MT2712 RTC related files to MAINTAINERS file. Signed-off-by: Ran Bi Link: https://lore.kernel.org/r/20200226051303.22560-5-ran.bi@mediatek.com Signed-off-by: Alexandre Belloni --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 38fe2f3f7b6f..57549356e731 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1995,7 +1995,9 @@ M: Sean Wang L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/rtc/rtc-mt2712.txt F: Documentation/devicetree/bindings/rtc/rtc-mt7622.txt +F: drivers/rtc/rtc-mt2712.c F: drivers/rtc/rtc-mt6397.c F: drivers/rtc/rtc-mt7622.c From 7863bd076b990f57076f2123337b67b5d5ccd190 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 13 Mar 2020 22:30:49 +0800 Subject: [PATCH 338/809] rtc: snvs: Use devm_add_action_or_reset() for calls to clk_disable_unprepare() Use devm_add_action_or_reset() for calls to clk_disable_unprepare(), which can simplify the error handling. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1584109849-21402-1-git-send-email-Anson.Huang@nxp.com Link: https://lore.kernel.org/r/1584233264-26025-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-snvs.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 7630089a113c..35ee08aa7584 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -263,6 +263,12 @@ static const struct regmap_config snvs_rtc_config = { .reg_stride = 4, }; +static void snvs_rtc_action(void *data) +{ + if (data) + clk_disable_unprepare(data); +} + static int snvs_rtc_probe(struct platform_device *pdev) { struct snvs_rtc_data *data; @@ -313,6 +319,10 @@ static int snvs_rtc_probe(struct platform_device *pdev) } } + ret = devm_add_action_or_reset(&pdev->dev, snvs_rtc_action, data->clk); + if (ret) + return ret; + platform_set_drvdata(pdev, data); /* Initialize glitch detect */ @@ -325,7 +335,7 @@ static int snvs_rtc_probe(struct platform_device *pdev) ret = snvs_rtc_enable(data, true); if (ret) { dev_err(&pdev->dev, "failed to enable rtc %d\n", ret); - goto error_rtc_device_register; + return ret; } device_init_wakeup(&pdev->dev, true); @@ -338,24 +348,13 @@ static int snvs_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request irq %d: %d\n", data->irq, ret); - goto error_rtc_device_register; + return ret; } data->rtc->ops = &snvs_rtc_ops; data->rtc->range_max = U32_MAX; - ret = rtc_register_device(data->rtc); - if (ret) { - dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); - goto error_rtc_device_register; - } - return 0; - -error_rtc_device_register: - if (data->clk) - clk_disable_unprepare(data->clk); - - return ret; + return rtc_register_device(data->rtc); } static int __maybe_unused snvs_rtc_suspend_noirq(struct device *dev) From 9cf4789e6e4673d0b2c96fa6bb0c35e81b43111a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:51 +0100 Subject: [PATCH 339/809] rtc: 88pm860x: fix possible race condition The RTC IRQ is requested before the struct rtc_device is allocated, this may lead to a NULL pointer dereference in the IRQ handler. To fix this issue, allocating the rtc_device struct before requesting the RTC IRQ using devm_rtc_allocate_device, and use rtc_register_device to register the RTC device. Also remove the unnecessary error message as the core already prints the info. Link: https://lore.kernel.org/r/20200311223956.51352-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 4743b16a8d84..1526402e126b 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -336,6 +336,10 @@ static int pm860x_rtc_probe(struct platform_device *pdev) info->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, info); + info->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(info->rtc_dev)) + return PTR_ERR(info->rtc_dev); + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, rtc_update_handler, IRQF_ONESHOT, "rtc", info); @@ -377,13 +381,11 @@ static int pm860x_rtc_probe(struct platform_device *pdev) } } - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm860x-rtc", - &pm860x_rtc_ops, THIS_MODULE); - ret = PTR_ERR(info->rtc_dev); - if (IS_ERR(info->rtc_dev)) { - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + info->rtc_dev->ops = &pm860x_rtc_ops; + + ret = rtc_register_device(info->rtc_dev); + if (ret) return ret; - } /* * enable internal XO instead of internal 3.25MHz clock since it can From b773f2a97fc5d53c5e57cf37fd4029026d38ba55 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:52 +0100 Subject: [PATCH 340/809] rtc: 88pm860x: stop setting a default time It doesn't make sense to set the RTC to a default value at probe time. Let the core handle invalid date and time. Link: https://lore.kernel.org/r/20200311223956.51352-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 1526402e126b..d6aca28905e3 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -360,19 +360,6 @@ static int pm860x_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to read initial time.\n"); return ret; } - if ((tm.tm_year < 70) || (tm.tm_year > 138)) { - tm.tm_year = 70; - tm.tm_mon = 0; - tm.tm_mday = 1; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - ret = pm860x_rtc_set_time(&pdev->dev, &tm); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to set initial time.\n"); - return ret; - } - } rtc_tm_to_time(&tm, &ticks); if (pm860x_rtc_dt_init(pdev, info)) { if (pdata && pdata->sync) { From 1c9fe6d6d2752cbca0b006355d0557cdf355b559 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:53 +0100 Subject: [PATCH 341/809] rtc: 88pm860x: stop calling unused callback pdata->sync is not defined by any platform, stop calling it. Link: https://lore.kernel.org/r/20200311223956.51352-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index d6aca28905e3..0abf2b194938 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -28,7 +28,6 @@ struct pm860x_rtc_info { int irq; int vrtc; - int (*sync)(unsigned int ticks); }; #define REG_VRTC_MEAS1 0x7D @@ -155,8 +154,6 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF); pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF); - if (info->sync) - info->sync(ticks); return 0; } @@ -317,8 +314,6 @@ static int pm860x_rtc_probe(struct platform_device *pdev) struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_rtc_pdata *pdata = NULL; struct pm860x_rtc_info *info; - struct rtc_time tm; - unsigned long ticks = 0; int ret; pdata = dev_get_platdata(&pdev->dev); @@ -355,18 +350,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev) pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA); pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA); - ret = pm860x_rtc_read_time(&pdev->dev, &tm); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to read initial time.\n"); - return ret; - } - rtc_tm_to_time(&tm, &ticks); - if (pm860x_rtc_dt_init(pdev, info)) { - if (pdata && pdata->sync) { - pdata->sync(ticks); - info->sync = pdata->sync; - } - } + pm860x_rtc_dt_init(pdev, info); info->rtc_dev->ops = &pm860x_rtc_ops; From a3e4937112cea362ebd813f9bf5e1a6b75cade1e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:54 +0100 Subject: [PATCH 342/809] rtc: 88pm860x: set range The 88pm860x RTC is a 32bit read only seconds counter with a 32bit offset. Link: https://lore.kernel.org/r/20200311223956.51352-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 0abf2b194938..f5933a08454c 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -353,6 +353,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev) pm860x_rtc_dt_init(pdev, info); info->rtc_dev->ops = &pm860x_rtc_ops; + info->rtc_dev->range_max = U32_MAX; ret = rtc_register_device(info->rtc_dev); if (ret) From 3b45cc522e5bb68ff4b0572b517f3aa0789a26c2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:55 +0100 Subject: [PATCH 343/809] rtc: 88pm860x: stop mangling alarm time The RTC core always passes a valid alarm time there is no need to modify it. Link: https://lore.kernel.org/r/20200311223956.51352-5-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 41 +------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index f5933a08454c..e0b18227514b 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -75,33 +75,6 @@ static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -/* - * Calculate the next alarm time given the requested alarm time mask - * and the current time. - */ -static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, - struct rtc_time *alrm) -{ - unsigned long next_time; - unsigned long now_time; - - next->tm_year = now->tm_year; - next->tm_mon = now->tm_mon; - next->tm_mday = now->tm_mday; - next->tm_hour = alrm->tm_hour; - next->tm_min = alrm->tm_min; - next->tm_sec = alrm->tm_sec; - - rtc_tm_to_time(now, &now_time); - rtc_tm_to_time(next, &next_time); - - if (next_time < now_time) { - /* Advance one day */ - next_time += 60 * 60 * 24; - rtc_time_to_tm(next_time, next); - } -} - static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pm860x_rtc_info *info = dev_get_drvdata(dev); @@ -187,7 +160,6 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pm860x_rtc_info *info = dev_get_drvdata(dev); - struct rtc_time now_tm, alarm_tm; unsigned long ticks, base, data; unsigned char buf[8]; int mask; @@ -200,18 +172,7 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; - /* load 32-bit read-only counter */ - pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | - (buf[1] << 8) | buf[0]; - ticks = base + data; - dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", - base, data, ticks); - - rtc_time_to_tm(ticks, &now_tm); - rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); - /* get new ticks for alarm in 24 hours */ - rtc_tm_to_time(&alarm_tm, &ticks); + rtc_tm_to_time(&alrm->time, &ticks); data = ticks - base; buf[0] = data & 0xff; From b2a2aa63f9f1b87b0e6cac0eead3962bb09ee16c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 11 Mar 2020 23:39:56 +0100 Subject: [PATCH 344/809] rtc: 88pm860x: switch to rtc_time64_to_tm/rtc_tm_to_time64 Call the 64bit versions of rtc_tm time conversion. Link: https://lore.kernel.org/r/20200311223956.51352-6-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index e0b18227514b..88bda3e072d8 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -95,7 +95,7 @@ static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); - rtc_time_to_tm(ticks, tm); + rtc_time64_to_tm(ticks, tm); return 0; } @@ -112,7 +112,7 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) 1900 + tm->tm_year); return -EINVAL; } - rtc_tm_to_time(tm, &ticks); + ticks = rtc_tm_to_time64(tm); /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); @@ -150,7 +150,7 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); - rtc_time_to_tm(ticks, &alrm->time); + rtc_time64_to_tm(ticks, &alrm->time); ret = pm860x_reg_read(info->i2c, PM8607_RTC1); alrm->enabled = (ret & ALARM_EN) ? 1 : 0; alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0; @@ -172,7 +172,7 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; - rtc_tm_to_time(&alrm->time, &ticks); + ticks = rtc_tm_to_time64(&alrm->time); data = ticks - base; buf[0] = data & 0xff; From ccf1441db9ca84fb2803a361964a0ffc4165c2d8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 16 Mar 2020 11:25:37 +0100 Subject: [PATCH 345/809] rtc: 88pm860x: remove platform data support There is no users of the rtc platform data left, remove its support. Link: https://lore.kernel.org/r/20200316102537.180398-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm860x.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 88bda3e072d8..cc9b14ef90f1 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -267,18 +267,15 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev, return 0; } #else -#define pm860x_rtc_dt_init(x, y) (-1) +#define pm860x_rtc_dt_init(x, y) do { } while (0) #endif static int pm860x_rtc_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_rtc_pdata *pdata = NULL; struct pm860x_rtc_info *info; int ret; - pdata = dev_get_platdata(&pdev->dev); - info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info), GFP_KERNEL); if (!info) @@ -328,12 +325,6 @@ static int pm860x_rtc_probe(struct platform_device *pdev) #ifdef VRTC_CALIBRATION /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ - if (pm860x_rtc_dt_init(pdev, info)) { - if (pdata && pdata->vrtc) - info->vrtc = pdata->vrtc & 0x3; - else - info->vrtc = 1; - } pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); /* calibrate VRTC */ From c2d0699c629d30dde3329003baac3b94f1d717e6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Mar 2020 13:04:41 -0500 Subject: [PATCH 346/809] ext2: xattr.h: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Link: https://lore.kernel.org/r/20200309180441.GA2992@embeddedor Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jan Kara --- fs/ext2/xattr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index cee888cdc235..16272e6ddcf4 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -39,7 +39,7 @@ struct ext2_xattr_entry { __le32 e_value_block; /* disk block attribute is stored on (n/i) */ __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ + char e_name[]; /* attribute name */ }; #define EXT2_XATTR_PAD_BITS 2 From 3fc131663cec7ca8e05bf25d99cecc2ab56bc50d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Mar 2020 15:27:15 -0500 Subject: [PATCH 347/809] udf: udf_sb.h: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Link: https://lore.kernel.org/r/20200309202715.GA9428@embeddedor Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jan Kara --- fs/udf/udf_sb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 3d83be54c474..758efe557a19 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -83,7 +83,7 @@ struct udf_virtual_data { struct udf_bitmap { __u32 s_extPosition; int s_nr_groups; - struct buffer_head *s_block_bitmap[0]; + struct buffer_head *s_block_bitmap[]; }; struct udf_part_map { From 7627d7dc79a8edd4b8f946a66002ea4205203112 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Wed, 19 Feb 2020 15:52:15 -0500 Subject: [PATCH 348/809] nfsd: set the server_scope during service startup Currently, nfsd4_encode_exchange_id() encodes the utsname nodename string in the server_scope field. In a multi-host container environemnt, if an nfsd container is restarted on a different host than it was originally running on, clients will see a server_scope mismatch and will not attempt to reclaim opens. Instead, set the server_scope while we're in a process context during service startup, so we get the utsname nodename of the current process and store that in nfsd_net. Signed-off-by: Scott Mayhew [bfields: fix up major_id too] Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- fs/nfsd/netns.h | 2 ++ fs/nfsd/nfs4xdr.c | 9 +++++---- fs/nfsd/nfssvc.c | 3 +++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 2baf32311e00..09aa545825bd 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -172,6 +172,8 @@ struct nfsd_net { unsigned int longest_chain_cachesize; struct shrinker nfsd_reply_cache_shrinker; + /* utsname taken from the the process that starts the server */ + char nfsd_name[UNX_MAXNODENAME+1]; }; /* Simple check to find out if a given net was properly initialized */ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9761512674a0..ad38aed6f5c2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4005,11 +4005,12 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, int major_id_sz; int server_scope_sz; uint64_t minor_id = 0; + struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id); - major_id = utsname()->nodename; - major_id_sz = strlen(major_id); - server_scope = utsname()->nodename; - server_scope_sz = strlen(server_scope); + major_id = nn->nfsd_name; + major_id_sz = strlen(nn->nfsd_name); + server_scope = nn->nfsd_name; + server_scope_sz = strlen(nn->nfsd_name); p = xdr_reserve_space(xdr, 8 /* eir_clientid */ + diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 3b77b904212d..ca9fd348548b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -749,6 +749,9 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) if (nrservs == 0 && nn->nfsd_serv == NULL) goto out; + strlcpy(nn->nfsd_name, utsname()->nodename, + sizeof(nn->nfsd_name)); + error = nfsd_create_serv(net); if (error) goto out; From 469aef23aa4e49d5191050410a1422117db03e11 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 28 Feb 2020 07:23:23 -0600 Subject: [PATCH 349/809] sunrpc: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 1afe38eb33f7..7f0a83451bc0 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -380,7 +380,7 @@ struct svc_deferred_req { struct cache_deferred_req handle; size_t xprt_hlen; int argslen; - __be32 args[0]; + __be32 args[]; }; struct svc_process_info { From 51cae673d036a32fe5cca9ec61765aa09e322c59 Mon Sep 17 00:00:00 2001 From: Amol Grover Date: Wed, 19 Feb 2020 15:05:05 +0530 Subject: [PATCH 350/809] sunrpc: Pass lockdep expression to RCU lists detail->hash_table[] is traversed using hlist_for_each_entry_rcu outside an RCU read-side critical section but under the protection of detail->hash_lock. Hence, add corresponding lockdep expression to silence false-positive warnings, and harden RCU lists. Signed-off-by: Amol Grover Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- net/sunrpc/cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index bd843a81afa0..8a8e3528293c 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -113,7 +113,8 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail, spin_lock(&detail->hash_lock); /* check if entry appeared while we slept */ - hlist_for_each_entry_rcu(tmp, head, cache_list) { + hlist_for_each_entry_rcu(tmp, head, cache_list, + lockdep_is_held(&detail->hash_lock)) { if (detail->match(tmp, key)) { if (cache_is_expired(detail, tmp)) { sunrpc_begin_cache_remove_entry(tmp, detail); From c0fb23f867b632293500d7900e0288cf17bfcb1a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 17 Feb 2020 14:05:00 -0600 Subject: [PATCH 351/809] svcrdma: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 48fe3b16b0d9..003610ce00bc 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -41,7 +41,7 @@ struct svc_rdma_rw_ctxt { struct rdma_rw_ctx rw_ctx; int rw_nents; struct sg_table rw_sg_table; - struct scatterlist rw_first_sgl[0]; + struct scatterlist rw_first_sgl[]; }; static inline struct svc_rdma_rw_ctxt * From 36a8049181d590939a793e55105bb5921ec8c8b8 Mon Sep 17 00:00:00 2001 From: Madhuparna Bhowmik Date: Thu, 13 Feb 2020 20:33:31 +0530 Subject: [PATCH 352/809] fs: nfsd: nfs4state.c: Use built-in RCU list checking list_for_each_entry_rcu() has built-in RCU and lock checking. Pass cond argument to list_for_each_entry_rcu() to silence false lockdep warning when CONFIG_PROVE_RCU_LIST is enabled by default. Signed-off-by: Madhuparna Bhowmik Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 65cfe9ab47be..c1f347bbf8f4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4343,7 +4343,8 @@ find_file_locked(struct knfsd_fh *fh, unsigned int hashval) { struct nfs4_file *fp; - hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { + hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, + lockdep_is_held(&state_lock)) { if (fh_match(&fp->fi_fhandle, fh)) { if (refcount_inc_not_zero(&fp->fi_ref)) return fp; From 057a2274357786c637093866c6668d5ff048436f Mon Sep 17 00:00:00 2001 From: Madhuparna Bhowmik Date: Thu, 13 Feb 2020 20:33:59 +0530 Subject: [PATCH 353/809] fs: nfsd: fileache.c: Use built-in RCU list checking list_for_each_entry_rcu() has built-in RCU and lock checking. Pass cond argument to list_for_each_entry_rcu() to silence false lockdep warning when CONFIG_PROVE_RCU_LIST is enabled by default. Signed-off-by: Madhuparna Bhowmik Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- fs/nfsd/filecache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index 22e77ede9f14..82198d747c4c 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -890,7 +890,7 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, unsigned char need = may_flags & NFSD_FILE_MAY_MASK; hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, - nf_node) { + nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) { if ((need & nf->nf_may) != need) continue; if (nf->nf_inode != inode) From 412055398b9e67e07347a936fc4a6adddabe9cf4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 14:45:53 -0500 Subject: [PATCH 354/809] nfsd: Fix NFSv4 READ on RDMA when using readv svcrdma expects that the payload falls precisely into the xdr_buf page vector. This does not seem to be the case for nfsd4_encode_readv(). This code is called only when fops->splice_read is missing or when RQ_SPLICE_OK is clear, so it's not a noticeable problem in many common cases. Add new transport method: ->xpo_read_payload so that when a READ payload does not fit exactly in rq_res's page vector, the XDR encoder can inform the RPC transport exactly where that payload is, without the payload's XDR pad. That way, when a Write chunk is present, the transport knows what byte range in the Reply message is supposed to be matched with the chunk. Note that the Linux NFS server implementation of NFS/RDMA can currently handle only one Write chunk per RPC-over-RDMA message. This simplifies the implementation of this fix. Fixes: b04209806384 ("nfsd4: allow exotic read compounds") Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=198053 Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 20 ++++++------ include/linux/sunrpc/svc.h | 3 ++ include/linux/sunrpc/svc_rdma.h | 8 ++++- include/linux/sunrpc/svc_xprt.h | 2 ++ net/sunrpc/svc.c | 16 ++++++++++ net/sunrpc/svcsock.c | 8 +++++ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 1 + net/sunrpc/xprtrdma/svc_rdma_rw.c | 30 +++++++++++------- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 40 +++++++++++++++++++++++- net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + 10 files changed, 106 insertions(+), 23 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ad38aed6f5c2..eedb62c411a5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3594,17 +3594,17 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, u32 zzz = 0; int pad; + /* + * svcrdma requires every READ payload to start somewhere + * in xdr->pages. + */ + if (xdr->iov == xdr->buf->head) { + xdr->iov = NULL; + xdr->end = xdr->p; + } + len = maxcount; v = 0; - - thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p)); - p = xdr_reserve_space(xdr, (thislen+3)&~3); - WARN_ON_ONCE(!p); - resp->rqstp->rq_vec[v].iov_base = p; - resp->rqstp->rq_vec[v].iov_len = thislen; - v++; - len -= thislen; - while (len) { thislen = min_t(long, len, PAGE_SIZE); p = xdr_reserve_space(xdr, (thislen+3)&~3); @@ -3623,6 +3623,8 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, read->rd_length = maxcount; if (nfserr) return nfserr; + if (svc_encode_read_payload(resp->rqstp, starting_len + 8, maxcount)) + return nfserr_io; xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); tmp = htonl(eof); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 7f0a83451bc0..fd390894a584 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -517,6 +517,9 @@ void svc_wake_up(struct svc_serv *); void svc_reserve(struct svc_rqst *rqstp, int space); struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); char * svc_print_addr(struct svc_rqst *, char *, size_t); +int svc_encode_read_payload(struct svc_rqst *rqstp, + unsigned int offset, + unsigned int length); unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct page **pages, struct kvec *first, size_t total); diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index 40f65888dd38..04e4a34d1c6a 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -137,6 +137,8 @@ struct svc_rdma_recv_ctxt { unsigned int rc_page_count; unsigned int rc_hdr_count; u32 rc_inv_rkey; + unsigned int rc_read_payload_offset; + unsigned int rc_read_payload_length; struct page *rc_pages[RPCSVC_MAXPAGES]; }; @@ -170,7 +172,9 @@ extern int svc_rdma_recv_read_chunk(struct svcxprt_rdma *rdma, struct svc_rqst *rqstp, struct svc_rdma_recv_ctxt *head, __be32 *p); extern int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, - __be32 *wr_ch, struct xdr_buf *xdr); + __be32 *wr_ch, struct xdr_buf *xdr, + unsigned int offset, + unsigned long length); extern int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, __be32 *rp_ch, bool writelist, struct xdr_buf *xdr); @@ -189,6 +193,8 @@ extern int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt, struct xdr_buf *xdr, __be32 *wr_lst); extern int svc_rdma_sendto(struct svc_rqst *); +extern int svc_rdma_read_payload(struct svc_rqst *rqstp, unsigned int offset, + unsigned int length); /* svc_rdma_transport.c */ extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *); diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index ea6f46be9cb7..9e1e046de176 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -21,6 +21,8 @@ struct svc_xprt_ops { int (*xpo_has_wspace)(struct svc_xprt *); int (*xpo_recvfrom)(struct svc_rqst *); int (*xpo_sendto)(struct svc_rqst *); + int (*xpo_read_payload)(struct svc_rqst *, unsigned int, + unsigned int); void (*xpo_release_rqst)(struct svc_rqst *); void (*xpo_detach)(struct svc_xprt *); void (*xpo_free)(struct svc_xprt *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 187dd4e73d64..18676d36f490 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1636,6 +1636,22 @@ u32 svc_max_payload(const struct svc_rqst *rqstp) } EXPORT_SYMBOL_GPL(svc_max_payload); +/** + * svc_encode_read_payload - mark a range of bytes as a READ payload + * @rqstp: svc_rqst to operate on + * @offset: payload's byte offset in rqstp->rq_res + * @length: size of payload, in bytes + * + * Returns zero on success, or a negative errno if a permanent + * error occurred. + */ +int svc_encode_read_payload(struct svc_rqst *rqstp, unsigned int offset, + unsigned int length) +{ + return rqstp->rq_xprt->xpt_ops->xpo_read_payload(rqstp, offset, length); +} +EXPORT_SYMBOL_GPL(svc_encode_read_payload); + /** * svc_fill_write_vector - Construct data argument for VFS write call * @rqstp: svc_rqst to operate on diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2934dd711715..758ab10690de 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -279,6 +279,12 @@ out: return len; } +static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset, + unsigned int length) +{ + return 0; +} + /* * Report socket names for nfsdfs */ @@ -653,6 +659,7 @@ static const struct svc_xprt_ops svc_udp_ops = { .xpo_create = svc_udp_create, .xpo_recvfrom = svc_udp_recvfrom, .xpo_sendto = svc_udp_sendto, + .xpo_read_payload = svc_sock_read_payload, .xpo_release_rqst = svc_release_udp_skb, .xpo_detach = svc_sock_detach, .xpo_free = svc_sock_free, @@ -1171,6 +1178,7 @@ static const struct svc_xprt_ops svc_tcp_ops = { .xpo_create = svc_tcp_create, .xpo_recvfrom = svc_tcp_recvfrom, .xpo_sendto = svc_tcp_sendto, + .xpo_read_payload = svc_sock_read_payload, .xpo_release_rqst = svc_release_skb, .xpo_detach = svc_tcp_sock_detach, .xpo_free = svc_sock_free, diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 96bccd398469..71127d898562 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -193,6 +193,7 @@ svc_rdma_recv_ctxt_get(struct svcxprt_rdma *rdma) out: ctxt->rc_page_count = 0; + ctxt->rc_read_payload_length = 0; return ctxt; out_empty: diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 003610ce00bc..927f98995356 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -482,18 +482,19 @@ static int svc_rdma_send_xdr_kvec(struct svc_rdma_write_info *info, vec->iov_len); } -/* Send an xdr_buf's page list by itself. A Write chunk is - * just the page list. a Reply chunk is the head, page list, - * and tail. This function is shared between the two types - * of chunk. +/* Send an xdr_buf's page list by itself. A Write chunk is just + * the page list. A Reply chunk is @xdr's head, page list, and + * tail. This function is shared between the two types of chunk. */ static int svc_rdma_send_xdr_pagelist(struct svc_rdma_write_info *info, - struct xdr_buf *xdr) + struct xdr_buf *xdr, + unsigned int offset, + unsigned long length) { info->wi_xdr = xdr; - info->wi_next_off = 0; + info->wi_next_off = offset - xdr->head[0].iov_len; return svc_rdma_build_writes(info, svc_rdma_pagelist_to_sg, - xdr->page_len); + length); } /** @@ -501,6 +502,8 @@ static int svc_rdma_send_xdr_pagelist(struct svc_rdma_write_info *info, * @rdma: controlling RDMA transport * @wr_ch: Write chunk provided by client * @xdr: xdr_buf containing the data payload + * @offset: payload's byte offset in @xdr + * @length: size of payload, in bytes * * Returns a non-negative number of bytes the chunk consumed, or * %-E2BIG if the payload was larger than the Write chunk, @@ -510,19 +513,20 @@ static int svc_rdma_send_xdr_pagelist(struct svc_rdma_write_info *info, * %-EIO if rdma_rw initialization failed (DMA mapping, etc). */ int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, __be32 *wr_ch, - struct xdr_buf *xdr) + struct xdr_buf *xdr, + unsigned int offset, unsigned long length) { struct svc_rdma_write_info *info; int ret; - if (!xdr->page_len) + if (!length) return 0; info = svc_rdma_write_info_alloc(rdma, wr_ch); if (!info) return -ENOMEM; - ret = svc_rdma_send_xdr_pagelist(info, xdr); + ret = svc_rdma_send_xdr_pagelist(info, xdr, offset, length); if (ret < 0) goto out_err; @@ -531,7 +535,7 @@ int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, __be32 *wr_ch, goto out_err; trace_svcrdma_encode_write(xdr->page_len); - return xdr->page_len; + return length; out_err: svc_rdma_write_info_free(info); @@ -571,7 +575,9 @@ int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, __be32 *rp_ch, * client did not provide Write chunks. */ if (!writelist && xdr->page_len) { - ret = svc_rdma_send_xdr_pagelist(info, xdr); + ret = svc_rdma_send_xdr_pagelist(info, xdr, + xdr->head[0].iov_len, + xdr->page_len); if (ret < 0) goto out_err; consumed += xdr->page_len; diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index f3f108090aa4..a11983c2056f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -858,7 +858,18 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) if (wr_lst) { /* XXX: Presume the client sent only one Write chunk */ - ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr); + unsigned long offset; + unsigned int length; + + if (rctxt->rc_read_payload_length) { + offset = rctxt->rc_read_payload_offset; + length = rctxt->rc_read_payload_length; + } else { + offset = xdr->head[0].iov_len; + length = xdr->page_len; + } + ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr, offset, + length); if (ret < 0) goto err2; svc_rdma_xdr_encode_write_list(rdma_resp, wr_lst, ret); @@ -900,3 +911,30 @@ out: ret = -ENOTCONN; goto out; } + +/** + * svc_rdma_read_payload - special processing for a READ payload + * @rqstp: svc_rqst to operate on + * @offset: payload's byte offset in @xdr + * @length: size of payload, in bytes + * + * Returns zero on success. + * + * For the moment, just record the xdr_buf location of the READ + * payload. svc_rdma_sendto will use that location later when + * we actually send the payload. + */ +int svc_rdma_read_payload(struct svc_rqst *rqstp, unsigned int offset, + unsigned int length) +{ + struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; + + /* XXX: Just one READ payload slot for now, since our + * transport implementation currently supports only one + * Write chunk. + */ + rctxt->rc_read_payload_offset = offset; + rctxt->rc_read_payload_length = length; + + return 0; +} diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 145a3615c319..f6aad2798063 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -82,6 +82,7 @@ static const struct svc_xprt_ops svc_rdma_ops = { .xpo_create = svc_rdma_create, .xpo_recvfrom = svc_rdma_recvfrom, .xpo_sendto = svc_rdma_sendto, + .xpo_read_payload = svc_rdma_read_payload, .xpo_release_rqst = svc_rdma_release_rqst, .xpo_detach = svc_rdma_detach, .xpo_free = svc_rdma_free, From 7dcf4ab952d64ab6c2870ad414c4b81bd7346427 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:00:04 -0500 Subject: [PATCH 355/809] NFSD: Clean up nfsd4_encode_readv Address some minor nits I noticed while working on this function. Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index eedb62c411a5..996ac01ee977 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3591,7 +3591,6 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, __be32 nfserr; __be32 tmp; __be32 *p; - u32 zzz = 0; int pad; /* @@ -3607,7 +3606,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, v = 0; while (len) { thislen = min_t(long, len, PAGE_SIZE); - p = xdr_reserve_space(xdr, (thislen+3)&~3); + p = xdr_reserve_space(xdr, thislen); WARN_ON_ONCE(!p); resp->rqstp->rq_vec[v].iov_base = p; resp->rqstp->rq_vec[v].iov_len = thislen; @@ -3616,7 +3615,6 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, } read->rd_vlen = v; - len = maxcount; nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, &maxcount, &eof); @@ -3625,16 +3623,17 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, return nfserr; if (svc_encode_read_payload(resp->rqstp, starting_len + 8, maxcount)) return nfserr_io; - xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); + xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); tmp = htonl(eof); write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); tmp = htonl(maxcount); write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); + tmp = xdr_zero; pad = (maxcount&3) ? 4 - (maxcount&3) : 0; write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, - &zzz, pad); + &tmp, pad); return 0; } From 758a3bf9459d9daa19eac604f3dece77e0bf2441 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:00:14 -0500 Subject: [PATCH 356/809] svcrdma: Fix double svc_rdma_send_ctxt_put() in an error path This error path is almost never executed. Found by code inspection. Fixes: 99722fe4d5a6 ("svcrdma: Persistently allocate and DMA-map Send buffers") Signed-off-by: Chuck Lever --- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index a11983c2056f..354c5619176a 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -786,7 +786,6 @@ static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, struct svc_rqst *rqstp) { __be32 *p; - int ret; p = ctxt->sc_xprt_buf; trace_svcrdma_err_chunk(*p); @@ -798,13 +797,7 @@ static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, svc_rdma_save_io_pages(rqstp, ctxt); ctxt->sc_send_wr.opcode = IB_WR_SEND; - ret = svc_rdma_send(rdma, &ctxt->sc_send_wr); - if (ret) { - svc_rdma_send_ctxt_put(rdma, ctxt); - return ret; - } - - return 0; + return svc_rdma_send(rdma, &ctxt->sc_send_wr); } /** From 96f194b715b61b11f0184c776a1283df8e152033 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:01:08 -0500 Subject: [PATCH 357/809] SUNRPC: Add xdr_pad_size() helper Introduce a helper function to compute the XDR pad size of a variable-length XDR object. Clean up: Replace open-coded calculation of XDR pad sizes. I'm sure I haven't found every instance of this calculation. Signed-off-by: Chuck Lever --- include/linux/sunrpc/xdr.h | 15 +++++++++++++++ net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/auth_gss/svcauth_gss.c | 5 +++-- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 9 ++------- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index b41f34977995..83cd9f15c526 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -300,6 +300,21 @@ xdr_align_size(size_t n) return (n + mask) & ~mask; } +/** + * xdr_pad_size - Calculate size of an object's pad + * @n: Size of an object being XDR encoded (in bytes) + * + * This implementation avoids the need for conditional + * branches or modulo division. + * + * Return value: + * Size (in bytes) of the needed XDR pad + */ +static inline size_t xdr_pad_size(size_t n) +{ + return xdr_align_size(n) - n; +} + /** * xdr_stream_encode_u32 - Encode a 32-bit integer * @xdr: pointer to xdr_stream diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 24ca861815b1..ee060d57d216 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1877,7 +1877,7 @@ static int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, else iov = snd_buf->head; p = iov->iov_base + iov->iov_len; - pad = 3 - ((snd_buf->len - offset - 1) & 3); + pad = xdr_pad_size(snd_buf->len - offset); memset(p, 0, pad); iov->iov_len += pad; snd_buf->len += pad; diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 65b67b257302..fcf74621f008 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -961,7 +961,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs /* XXX: This is very inefficient. It would be better to either do * this while we encrypt, or maybe in the receive code, if we can peak * ahead and work out the service and mechanism there. */ - offset = buf->head[0].iov_len % 4; + offset = xdr_pad_size(buf->head[0].iov_len); if (offset) { buf->buflen = RPCSVC_MAXPAYLOAD; xdr_shift_buf(buf, offset); @@ -1680,7 +1680,8 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) goto out; integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base; integ_len = resbuf->len - integ_offset; - BUG_ON(integ_len % 4); + if (integ_len & 3) + goto out; *p++ = htonl(integ_len); *p++ = htonl(gc->gc_seq); if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len)) { diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 354c5619176a..4add875277f8 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -322,11 +322,6 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr) return ret; } -static u32 xdr_padsize(u32 len) -{ - return (len & 3) ? (4 - (len & 3)) : 0; -} - /* Returns length of transport header, in bytes. */ static unsigned int svc_rdma_reply_hdr_len(__be32 *rdma_resp) @@ -595,7 +590,7 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, if (wr_lst) { u32 xdrpad; - xdrpad = xdr_padsize(xdr->page_len); + xdrpad = xdr_pad_size(xdr->page_len); if (taillen && xdrpad) { tailbase += xdrpad; taillen -= xdrpad; @@ -670,7 +665,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, if (wr_lst) { base = xdr->tail[0].iov_base; len = xdr->tail[0].iov_len; - xdr_pad = xdr_padsize(xdr->page_len); + xdr_pad = xdr_pad_size(xdr->page_len); if (len && xdr_pad) { base += xdr_pad; From 28155524eaa2eabdc97e588db195d0a45d7e4d6f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:16:06 -0500 Subject: [PATCH 358/809] SUNRPC: Clean up: Replace dprintk and BUG_ON call sites in svcauth_gss.c Signed-off-by: Chuck Lever --- include/trace/events/rpcgss.h | 59 ++++++++++++++++++++++++++++++- net/sunrpc/auth_gss/svcauth_gss.c | 43 ++++++++-------------- 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h index 9827f535f032..32d88c4fb063 100644 --- a/include/trace/events/rpcgss.h +++ b/include/trace/events/rpcgss.h @@ -126,7 +126,7 @@ DEFINE_GSSAPI_EVENT(verify_mic); DEFINE_GSSAPI_EVENT(wrap); DEFINE_GSSAPI_EVENT(unwrap); -TRACE_EVENT(rpcgss_accept_upcall, +TRACE_EVENT(rpcgss_svc_accept_upcall, TP_PROTO( __be32 xid, u32 major_status, @@ -154,6 +154,29 @@ TRACE_EVENT(rpcgss_accept_upcall, ) ); +TRACE_EVENT(rpcgss_svc_accept, + TP_PROTO( + __be32 xid, + size_t len + ), + + TP_ARGS(xid, len), + + TP_STRUCT__entry( + __field(u32, xid) + __field(size_t, len) + ), + + TP_fast_assign( + __entry->xid = be32_to_cpu(xid); + __entry->len = len; + ), + + TP_printk("xid=0x%08x len=%zu", + __entry->xid, __entry->len + ) +); + /** ** GSS auth unwrap failures @@ -268,6 +291,40 @@ TRACE_EVENT(rpcgss_need_reencode, __entry->ret ? "" : "un") ); +DECLARE_EVENT_CLASS(rpcgss_svc_seqno_class, + TP_PROTO( + __be32 xid, + u32 seqno + ), + + TP_ARGS(xid, seqno), + + TP_STRUCT__entry( + __field(u32, xid) + __field(u32, seqno) + ), + + TP_fast_assign( + __entry->xid = be32_to_cpu(xid); + __entry->seqno = seqno; + ), + + TP_printk("xid=0x%08x seqno=%u, request discarded", + __entry->xid, __entry->seqno) +); + +#define DEFINE_SVC_SEQNO_EVENT(name) \ + DEFINE_EVENT(rpcgss_svc_seqno_class, rpcgss_svc_##name, \ + TP_PROTO( \ + __be32 xid, \ + u32 seqno \ + ), \ + TP_ARGS(xid, seqno)) + +DEFINE_SVC_SEQNO_EVENT(large_seqno); +DEFINE_SVC_SEQNO_EVENT(old_seqno); + + /** ** gssd upcall related trace events **/ diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index fcf74621f008..e93f06ec180d 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -55,10 +55,6 @@ #include "gss_rpc_upcall.h" -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -# define RPCDBG_FACILITY RPCDBG_AUTH -#endif - /* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests * into replies. * @@ -713,14 +709,12 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, } if (gc->gc_seq > MAXSEQ) { - dprintk("RPC: svcauth_gss: discarding request with " - "large sequence number %d\n", gc->gc_seq); + trace_rpcgss_svc_large_seqno(rqstp->rq_xid, gc->gc_seq); *authp = rpcsec_gsserr_ctxproblem; return SVC_DENIED; } if (!gss_check_seq_num(rsci, gc->gc_seq)) { - dprintk("RPC: svcauth_gss: discarding request with " - "old sequence number %d\n", gc->gc_seq); + trace_rpcgss_svc_old_seqno(rqstp->rq_xid, gc->gc_seq); return SVC_DROP; } return SVC_OK; @@ -1245,7 +1239,6 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, if (!ud->found_creds) { /* userspace seem buggy, we should always get at least a * mapping to nobody */ - dprintk("RPC: No creds found!\n"); goto out; } else { struct timespec64 boot; @@ -1311,8 +1304,8 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, if (status) goto out; - trace_rpcgss_accept_upcall(rqstp->rq_xid, ud.major_status, - ud.minor_status); + trace_rpcgss_svc_accept_upcall(rqstp->rq_xid, ud.major_status, + ud.minor_status); switch (ud.major_status) { case GSS_S_CONTINUE_NEEDED: @@ -1320,31 +1313,23 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, break; case GSS_S_COMPLETE: status = gss_proxy_save_rsc(sn->rsc_cache, &ud, &handle); - if (status) { - pr_info("%s: gss_proxy_save_rsc failed (%d)\n", - __func__, status); + if (status) goto out; - } cli_handle.data = (u8 *)&handle; cli_handle.len = sizeof(handle); break; default: - ret = SVC_CLOSE; goto out; } /* Got an answer to the upcall; use it: */ if (gss_write_init_verf(sn->rsc_cache, rqstp, - &cli_handle, &ud.major_status)) { - pr_info("%s: gss_write_init_verf failed\n", __func__); + &cli_handle, &ud.major_status)) goto out; - } if (gss_write_resv(resv, PAGE_SIZE, &cli_handle, &ud.out_token, - ud.major_status, ud.minor_status)) { - pr_info("%s: gss_write_resv failed\n", __func__); + ud.major_status, ud.minor_status)) goto out; - } ret = SVC_COMPLETE; out: @@ -1495,8 +1480,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) int ret; struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); - dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", - argv->iov_len); + trace_rpcgss_svc_accept(rqstp->rq_xid, argv->iov_len); *authp = rpc_autherr_badcred; if (!svcdata) @@ -1705,7 +1689,8 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) resv->iov_len += XDR_QUADLEN(mic.len) << 2; /* not strictly required: */ resbuf->len += XDR_QUADLEN(mic.len) << 2; - BUG_ON(resv->iov_len > PAGE_SIZE); + if (resv->iov_len > PAGE_SIZE) + goto out_err; out: stat = 0; out_err: @@ -1741,9 +1726,11 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) * both the head and tail. */ if (resbuf->tail[0].iov_base) { - BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base - + PAGE_SIZE); - BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base); + if (resbuf->tail[0].iov_base >= + resbuf->head[0].iov_base + PAGE_SIZE) + return -EINVAL; + if (resbuf->tail[0].iov_base < resbuf->head[0].iov_base) + return -EINVAL; if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len + 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE) return -ENOMEM; From b20dfc3fcd6ed1e16c828c81e1fc6f4aea2cfa77 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:01:08 -0500 Subject: [PATCH 359/809] svcrdma: Create a generic tracing class for displaying xdr_buf layout This class can be used to create trace points in either the RPC client or RPC server paths. It simply displays the length of each part of an xdr_buf, which is useful to determine that the transport and XDR codecs are operating correctly. Signed-off-by: Chuck Lever --- include/trace/events/sunrpc.h | 43 +++++++++++++++++++++++++++++++++++ net/sunrpc/clnt.c | 1 + net/sunrpc/svc_xprt.c | 3 +++ net/sunrpc/xprt.c | 3 +-- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index ee993575d2fa..1577223add43 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -14,6 +14,49 @@ #include #include +DECLARE_EVENT_CLASS(xdr_buf_class, + TP_PROTO( + const struct xdr_buf *xdr + ), + + TP_ARGS(xdr), + + TP_STRUCT__entry( + __field(const void *, head_base) + __field(size_t, head_len) + __field(const void *, tail_base) + __field(size_t, tail_len) + __field(unsigned int, page_len) + __field(unsigned int, msg_len) + ), + + TP_fast_assign( + __entry->head_base = xdr->head[0].iov_base; + __entry->head_len = xdr->head[0].iov_len; + __entry->tail_base = xdr->tail[0].iov_base; + __entry->tail_len = xdr->tail[0].iov_len; + __entry->page_len = xdr->page_len; + __entry->msg_len = xdr->len; + ), + + TP_printk("head=[%p,%zu] page=%u tail=[%p,%zu] len=%u", + __entry->head_base, __entry->head_len, __entry->page_len, + __entry->tail_base, __entry->tail_len, __entry->msg_len + ) +); + +#define DEFINE_XDRBUF_EVENT(name) \ + DEFINE_EVENT(xdr_buf_class, name, \ + TP_PROTO( \ + const struct xdr_buf *xdr \ + ), \ + TP_ARGS(xdr)) + +DEFINE_XDRBUF_EVENT(xprt_sendto); +DEFINE_XDRBUF_EVENT(xprt_recvfrom); +DEFINE_XDRBUF_EVENT(svc_recvfrom); +DEFINE_XDRBUF_EVENT(svc_sendto); + TRACE_DEFINE_ENUM(RPC_AUTH_OK); TRACE_DEFINE_ENUM(RPC_AUTH_BADCRED); TRACE_DEFINE_ENUM(RPC_AUTH_REJECTEDCRED); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 7324b21f923e..07992d3e8703 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2509,6 +2509,7 @@ call_decode(struct rpc_task *task) goto out; req->rq_rcv_buf.len = req->rq_private_buf.len; + trace_xprt_recvfrom(&req->rq_rcv_buf); /* Check that the softirq receive buffer is valid */ WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index de3c077733a7..d53259346235 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -802,6 +802,8 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) len = svc_deferred_recv(rqstp); else len = xprt->xpt_ops->xpo_recvfrom(rqstp); + if (len > 0) + trace_svc_recvfrom(&rqstp->rq_arg); rqstp->rq_stime = ktime_get(); rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); @@ -905,6 +907,7 @@ int svc_send(struct svc_rqst *rqstp) xb->len = xb->head[0].iov_len + xb->page_len + xb->tail[0].iov_len; + trace_svc_sendto(xb); /* Grab mutex to serialize outgoing data. */ mutex_lock(&xprt->xpt_mutex); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1aafe8d3f3f4..493a30a296fc 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1117,8 +1117,6 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", - task->tk_pid, ntohl(req->rq_xid), copied); trace_xprt_complete_rqst(xprt, req->rq_xid, copied); xprt->stat.recvs++; @@ -1462,6 +1460,7 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task) */ req->rq_ntrans++; + trace_xprt_sendto(&req->rq_snd_buf); connect_cookie = xprt->connect_cookie; status = xprt->ops->send_request(req); if (status != 0) { From 2426ddfdf169a4390e498b79b6d34d0d69c515bc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:01:08 -0500 Subject: [PATCH 360/809] svcrdma: Remove svcrdma_cm_event() trace point Clean up. This trace point is no longer needed because the RDMA/core CMA code has an equivalent trace point that was added by commit ed999f820a6c ("RDMA/cma: Add trace points in RDMA Connection Manager"). Signed-off-by: Chuck Lever --- include/trace/events/rpcrdma.h | 28 ------------------------ net/sunrpc/xprtrdma/svc_rdma_transport.c | 7 ------ 2 files changed, 35 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index c0e4c93324f5..545fe936a0cc 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -1813,34 +1813,6 @@ TRACE_EVENT(svcrdma_post_rw, DEFINE_SENDCOMP_EVENT(read); DEFINE_SENDCOMP_EVENT(write); -TRACE_EVENT(svcrdma_cm_event, - TP_PROTO( - const struct rdma_cm_event *event, - const struct sockaddr *sap - ), - - TP_ARGS(event, sap), - - TP_STRUCT__entry( - __field(unsigned int, event) - __field(int, status) - __array(__u8, addr, INET6_ADDRSTRLEN + 10) - ), - - TP_fast_assign( - __entry->event = event->event; - __entry->status = event->status; - snprintf(__entry->addr, sizeof(__entry->addr) - 1, - "%pISpc", sap); - ), - - TP_printk("addr=%s event=%s (%u/%d)", - __entry->addr, - rdma_show_cm_event(__entry->event), - __entry->event, __entry->status - ) -); - TRACE_EVENT(svcrdma_qp_error, TP_PROTO( const struct ib_event *event, diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index f6aad2798063..8bb99980ae85 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -241,10 +241,6 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, static int rdma_listen_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) { - struct sockaddr *sap = (struct sockaddr *)&cma_id->route.addr.src_addr; - - trace_svcrdma_cm_event(event, sap); - switch (event->event) { case RDMA_CM_EVENT_CONNECT_REQUEST: dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, " @@ -266,12 +262,9 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id, static int rdma_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) { - struct sockaddr *sap = (struct sockaddr *)&cma_id->route.addr.dst_addr; struct svcxprt_rdma *rdma = cma_id->context; struct svc_xprt *xprt = &rdma->sc_xprt; - trace_svcrdma_cm_event(event, sap); - switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: /* Accept complete */ From e604aad2cac7357162f661e45f2f60e46faa7b17 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:01:08 -0500 Subject: [PATCH 361/809] svcrdma: Use struct xdr_stream to decode ingress transport headers The logic that checks incoming network headers has to be scrupulous. De-duplicate: replace open-coded buffer overflow checks with the use of xdr_stream helpers that are used most everywhere else XDR decoding is done. One minor change to the sanity checks: instead of checking the length of individual segments, cap the length of the whole chunk to be sure it can fit in the set of pages available in rq_pages. This should be a better test of whether the server can handle the chunks in each request. Signed-off-by: Chuck Lever --- include/linux/sunrpc/rpc_rdma.h | 3 +- include/linux/sunrpc/svc_rdma.h | 1 + include/trace/events/rpcrdma.h | 7 +- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 208 ++++++++++++++---------- 4 files changed, 131 insertions(+), 88 deletions(-) diff --git a/include/linux/sunrpc/rpc_rdma.h b/include/linux/sunrpc/rpc_rdma.h index 92d182fd8e3b..320c672d84de 100644 --- a/include/linux/sunrpc/rpc_rdma.h +++ b/include/linux/sunrpc/rpc_rdma.h @@ -58,7 +58,8 @@ enum { enum { rpcrdma_fixed_maxsz = 4, rpcrdma_segment_maxsz = 4, - rpcrdma_readchunk_maxsz = 2 + rpcrdma_segment_maxsz, + rpcrdma_readseg_maxsz = 1 + rpcrdma_segment_maxsz, + rpcrdma_readchunk_maxsz = 1 + rpcrdma_readseg_maxsz, }; /* diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index 04e4a34d1c6a..c790dbb0dd90 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -132,6 +132,7 @@ struct svc_rdma_recv_ctxt { struct ib_sge rc_recv_sge; void *rc_recv_buf; struct xdr_buf rc_arg; + struct xdr_stream rc_stream; bool rc_temp; u32 rc_byte_len; unsigned int rc_page_count; diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 545fe936a0cc..814b73bd2cc7 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -1469,7 +1469,7 @@ DECLARE_EVENT_CLASS(svcrdma_segment_event, ); #define DEFINE_SEGMENT_EVENT(name) \ - DEFINE_EVENT(svcrdma_segment_event, svcrdma_encode_##name,\ + DEFINE_EVENT(svcrdma_segment_event, svcrdma_##name,\ TP_PROTO( \ u32 handle, \ u32 length, \ @@ -1477,8 +1477,9 @@ DECLARE_EVENT_CLASS(svcrdma_segment_event, ), \ TP_ARGS(handle, length, offset)) -DEFINE_SEGMENT_EVENT(rseg); -DEFINE_SEGMENT_EVENT(wseg); +DEFINE_SEGMENT_EVENT(decode_wseg); +DEFINE_SEGMENT_EVENT(encode_rseg); +DEFINE_SEGMENT_EVENT(encode_wseg); DECLARE_EVENT_CLASS(svcrdma_chunk_event, TP_PROTO( diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 71127d898562..bd92ed611b4c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -358,15 +358,14 @@ static void svc_rdma_build_arg_xdr(struct svc_rqst *rqstp, arg->len = ctxt->rc_byte_len; } -/* This accommodates the largest possible Write chunk, - * in one segment. +/* This accommodates the largest possible Write chunk. */ -#define MAX_BYTES_WRITE_SEG ((u32)(RPCSVC_MAXPAGES << PAGE_SHIFT)) +#define MAX_BYTES_WRITE_CHUNK ((u32)(RPCSVC_MAXPAGES << PAGE_SHIFT)) /* This accommodates the largest possible Position-Zero - * Read chunk or Reply chunk, in one segment. + * Read chunk or Reply chunk. */ -#define MAX_BYTES_SPECIAL_SEG ((u32)((RPCSVC_MAXPAGES + 2) << PAGE_SHIFT)) +#define MAX_BYTES_SPECIAL_CHUNK ((u32)((RPCSVC_MAXPAGES + 2) << PAGE_SHIFT)) /* Sanity check the Read list. * @@ -374,7 +373,7 @@ static void svc_rdma_build_arg_xdr(struct svc_rqst *rqstp, * - This implementation supports only one Read chunk. * * Sanity checks: - * - Read list does not overflow buffer. + * - Read list does not overflow Receive buffer. * - Segment size limited by largest NFS data payload. * * The segment count is limited to how many segments can @@ -382,30 +381,44 @@ static void svc_rdma_build_arg_xdr(struct svc_rqst *rqstp, * buffer. That's about 40 Read segments for a 1KB inline * threshold. * - * Returns pointer to the following Write list. + * Return values: + * %true: Read list is valid. @rctxt's xdr_stream is updated + * to point to the first byte past the Read list. + * %false: Read list is corrupt. @rctxt's xdr_stream is left + * in an unknown state. */ -static __be32 *xdr_check_read_list(__be32 *p, const __be32 *end) +static bool xdr_check_read_list(struct svc_rdma_recv_ctxt *rctxt) { - u32 position; + u32 position, len; bool first; + __be32 *p; + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); + if (!p) + return false; + + len = 0; first = true; - while (*p++ != xdr_zero) { - if (first) { - position = be32_to_cpup(p++); - first = false; - } else if (be32_to_cpup(p++) != position) { - return NULL; - } - p++; /* handle */ - if (be32_to_cpup(p++) > MAX_BYTES_SPECIAL_SEG) - return NULL; - p += 2; /* offset */ + while (*p != xdr_zero) { + p = xdr_inline_decode(&rctxt->rc_stream, + rpcrdma_readseg_maxsz * sizeof(*p)); + if (!p) + return false; - if (p > end) - return NULL; + if (first) { + position = be32_to_cpup(p); + first = false; + } else if (be32_to_cpup(p) != position) { + return false; + } + p += 2; + len += be32_to_cpup(p); + + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); + if (!p) + return false; } - return p; + return len <= MAX_BYTES_SPECIAL_CHUNK; } /* The segment count is limited to how many segments can @@ -413,67 +426,93 @@ static __be32 *xdr_check_read_list(__be32 *p, const __be32 *end) * buffer. That's about 60 Write segments for a 1KB inline * threshold. */ -static __be32 *xdr_check_write_chunk(__be32 *p, const __be32 *end, - u32 maxlen) +static bool xdr_check_write_chunk(struct svc_rdma_recv_ctxt *rctxt, u32 maxlen) { - u32 i, segcount; + u32 i, segcount, total; + __be32 *p; - segcount = be32_to_cpup(p++); + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); + if (!p) + return false; + segcount = be32_to_cpup(p); + + total = 0; for (i = 0; i < segcount; i++) { - p++; /* handle */ - if (be32_to_cpup(p++) > maxlen) - return NULL; - p += 2; /* offset */ + u32 handle, length; + u64 offset; - if (p > end) - return NULL; + p = xdr_inline_decode(&rctxt->rc_stream, + rpcrdma_segment_maxsz * sizeof(*p)); + if (!p) + return false; + + handle = be32_to_cpup(p++); + length = be32_to_cpup(p++); + xdr_decode_hyper(p, &offset); + trace_svcrdma_decode_wseg(handle, length, offset); + + total += length; } - - return p; + return total <= maxlen; } /* Sanity check the Write list. * * Implementation limits: - * - This implementation supports only one Write chunk. + * - This implementation currently supports only one Write chunk. * * Sanity checks: - * - Write list does not overflow buffer. - * - Segment size limited by largest NFS data payload. + * - Write list does not overflow Receive buffer. + * - Chunk size limited by largest NFS data payload. * - * Returns pointer to the following Reply chunk. + * Return values: + * %true: Write list is valid. @rctxt's xdr_stream is updated + * to point to the first byte past the Write list. + * %false: Write list is corrupt. @rctxt's xdr_stream is left + * in an unknown state. */ -static __be32 *xdr_check_write_list(__be32 *p, const __be32 *end) +static bool xdr_check_write_list(struct svc_rdma_recv_ctxt *rctxt) { - u32 chcount; + u32 chcount = 0; + __be32 *p; - chcount = 0; - while (*p++ != xdr_zero) { - p = xdr_check_write_chunk(p, end, MAX_BYTES_WRITE_SEG); + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); + if (!p) + return false; + while (*p != xdr_zero) { + if (!xdr_check_write_chunk(rctxt, MAX_BYTES_WRITE_CHUNK)) + return false; + ++chcount; + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); if (!p) - return NULL; - if (chcount++ > 1) - return NULL; + return false; } - return p; + return chcount < 2; } /* Sanity check the Reply chunk. * * Sanity checks: - * - Reply chunk does not overflow buffer. - * - Segment size limited by largest NFS data payload. + * - Reply chunk does not overflow Receive buffer. + * - Chunk size limited by largest NFS data payload. * - * Returns pointer to the following RPC header. + * Return values: + * %true: Reply chunk is valid. @rctxt's xdr_stream is updated + * to point to the first byte past the Reply chunk. + * %false: Reply chunk is corrupt. @rctxt's xdr_stream is left + * in an unknown state. */ -static __be32 *xdr_check_reply_chunk(__be32 *p, const __be32 *end) +static bool xdr_check_reply_chunk(struct svc_rdma_recv_ctxt *rctxt) { - if (*p++ != xdr_zero) { - p = xdr_check_write_chunk(p, end, MAX_BYTES_SPECIAL_SEG); - if (!p) - return NULL; - } - return p; + __be32 *p; + + p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); + if (!p) + return false; + if (*p != xdr_zero) + if (!xdr_check_write_chunk(rctxt, MAX_BYTES_SPECIAL_CHUNK)) + return false; + return true; } /* RPC-over-RDMA Version One private extension: Remote Invalidation. @@ -538,60 +577,61 @@ static void svc_rdma_get_inv_rkey(struct svcxprt_rdma *rdma, ctxt->rc_inv_rkey = be32_to_cpu(inv_rkey); } -/* On entry, xdr->head[0].iov_base points to first byte in the - * RPC-over-RDMA header. +/** + * svc_rdma_xdr_decode_req - Decode the transport header + * @rq_arg: xdr_buf containing ingress RPC/RDMA message + * @rctxt: state of decoding + * + * On entry, xdr->head[0].iov_base points to first byte of the + * RPC-over-RDMA transport header. * * On successful exit, head[0] points to first byte past the * RPC-over-RDMA header. For RDMA_MSG, this is the RPC message. + * * The length of the RPC-over-RDMA header is returned. * * Assumptions: * - The transport header is entirely contained in the head iovec. */ -static int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg) +static int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg, + struct svc_rdma_recv_ctxt *rctxt) { - __be32 *p, *end, *rdma_argp; + __be32 *p, *rdma_argp; unsigned int hdr_len; - /* Verify that there's enough bytes for header + something */ - if (rq_arg->len <= RPCRDMA_HDRLEN_ERR) - goto out_short; - rdma_argp = rq_arg->head[0].iov_base; - if (*(rdma_argp + 1) != rpcrdma_version) - goto out_version; + xdr_init_decode(&rctxt->rc_stream, rq_arg, rdma_argp, NULL); - switch (*(rdma_argp + 3)) { + p = xdr_inline_decode(&rctxt->rc_stream, + rpcrdma_fixed_maxsz * sizeof(*p)); + if (unlikely(!p)) + goto out_short; + p++; + if (*p != rpcrdma_version) + goto out_version; + p += 2; + switch (*p) { case rdma_msg: break; case rdma_nomsg: break; - case rdma_done: goto out_drop; - case rdma_error: goto out_drop; - default: goto out_proc; } - end = (__be32 *)((unsigned long)rdma_argp + rq_arg->len); - p = xdr_check_read_list(rdma_argp + 4, end); - if (!p) + if (!xdr_check_read_list(rctxt)) goto out_inval; - p = xdr_check_write_list(p, end); - if (!p) + if (!xdr_check_write_list(rctxt)) goto out_inval; - p = xdr_check_reply_chunk(p, end); - if (!p) - goto out_inval; - if (p > end) + if (!xdr_check_reply_chunk(rctxt)) goto out_inval; - rq_arg->head[0].iov_base = p; - hdr_len = (unsigned long)p - (unsigned long)rdma_argp; + rq_arg->head[0].iov_base = rctxt->rc_stream.p; + hdr_len = xdr_stream_pos(&rctxt->rc_stream); rq_arg->head[0].iov_len -= hdr_len; rq_arg->len -= hdr_len; trace_svcrdma_decode_rqst(rdma_argp, hdr_len); @@ -786,7 +826,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) rqstp->rq_next_page = rqstp->rq_respages; p = (__be32 *)rqstp->rq_arg.head[0].iov_base; - ret = svc_rdma_xdr_decode_req(&rqstp->rq_arg); + ret = svc_rdma_xdr_decode_req(&rqstp->rq_arg, ctxt); if (ret < 0) goto out_err; if (ret == 0) From 2fe8c446338e083a1f3c0ccaaaa20e7d48e71ebc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:01:08 -0500 Subject: [PATCH 362/809] svcrdma: De-duplicate code that locates Write and Reply chunks Cache the locations of the Requester-provided Write list and Reply chunk so that the Send path doesn't need to parse the Call header again. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 2 ++ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 9 +++++- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 38 +++---------------------- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index c790dbb0dd90..e714e4d90ac5 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -138,6 +138,8 @@ struct svc_rdma_recv_ctxt { unsigned int rc_page_count; unsigned int rc_hdr_count; u32 rc_inv_rkey; + __be32 *rc_write_list; + __be32 *rc_reply_chunk; unsigned int rc_read_payload_offset; unsigned int rc_read_payload_length; struct page *rc_pages[RPCSVC_MAXPAGES]; diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index bd92ed611b4c..70129d7cc972 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -479,6 +479,7 @@ static bool xdr_check_write_list(struct svc_rdma_recv_ctxt *rctxt) p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); if (!p) return false; + rctxt->rc_write_list = p; while (*p != xdr_zero) { if (!xdr_check_write_chunk(rctxt, MAX_BYTES_WRITE_CHUNK)) return false; @@ -487,6 +488,8 @@ static bool xdr_check_write_list(struct svc_rdma_recv_ctxt *rctxt) if (!p) return false; } + if (!chcount) + rctxt->rc_write_list = NULL; return chcount < 2; } @@ -509,9 +512,13 @@ static bool xdr_check_reply_chunk(struct svc_rdma_recv_ctxt *rctxt) p = xdr_inline_decode(&rctxt->rc_stream, sizeof(*p)); if (!p) return false; - if (*p != xdr_zero) + rctxt->rc_reply_chunk = p; + if (*p != xdr_zero) { if (!xdr_check_write_chunk(rctxt, MAX_BYTES_SPECIAL_CHUNK)) return false; + } else { + rctxt->rc_reply_chunk = NULL; + } return true; } diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 4add875277f8..94895635c007 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -449,36 +449,6 @@ static void svc_rdma_xdr_encode_reply_chunk(__be32 *rdma_resp, __be32 *rp_ch, xdr_encode_write_chunk(p, rp_ch, consumed); } -/* Parse the RPC Call's transport header. - */ -static void svc_rdma_get_write_arrays(__be32 *rdma_argp, - __be32 **write, __be32 **reply) -{ - __be32 *p; - - p = rdma_argp + rpcrdma_fixed_maxsz; - - /* Read list */ - while (*p++ != xdr_zero) - p += 5; - - /* Write list */ - if (*p != xdr_zero) { - *write = p; - while (*p++ != xdr_zero) - p += 1 + be32_to_cpu(*p) * 4; - } else { - *write = NULL; - p++; - } - - /* Reply chunk */ - if (*p != xdr_zero) - *reply = p; - else - *reply = NULL; -} - static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt, struct page *page, @@ -813,14 +783,14 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) struct svcxprt_rdma *rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt); struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; - __be32 *p, *rdma_argp, *rdma_resp, *wr_lst, *rp_ch; + __be32 *rdma_argp = rctxt->rc_recv_buf; + __be32 *wr_lst = rctxt->rc_write_list; + __be32 *rp_ch = rctxt->rc_reply_chunk; struct xdr_buf *xdr = &rqstp->rq_res; struct svc_rdma_send_ctxt *sctxt; + __be32 *p, *rdma_resp; int ret; - rdma_argp = rctxt->rc_recv_buf; - svc_rdma_get_write_arrays(rdma_argp, &wr_lst, &rp_ch); - /* Create the RDMA response header. xprt->xpt_mutex, * acquired in svc_send(), serializes RPC replies. The * code path below that inserts the credit grant value From 6fa5785e78d39f03d9fa33dea4dad2e7caf21e1e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:19 -0500 Subject: [PATCH 363/809] svcrdma: Update synopsis of svc_rdma_send_reply_chunk() Preparing for subsequent patches, no behavior change expected. Pass the RPC Call's svc_rdma_recv_ctxt deeper into the sendto() path. This enables passing more information about Requester- provided Write and Reply chunks into the lower-level send functions. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 2 +- net/sunrpc/xprtrdma/svc_rdma_rw.c | 12 ++++++------ net/sunrpc/xprtrdma/svc_rdma_sendto.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index e714e4d90ac5..42b68126cc60 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -179,7 +179,7 @@ extern int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, unsigned int offset, unsigned long length); extern int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, - __be32 *rp_ch, bool writelist, + const struct svc_rdma_recv_ctxt *rctxt, struct xdr_buf *xdr); /* svc_rdma_sendto.c */ diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 927f98995356..aee8ee2d01da 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -545,8 +545,7 @@ out_err: /** * svc_rdma_send_reply_chunk - Write all segments in the Reply chunk * @rdma: controlling RDMA transport - * @rp_ch: Reply chunk provided by client - * @writelist: true if client provided a Write list + * @rctxt: Write and Reply chunks from client * @xdr: xdr_buf containing an RPC Reply * * Returns a non-negative number of bytes the chunk consumed, or @@ -556,13 +555,14 @@ out_err: * %-ENOTCONN if posting failed (connection is lost), * %-EIO if rdma_rw initialization failed (DMA mapping, etc). */ -int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, __be32 *rp_ch, - bool writelist, struct xdr_buf *xdr) +int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, + const struct svc_rdma_recv_ctxt *rctxt, + struct xdr_buf *xdr) { struct svc_rdma_write_info *info; int consumed, ret; - info = svc_rdma_write_info_alloc(rdma, rp_ch); + info = svc_rdma_write_info_alloc(rdma, rctxt->rc_reply_chunk); if (!info) return -ENOMEM; @@ -574,7 +574,7 @@ int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, __be32 *rp_ch, /* Send the page list in the Reply chunk only if the * client did not provide Write chunks. */ - if (!writelist && xdr->page_len) { + if (!rctxt->rc_write_list && xdr->page_len) { ret = svc_rdma_send_xdr_pagelist(info, xdr, xdr->head[0].iov_len, xdr->page_len); diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 94895635c007..0b6ff55b1ab1 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -833,7 +833,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) svc_rdma_xdr_encode_write_list(rdma_resp, wr_lst, ret); } if (rp_ch) { - ret = svc_rdma_send_reply_chunk(rdma, rp_ch, wr_lst, xdr); + ret = svc_rdma_send_reply_chunk(rdma, rctxt, &rqstp->rq_res); if (ret < 0) goto err2; svc_rdma_xdr_encode_reply_chunk(rdma_resp, rp_ch, ret); From 4554755ed81bb690d709168550aba5b46447f069 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:19 -0500 Subject: [PATCH 364/809] svcrdma: Update synopsis of svc_rdma_map_reply_msg() Preparing for subsequent patches, no behavior change expected. Pass the RPC Call's svc_rdma_recv_ctxt deeper into the sendto() path. This enables passing more information about Requester- provided Write and Reply chunks into those lower-level functions. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 5 +- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 82 +++++++++++++--------- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index 42b68126cc60..c506732886b3 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -193,8 +193,9 @@ extern void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt, unsigned int len); extern int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, - struct svc_rdma_send_ctxt *ctxt, - struct xdr_buf *xdr, __be32 *wr_lst); + struct svc_rdma_send_ctxt *sctxt, + const struct svc_rdma_recv_ctxt *rctxt, + struct xdr_buf *xdr); extern int svc_rdma_sendto(struct svc_rqst *); extern int svc_rdma_read_payload(struct svc_rqst *rqstp, unsigned int offset, unsigned int length); diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 908e78bb87c6..ce1a7a706f36 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -117,7 +117,7 @@ static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma, { int ret; - ret = svc_rdma_map_reply_msg(rdma, ctxt, &rqst->rq_snd_buf, NULL); + ret = svc_rdma_map_reply_msg(rdma, ctxt, NULL, &rqst->rq_snd_buf); if (ret < 0) return -EIO; diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 0b6ff55b1ab1..0301b8721868 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -502,13 +502,19 @@ void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, DMA_TO_DEVICE); } -/* If the xdr_buf has more elements than the device can - * transmit in a single RDMA Send, then the reply will - * have to be copied into a bounce buffer. +/** + * svc_rdma_pull_up_needed - Determine whether to use pull-up + * @rdma: controlling transport + * @rctxt: Write and Reply chunks provided by client + * @xdr: xdr_buf containing RPC message to transmit + * + * Returns: + * %true if pull-up must be used + * %false otherwise */ static bool svc_rdma_pull_up_needed(struct svcxprt_rdma *rdma, - struct xdr_buf *xdr, - __be32 *wr_lst) + const struct svc_rdma_recv_ctxt *rctxt, + struct xdr_buf *xdr) { int elements; @@ -516,7 +522,7 @@ static bool svc_rdma_pull_up_needed(struct svcxprt_rdma *rdma, elements = 1; /* xdr->pages */ - if (!wr_lst) { + if (!rctxt || !rctxt->rc_write_list) { unsigned int remaining; unsigned long pageoff; @@ -538,26 +544,35 @@ static bool svc_rdma_pull_up_needed(struct svcxprt_rdma *rdma, return elements >= rdma->sc_max_send_sges; } -/* The device is not capable of sending the reply directly. - * Assemble the elements of @xdr into the transport header - * buffer. +/** + * svc_rdma_pull_up_reply_msg - Copy Reply into a single buffer + * @rdma: controlling transport + * @sctxt: send_ctxt for the Send WR; xprt hdr is already prepared + * @rctxt: Write and Reply chunks provided by client + * @xdr: prepared xdr_buf containing RPC message + * + * The device is not capable of sending the reply directly. + * Assemble the elements of @xdr into the transport header buffer. + * + * Returns zero on success, or a negative errno on failure. */ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, - struct svc_rdma_send_ctxt *ctxt, - struct xdr_buf *xdr, __be32 *wr_lst) + struct svc_rdma_send_ctxt *sctxt, + const struct svc_rdma_recv_ctxt *rctxt, + const struct xdr_buf *xdr) { unsigned char *dst, *tailbase; unsigned int taillen; - dst = ctxt->sc_xprt_buf; - dst += ctxt->sc_sges[0].length; + dst = sctxt->sc_xprt_buf; + dst += sctxt->sc_sges[0].length; memcpy(dst, xdr->head[0].iov_base, xdr->head[0].iov_len); dst += xdr->head[0].iov_len; tailbase = xdr->tail[0].iov_base; taillen = xdr->tail[0].iov_len; - if (wr_lst) { + if (rctxt && rctxt->rc_write_list) { u32 xdrpad; xdrpad = xdr_pad_size(xdr->page_len); @@ -586,20 +601,20 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, if (taillen) memcpy(dst, tailbase, taillen); - ctxt->sc_sges[0].length += xdr->len; + sctxt->sc_sges[0].length += xdr->len; ib_dma_sync_single_for_device(rdma->sc_pd->device, - ctxt->sc_sges[0].addr, - ctxt->sc_sges[0].length, + sctxt->sc_sges[0].addr, + sctxt->sc_sges[0].length, DMA_TO_DEVICE); return 0; } -/* svc_rdma_map_reply_msg - Map the buffer holding RPC message +/* svc_rdma_map_reply_msg - DMA map the buffer holding RPC message * @rdma: controlling transport - * @ctxt: send_ctxt for the Send WR + * @sctxt: send_ctxt for the Send WR + * @rctxt: Write and Reply chunks provided by client * @xdr: prepared xdr_buf containing RPC message - * @wr_lst: pointer to Call header's Write list, or NULL * * Load the xdr_buf into the ctxt's sge array, and DMA map each * element as it is added. @@ -607,8 +622,9 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, * Returns zero on success, or a negative errno on failure. */ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, - struct svc_rdma_send_ctxt *ctxt, - struct xdr_buf *xdr, __be32 *wr_lst) + struct svc_rdma_send_ctxt *sctxt, + const struct svc_rdma_recv_ctxt *rctxt, + struct xdr_buf *xdr) { unsigned int len, remaining; unsigned long page_off; @@ -617,11 +633,11 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, u32 xdr_pad; int ret; - if (svc_rdma_pull_up_needed(rdma, xdr, wr_lst)) - return svc_rdma_pull_up_reply_msg(rdma, ctxt, xdr, wr_lst); + if (svc_rdma_pull_up_needed(rdma, rctxt, xdr)) + return svc_rdma_pull_up_reply_msg(rdma, sctxt, rctxt, xdr); - ++ctxt->sc_cur_sge_no; - ret = svc_rdma_dma_map_buf(rdma, ctxt, + ++sctxt->sc_cur_sge_no; + ret = svc_rdma_dma_map_buf(rdma, sctxt, xdr->head[0].iov_base, xdr->head[0].iov_len); if (ret < 0) @@ -632,7 +648,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, * have added XDR padding in the tail buffer, and that * should not be included inline. */ - if (wr_lst) { + if (rctxt && rctxt->rc_write_list) { base = xdr->tail[0].iov_base; len = xdr->tail[0].iov_len; xdr_pad = xdr_pad_size(xdr->page_len); @@ -651,8 +667,8 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, while (remaining) { len = min_t(u32, PAGE_SIZE - page_off, remaining); - ++ctxt->sc_cur_sge_no; - ret = svc_rdma_dma_map_page(rdma, ctxt, *ppages++, + ++sctxt->sc_cur_sge_no; + ret = svc_rdma_dma_map_page(rdma, sctxt, *ppages++, page_off, len); if (ret < 0) return ret; @@ -665,8 +681,8 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, len = xdr->tail[0].iov_len; tail: if (len) { - ++ctxt->sc_cur_sge_no; - ret = svc_rdma_dma_map_buf(rdma, ctxt, base, len); + ++sctxt->sc_cur_sge_no; + ret = svc_rdma_dma_map_buf(rdma, sctxt, base, len); if (ret < 0) return ret; } @@ -720,8 +736,8 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, int ret; if (!rp_ch) { - ret = svc_rdma_map_reply_msg(rdma, sctxt, - &rqstp->rq_res, wr_lst); + ret = svc_rdma_map_reply_msg(rdma, sctxt, rctxt, + &rqstp->rq_res); if (ret < 0) return ret; } From db9602e40425c469dabaf8b3400ee553fbbd8307 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:20 -0500 Subject: [PATCH 365/809] svcrdma: Update synopsis of svc_rdma_send_reply_msg() Preparing for subsequent patches, no behavior change expected. Pass the RPC Call's svc_rdma_recv_ctxt deeper into the sendto() path. This enables passing more information about Requester- provided Write and Reply chunks into those lower-level functions. Signed-off-by: Chuck Lever --- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 0301b8721868..c2ace0fb7a2e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -729,13 +729,12 @@ static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, */ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *sctxt, - struct svc_rdma_recv_ctxt *rctxt, - struct svc_rqst *rqstp, - __be32 *wr_lst, __be32 *rp_ch) + const struct svc_rdma_recv_ctxt *rctxt, + struct svc_rqst *rqstp) { int ret; - if (!rp_ch) { + if (!rctxt->rc_reply_chunk) { ret = svc_rdma_map_reply_msg(rdma, sctxt, rctxt, &rqstp->rq_res); if (ret < 0) @@ -856,8 +855,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) } svc_rdma_sync_reply_hdr(rdma, sctxt, svc_rdma_reply_hdr_len(rdma_resp)); - ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp, - wr_lst, rp_ch); + ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp); if (ret < 0) goto err1; ret = 0; From a406c563e84212c6c63c5204817e30e4c5250dbb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:20 -0500 Subject: [PATCH 366/809] svcrdma: Rename svcrdma_encode trace points in send routines These trace points are misnamed: trace_svcrdma_encode_wseg trace_svcrdma_encode_write trace_svcrdma_encode_reply trace_svcrdma_encode_rseg trace_svcrdma_encode_read trace_svcrdma_encode_pzr Because they actually trace posting on the Send Queue. Let's rename them so that I can add trace points in the chunk list encoders that actually do trace chunk list encoding events. Signed-off-by: Chuck Lever --- include/trace/events/rpcrdma.h | 14 +++++++++----- net/sunrpc/xprtrdma/svc_rdma_rw.c | 13 +++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 814b73bd2cc7..74b68547eefb 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -1479,7 +1479,9 @@ DECLARE_EVENT_CLASS(svcrdma_segment_event, DEFINE_SEGMENT_EVENT(decode_wseg); DEFINE_SEGMENT_EVENT(encode_rseg); +DEFINE_SEGMENT_EVENT(send_rseg); DEFINE_SEGMENT_EVENT(encode_wseg); +DEFINE_SEGMENT_EVENT(send_wseg); DECLARE_EVENT_CLASS(svcrdma_chunk_event, TP_PROTO( @@ -1502,17 +1504,19 @@ DECLARE_EVENT_CLASS(svcrdma_chunk_event, ); #define DEFINE_CHUNK_EVENT(name) \ - DEFINE_EVENT(svcrdma_chunk_event, svcrdma_encode_##name,\ + DEFINE_EVENT(svcrdma_chunk_event, svcrdma_##name, \ TP_PROTO( \ u32 length \ ), \ TP_ARGS(length)) -DEFINE_CHUNK_EVENT(pzr); -DEFINE_CHUNK_EVENT(write); -DEFINE_CHUNK_EVENT(reply); +DEFINE_CHUNK_EVENT(send_pzr); +DEFINE_CHUNK_EVENT(encode_write_chunk); +DEFINE_CHUNK_EVENT(send_write_chunk); +DEFINE_CHUNK_EVENT(encode_read_chunk); +DEFINE_CHUNK_EVENT(send_reply_chunk); -TRACE_EVENT(svcrdma_encode_read, +TRACE_EVENT(svcrdma_send_read_chunk, TP_PROTO( u32 length, u32 position diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index aee8ee2d01da..bd7c195d872e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -439,7 +439,8 @@ svc_rdma_build_writes(struct svc_rdma_write_info *info, if (ret < 0) goto out_initerr; - trace_svcrdma_encode_wseg(seg_handle, write_len, seg_offset); + trace_svcrdma_send_wseg(seg_handle, write_len, seg_offset); + list_add(&ctxt->rw_list, &cc->cc_rwctxts); cc->cc_sqecount += ret; if (write_len == seg_length - info->wi_seg_off) { @@ -534,7 +535,7 @@ int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, __be32 *wr_ch, if (ret < 0) goto out_err; - trace_svcrdma_encode_write(xdr->page_len); + trace_svcrdma_send_write_chunk(xdr->page_len); return length; out_err: @@ -594,7 +595,7 @@ int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma, if (ret < 0) goto out_err; - trace_svcrdma_encode_reply(consumed); + trace_svcrdma_send_reply_chunk(consumed); return consumed; out_err: @@ -697,7 +698,7 @@ static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp, if (ret < 0) break; - trace_svcrdma_encode_rseg(rs_handle, rs_length, rs_offset); + trace_svcrdma_send_rseg(rs_handle, rs_length, rs_offset); info->ri_chunklen += rs_length; } @@ -728,7 +729,7 @@ static int svc_rdma_build_normal_read_chunk(struct svc_rqst *rqstp, if (ret < 0) goto out; - trace_svcrdma_encode_read(info->ri_chunklen, info->ri_position); + trace_svcrdma_send_read_chunk(info->ri_chunklen, info->ri_position); head->rc_hdr_count = 0; @@ -784,7 +785,7 @@ static int svc_rdma_build_pz_read_chunk(struct svc_rqst *rqstp, if (ret < 0) goto out; - trace_svcrdma_encode_pzr(info->ri_chunklen); + trace_svcrdma_send_pzr(info->ri_chunklen); head->rc_arg.len += info->ri_chunklen; head->rc_arg.buflen += info->ri_chunklen; From 5c266df52701635edfd49415b225fb17ceac5183 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:20 -0500 Subject: [PATCH 367/809] SUNRPC: Add encoders for list item discriminators Clean up. These are taken from the client-side RPC/RDMA transport to a more global header file so they can be used elsewhere. Signed-off-by: Chuck Lever --- include/linux/sunrpc/xdr.h | 38 ++++++++++++++++++++++++++++++++++ net/sunrpc/xprtrdma/rpc_rdma.c | 36 +++++--------------------------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 83cd9f15c526..9c8b73b509a1 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -315,6 +315,44 @@ static inline size_t xdr_pad_size(size_t n) return xdr_align_size(n) - n; } +/** + * xdr_stream_encode_item_present - Encode a "present" list item + * @xdr: pointer to xdr_stream + * + * Return values: + * On success, returns length in bytes of XDR buffer consumed + * %-EMSGSIZE on XDR buffer overflow + */ +static inline ssize_t xdr_stream_encode_item_present(struct xdr_stream *xdr) +{ + const size_t len = sizeof(__be32); + __be32 *p = xdr_reserve_space(xdr, len); + + if (unlikely(!p)) + return -EMSGSIZE; + *p = xdr_one; + return len; +} + +/** + * xdr_stream_encode_item_absent - Encode a "not present" list item + * @xdr: pointer to xdr_stream + * + * Return values: + * On success, returns length in bytes of XDR buffer consumed + * %-EMSGSIZE on XDR buffer overflow + */ +static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) +{ + const size_t len = sizeof(__be32); + __be32 *p = xdr_reserve_space(xdr, len); + + if (unlikely(!p)) + return -EMSGSIZE; + *p = xdr_zero; + return len; +} + /** * xdr_stream_encode_u32 - Encode a 32-bit integer * @xdr: pointer to xdr_stream diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 28020ec104d4..577513b7642e 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -275,32 +275,6 @@ out: return n; } -static inline int -encode_item_present(struct xdr_stream *xdr) -{ - __be32 *p; - - p = xdr_reserve_space(xdr, sizeof(*p)); - if (unlikely(!p)) - return -EMSGSIZE; - - *p = xdr_one; - return 0; -} - -static inline int -encode_item_not_present(struct xdr_stream *xdr) -{ - __be32 *p; - - p = xdr_reserve_space(xdr, sizeof(*p)); - if (unlikely(!p)) - return -EMSGSIZE; - - *p = xdr_zero; - return 0; -} - static void xdr_encode_rdma_segment(__be32 *iptr, struct rpcrdma_mr *mr) { @@ -414,7 +388,7 @@ static int rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt, } while (nsegs); done: - return encode_item_not_present(xdr); + return xdr_stream_encode_item_absent(xdr); } /* Register and XDR encode the Write list. Supports encoding a list @@ -453,7 +427,7 @@ static int rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, if (nsegs < 0) return nsegs; - if (encode_item_present(xdr) < 0) + if (xdr_stream_encode_item_present(xdr) < 0) return -EMSGSIZE; segcount = xdr_reserve_space(xdr, sizeof(*segcount)); if (unlikely(!segcount)) @@ -480,7 +454,7 @@ static int rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, *segcount = cpu_to_be32(nchunks); done: - return encode_item_not_present(xdr); + return xdr_stream_encode_item_absent(xdr); } /* Register and XDR encode the Reply chunk. Supports encoding an array @@ -507,14 +481,14 @@ static int rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, __be32 *segcount; if (wtype != rpcrdma_replych) - return encode_item_not_present(xdr); + return xdr_stream_encode_item_absent(xdr); seg = req->rl_segments; nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg); if (nsegs < 0) return nsegs; - if (encode_item_present(xdr) < 0) + if (xdr_stream_encode_item_present(xdr) < 0) return -EMSGSIZE; segcount = xdr_reserve_space(xdr, sizeof(*segcount)); if (unlikely(!segcount)) From 6fd5034db45c9c0ca57c98f3d5b9a0ce5869eab3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:02:20 -0500 Subject: [PATCH 368/809] svcrdma: Refactor chunk list encoders Same idea as the receive-side changes I did a while back: use xdr_stream helpers rather than open-coding the XDR chunk list encoders. This builds the Reply transport header from beginning to end without backtracking. As additional clean-ups, fill in documenting comments for the XDR encoders and sprinkle some trace points in the new encoding functions. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 2 + net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 15 +- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 32 ++- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 283 +++++++++++++-------- 4 files changed, 210 insertions(+), 122 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index c506732886b3..d001aac13c2f 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -149,6 +149,8 @@ struct svc_rdma_send_ctxt { struct list_head sc_list; struct ib_send_wr sc_send_wr; struct ib_cqe sc_cqe; + struct xdr_buf sc_hdrbuf; + struct xdr_stream sc_stream; void *sc_xprt_buf; int sc_page_count; int sc_cur_sge_no; diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index ce1a7a706f36..9830748c58d2 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -181,7 +181,9 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) if (!ctxt) goto drop_connection; - p = ctxt->sc_xprt_buf; + p = xdr_reserve_space(&ctxt->sc_stream, RPCRDMA_HDRLEN_MIN); + if (!p) + goto put_ctxt; *p++ = rqst->rq_xid; *p++ = rpcrdma_version; *p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_max_requests); @@ -189,7 +191,7 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) *p++ = xdr_zero; *p++ = xdr_zero; *p = xdr_zero; - svc_rdma_sync_reply_hdr(rdma, ctxt, RPCRDMA_HDRLEN_MIN); + svc_rdma_sync_reply_hdr(rdma, ctxt, ctxt->sc_hdrbuf.len); #ifdef SVCRDMA_BACKCHANNEL_DEBUG pr_info("%s: %*ph\n", __func__, 64, rqst->rq_buffer); @@ -197,12 +199,13 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) rqst->rq_xtime = ktime_get(); rc = svc_rdma_bc_sendto(rdma, rqst, ctxt); - if (rc) { - svc_rdma_send_ctxt_put(rdma, ctxt); - goto drop_connection; - } + if (rc) + goto put_ctxt; return 0; +put_ctxt: + svc_rdma_send_ctxt_put(rdma, ctxt); + drop_connection: dprintk("svcrdma: failed to send bc call\n"); return -ENOTCONN; diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 70129d7cc972..e2c747b5f517 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -698,7 +698,6 @@ static void svc_rdma_send_error(struct svcxprt_rdma *xprt, __be32 *rdma_argp, int status) { struct svc_rdma_send_ctxt *ctxt; - unsigned int length; __be32 *p; int ret; @@ -706,29 +705,46 @@ static void svc_rdma_send_error(struct svcxprt_rdma *xprt, if (!ctxt) return; - p = ctxt->sc_xprt_buf; + p = xdr_reserve_space(&ctxt->sc_stream, + rpcrdma_fixed_maxsz * sizeof(*p)); + if (!p) + goto put_ctxt; + *p++ = *rdma_argp; *p++ = *(rdma_argp + 1); *p++ = xprt->sc_fc_credits; - *p++ = rdma_error; + *p = rdma_error; + switch (status) { case -EPROTONOSUPPORT: + p = xdr_reserve_space(&ctxt->sc_stream, 3 * sizeof(*p)); + if (!p) + goto put_ctxt; + *p++ = err_vers; *p++ = rpcrdma_version; - *p++ = rpcrdma_version; + *p = rpcrdma_version; trace_svcrdma_err_vers(*rdma_argp); break; default: - *p++ = err_chunk; + p = xdr_reserve_space(&ctxt->sc_stream, sizeof(*p)); + if (!p) + goto put_ctxt; + + *p = err_chunk; trace_svcrdma_err_chunk(*rdma_argp); } - length = (unsigned long)p - (unsigned long)ctxt->sc_xprt_buf; - svc_rdma_sync_reply_hdr(xprt, ctxt, length); + + svc_rdma_sync_reply_hdr(xprt, ctxt, ctxt->sc_hdrbuf.len); ctxt->sc_send_wr.opcode = IB_WR_SEND; ret = svc_rdma_send(xprt, &ctxt->sc_send_wr); if (ret) - svc_rdma_send_ctxt_put(xprt, ctxt); + goto put_ctxt; + return; + +put_ctxt: + svc_rdma_send_ctxt_put(xprt, ctxt); } /* By convention, backchannel calls arrive via rdma_msg type diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index c2ace0fb7a2e..9d3b9a7e954f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -151,6 +151,8 @@ svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED; ctxt->sc_cqe.done = svc_rdma_wc_send; ctxt->sc_xprt_buf = buffer; + xdr_buf_init(&ctxt->sc_hdrbuf, ctxt->sc_xprt_buf, + rdma->sc_max_req_size); ctxt->sc_sges[0].addr = addr; for (i = 0; i < rdma->sc_max_send_sges; i++) @@ -204,6 +206,10 @@ struct svc_rdma_send_ctxt *svc_rdma_send_ctxt_get(struct svcxprt_rdma *rdma) spin_unlock(&rdma->sc_send_lock); out: + rpcrdma_set_xdrlen(&ctxt->sc_hdrbuf, 0); + xdr_init_encode(&ctxt->sc_stream, &ctxt->sc_hdrbuf, + ctxt->sc_xprt_buf, NULL); + ctxt->sc_send_wr.num_sge = 0; ctxt->sc_cur_sge_no = 0; ctxt->sc_page_count = 0; @@ -322,131 +328,173 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr) return ret; } -/* Returns length of transport header, in bytes. +/** + * svc_rdma_encode_read_list - Encode RPC Reply's Read chunk list + * @sctxt: Send context for the RPC Reply + * + * Return values: + * On success, returns length in bytes of the Reply XDR buffer + * that was consumed by the Reply Read list + * %-EMSGSIZE on XDR buffer overflow */ -static unsigned int svc_rdma_reply_hdr_len(__be32 *rdma_resp) +static ssize_t svc_rdma_encode_read_list(struct svc_rdma_send_ctxt *sctxt) { - unsigned int nsegs; - __be32 *p; - - p = rdma_resp; - - /* RPC-over-RDMA V1 replies never have a Read list. */ - p += rpcrdma_fixed_maxsz + 1; - - /* Skip Write list. */ - while (*p++ != xdr_zero) { - nsegs = be32_to_cpup(p++); - p += nsegs * rpcrdma_segment_maxsz; - } - - /* Skip Reply chunk. */ - if (*p++ != xdr_zero) { - nsegs = be32_to_cpup(p++); - p += nsegs * rpcrdma_segment_maxsz; - } - - return (unsigned long)p - (unsigned long)rdma_resp; + /* RPC-over-RDMA version 1 replies never have a Read list. */ + return xdr_stream_encode_item_absent(&sctxt->sc_stream); } -/* One Write chunk is copied from Call transport header to Reply - * transport header. Each segment's length field is updated to - * reflect number of bytes consumed in the segment. +/** + * svc_rdma_encode_write_segment - Encode one Write segment + * @src: matching Write chunk in the RPC Call header + * @sctxt: Send context for the RPC Reply + * @remaining: remaining bytes of the payload left in the Write chunk * - * Returns number of segments in this chunk. + * Return values: + * On success, returns length in bytes of the Reply XDR buffer + * that was consumed by the Write segment + * %-EMSGSIZE on XDR buffer overflow */ -static unsigned int xdr_encode_write_chunk(__be32 *dst, __be32 *src, +static ssize_t svc_rdma_encode_write_segment(__be32 *src, + struct svc_rdma_send_ctxt *sctxt, + unsigned int *remaining) +{ + __be32 *p; + const size_t len = rpcrdma_segment_maxsz * sizeof(*p); + u32 handle, length; + u64 offset; + + p = xdr_reserve_space(&sctxt->sc_stream, len); + if (!p) + return -EMSGSIZE; + + handle = be32_to_cpup(src++); + length = be32_to_cpup(src++); + xdr_decode_hyper(src, &offset); + + *p++ = cpu_to_be32(handle); + if (*remaining < length) { + /* segment only partly filled */ + length = *remaining; + *remaining = 0; + } else { + /* entire segment was consumed */ + *remaining -= length; + } + *p++ = cpu_to_be32(length); + xdr_encode_hyper(p, offset); + + trace_svcrdma_encode_wseg(handle, length, offset); + return len; +} + +/** + * svc_rdma_encode_write_chunk - Encode one Write chunk + * @src: matching Write chunk in the RPC Call header + * @sctxt: Send context for the RPC Reply + * @remaining: size in bytes of the payload in the Write chunk + * + * Copy a Write chunk from the Call transport header to the + * Reply transport header. Update each segment's length field + * to reflect the number of bytes written in that segment. + * + * Return values: + * On success, returns length in bytes of the Reply XDR buffer + * that was consumed by the Write chunk + * %-EMSGSIZE on XDR buffer overflow + */ +static ssize_t svc_rdma_encode_write_chunk(__be32 *src, + struct svc_rdma_send_ctxt *sctxt, unsigned int remaining) { unsigned int i, nsegs; - u32 seg_len; + ssize_t len, ret; - /* Write list discriminator */ - *dst++ = *src++; + len = 0; + trace_svcrdma_encode_write_chunk(remaining); - /* number of segments in this chunk */ - nsegs = be32_to_cpup(src); - *dst++ = *src++; + src++; + ret = xdr_stream_encode_item_present(&sctxt->sc_stream); + if (ret < 0) + return -EMSGSIZE; + len += ret; + + nsegs = be32_to_cpup(src++); + ret = xdr_stream_encode_u32(&sctxt->sc_stream, nsegs); + if (ret < 0) + return -EMSGSIZE; + len += ret; for (i = nsegs; i; i--) { - /* segment's RDMA handle */ - *dst++ = *src++; - - /* bytes returned in this segment */ - seg_len = be32_to_cpu(*src); - if (remaining >= seg_len) { - /* entire segment was consumed */ - *dst = *src; - remaining -= seg_len; - } else { - /* segment only partly filled */ - *dst = cpu_to_be32(remaining); - remaining = 0; - } - dst++; src++; - - /* segment's RDMA offset */ - *dst++ = *src++; - *dst++ = *src++; + ret = svc_rdma_encode_write_segment(src, sctxt, &remaining); + if (ret < 0) + return -EMSGSIZE; + src += rpcrdma_segment_maxsz; + len += ret; } - return nsegs; + return len; } -/* The client provided a Write list in the Call message. Fill in - * the segments in the first Write chunk in the Reply's transport +/** + * svc_rdma_encode_write_list - Encode RPC Reply's Write chunk list + * @rctxt: Reply context with information about the RPC Call + * @sctxt: Send context for the RPC Reply + * @length: size in bytes of the payload in the first Write chunk + * + * The client provides a Write chunk list in the Call message. Fill + * in the segments in the first Write chunk in the Reply's transport * header with the number of bytes consumed in each segment. * Remaining chunks are returned unused. * * Assumptions: * - Client has provided only one Write chunk + * + * Return values: + * On success, returns length in bytes of the Reply XDR buffer + * that was consumed by the Reply's Write list + * %-EMSGSIZE on XDR buffer overflow */ -static void svc_rdma_xdr_encode_write_list(__be32 *rdma_resp, __be32 *wr_ch, - unsigned int consumed) +static ssize_t +svc_rdma_encode_write_list(const struct svc_rdma_recv_ctxt *rctxt, + struct svc_rdma_send_ctxt *sctxt, + unsigned int length) { - unsigned int nsegs; - __be32 *p, *q; + ssize_t len, ret; - /* RPC-over-RDMA V1 replies never have a Read list. */ - p = rdma_resp + rpcrdma_fixed_maxsz + 1; + ret = svc_rdma_encode_write_chunk(rctxt->rc_write_list, sctxt, length); + if (ret < 0) + return ret; + len = ret; - q = wr_ch; - while (*q != xdr_zero) { - nsegs = xdr_encode_write_chunk(p, q, consumed); - q += 2 + nsegs * rpcrdma_segment_maxsz; - p += 2 + nsegs * rpcrdma_segment_maxsz; - consumed = 0; - } + /* Terminate the Write list */ + ret = xdr_stream_encode_item_absent(&sctxt->sc_stream); + if (ret < 0) + return ret; - /* Terminate Write list */ - *p++ = xdr_zero; - - /* Reply chunk discriminator; may be replaced later */ - *p = xdr_zero; + return len + ret; } -/* The client provided a Reply chunk in the Call message. Fill in - * the segments in the Reply chunk in the Reply message with the - * number of bytes consumed in each segment. +/** + * svc_rdma_encode_reply_chunk - Encode RPC Reply's Reply chunk + * @rctxt: Reply context with information about the RPC Call + * @sctxt: Send context for the RPC Reply + * @length: size in bytes of the payload in the Reply chunk * * Assumptions: - * - Reply can always fit in the provided Reply chunk + * - Reply can always fit in the client-provided Reply chunk + * + * Return values: + * On success, returns length in bytes of the Reply XDR buffer + * that was consumed by the Reply's Reply chunk + * %-EMSGSIZE on XDR buffer overflow */ -static void svc_rdma_xdr_encode_reply_chunk(__be32 *rdma_resp, __be32 *rp_ch, - unsigned int consumed) +static ssize_t +svc_rdma_encode_reply_chunk(const struct svc_rdma_recv_ctxt *rctxt, + struct svc_rdma_send_ctxt *sctxt, + unsigned int length) { - __be32 *p; - - /* Find the Reply chunk in the Reply's xprt header. - * RPC-over-RDMA V1 replies never have a Read list. - */ - p = rdma_resp + rpcrdma_fixed_maxsz + 1; - - /* Skip past Write list */ - while (*p++ != xdr_zero) - p += 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz; - - xdr_encode_write_chunk(p, rp_ch, consumed); + return svc_rdma_encode_write_chunk(rctxt->rc_reply_chunk, sctxt, + length); } static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma, @@ -765,14 +813,26 @@ static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt, struct svc_rqst *rqstp) { + struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; + __be32 *rdma_argp = rctxt->rc_recv_buf; __be32 *p; - p = ctxt->sc_xprt_buf; - trace_svcrdma_err_chunk(*p); - p += 3; + rpcrdma_set_xdrlen(&ctxt->sc_hdrbuf, 0); + xdr_init_encode(&ctxt->sc_stream, &ctxt->sc_hdrbuf, ctxt->sc_xprt_buf, + NULL); + + p = xdr_reserve_space(&ctxt->sc_stream, RPCRDMA_HDRLEN_ERR); + if (!p) + return -ENOMSG; + + *p++ = *rdma_argp; + *p++ = *(rdma_argp + 1); + *p++ = rdma->sc_fc_credits; *p++ = rdma_error; *p = err_chunk; - svc_rdma_sync_reply_hdr(rdma, ctxt, RPCRDMA_HDRLEN_ERR); + trace_svcrdma_err_chunk(*rdma_argp); + + svc_rdma_sync_reply_hdr(rdma, ctxt, ctxt->sc_hdrbuf.len); svc_rdma_save_io_pages(rqstp, ctxt); @@ -803,7 +863,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) __be32 *rp_ch = rctxt->rc_reply_chunk; struct xdr_buf *xdr = &rqstp->rq_res; struct svc_rdma_send_ctxt *sctxt; - __be32 *p, *rdma_resp; + __be32 *p; int ret; /* Create the RDMA response header. xprt->xpt_mutex, @@ -816,19 +876,18 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) sctxt = svc_rdma_send_ctxt_get(rdma); if (!sctxt) goto err0; - rdma_resp = sctxt->sc_xprt_buf; - p = rdma_resp; + p = xdr_reserve_space(&sctxt->sc_stream, + rpcrdma_fixed_maxsz * sizeof(*p)); + if (!p) + goto err0; *p++ = *rdma_argp; *p++ = *(rdma_argp + 1); *p++ = rdma->sc_fc_credits; - *p++ = rp_ch ? rdma_nomsg : rdma_msg; - - /* Start with empty chunks */ - *p++ = xdr_zero; - *p++ = xdr_zero; - *p = xdr_zero; + *p = rp_ch ? rdma_nomsg : rdma_msg; + if (svc_rdma_encode_read_list(sctxt) < 0) + goto err0; if (wr_lst) { /* XXX: Presume the client sent only one Write chunk */ unsigned long offset; @@ -845,16 +904,24 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) length); if (ret < 0) goto err2; - svc_rdma_xdr_encode_write_list(rdma_resp, wr_lst, ret); + if (svc_rdma_encode_write_list(rctxt, sctxt, length) < 0) + goto err0; + } else { + if (xdr_stream_encode_item_absent(&sctxt->sc_stream) < 0) + goto err0; } if (rp_ch) { ret = svc_rdma_send_reply_chunk(rdma, rctxt, &rqstp->rq_res); if (ret < 0) goto err2; - svc_rdma_xdr_encode_reply_chunk(rdma_resp, rp_ch, ret); + if (svc_rdma_encode_reply_chunk(rctxt, sctxt, ret) < 0) + goto err0; + } else { + if (xdr_stream_encode_item_absent(&sctxt->sc_stream) < 0) + goto err0; } - svc_rdma_sync_reply_hdr(rdma, sctxt, svc_rdma_reply_hdr_len(rdma_resp)); + svc_rdma_sync_reply_hdr(rdma, sctxt, sctxt->sc_hdrbuf.len); ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp); if (ret < 0) goto err1; From aee4b74a3f273b54d136132fedf575ec464f4134 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 3 Mar 2020 11:08:05 -0500 Subject: [PATCH 369/809] svcrdma: Fix double sync of transport header buffer Performance optimization: Avoid syncing the transport buffer twice when Reply buffer pull-up is necessary. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 3 - net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 1 - net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 4 +- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 64 +++++++++------------- 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index d001aac13c2f..a3fa5b4fa2e4 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -191,9 +191,6 @@ extern struct svc_rdma_send_ctxt * extern void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt); extern int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr); -extern void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, - struct svc_rdma_send_ctxt *ctxt, - unsigned int len); extern int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *sctxt, const struct svc_rdma_recv_ctxt *rctxt, diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 9830748c58d2..46b59e91d34a 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -191,7 +191,6 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) *p++ = xdr_zero; *p++ = xdr_zero; *p = xdr_zero; - svc_rdma_sync_reply_hdr(rdma, ctxt, ctxt->sc_hdrbuf.len); #ifdef SVCRDMA_BACKCHANNEL_DEBUG pr_info("%s: %*ph\n", __func__, 64, rqst->rq_buffer); diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index e2c747b5f517..54469b72b25f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -735,9 +735,9 @@ static void svc_rdma_send_error(struct svcxprt_rdma *xprt, trace_svcrdma_err_chunk(*rdma_argp); } - svc_rdma_sync_reply_hdr(xprt, ctxt, ctxt->sc_hdrbuf.len); - + ctxt->sc_send_wr.num_sge = 1; ctxt->sc_send_wr.opcode = IB_WR_SEND; + ctxt->sc_sges[0].length = ctxt->sc_hdrbuf.len; ret = svc_rdma_send(xprt, &ctxt->sc_send_wr); if (ret) goto put_ctxt; diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 9d3b9a7e954f..7b9853214769 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -301,6 +301,12 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr) might_sleep(); + /* Sync the transport header buffer */ + ib_dma_sync_single_for_device(rdma->sc_pd->device, + wr->sg_list[0].addr, + wr->sg_list[0].length, + DMA_TO_DEVICE); + /* If the SQ is full, wait until an SQ entry is available */ while (1) { if ((atomic_dec_return(&rdma->sc_sq_avail) < 0)) { @@ -532,24 +538,6 @@ static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma, offset_in_page(base), len); } -/** - * svc_rdma_sync_reply_hdr - DMA sync the transport header buffer - * @rdma: controlling transport - * @ctxt: send_ctxt for the Send WR - * @len: length of transport header - * - */ -void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, - struct svc_rdma_send_ctxt *ctxt, - unsigned int len) -{ - ctxt->sc_sges[0].length = len; - ctxt->sc_send_wr.num_sge++; - ib_dma_sync_single_for_device(rdma->sc_pd->device, - ctxt->sc_sges[0].addr, len, - DMA_TO_DEVICE); -} - /** * svc_rdma_pull_up_needed - Determine whether to use pull-up * @rdma: controlling transport @@ -612,9 +600,7 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, unsigned char *dst, *tailbase; unsigned int taillen; - dst = sctxt->sc_xprt_buf; - dst += sctxt->sc_sges[0].length; - + dst = sctxt->sc_xprt_buf + sctxt->sc_hdrbuf.len; memcpy(dst, xdr->head[0].iov_base, xdr->head[0].iov_len); dst += xdr->head[0].iov_len; @@ -650,11 +636,6 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, memcpy(dst, tailbase, taillen); sctxt->sc_sges[0].length += xdr->len; - ib_dma_sync_single_for_device(rdma->sc_pd->device, - sctxt->sc_sges[0].addr, - sctxt->sc_sges[0].length, - DMA_TO_DEVICE); - return 0; } @@ -665,7 +646,7 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, * @xdr: prepared xdr_buf containing RPC message * * Load the xdr_buf into the ctxt's sge array, and DMA map each - * element as it is added. + * element as it is added. The Send WR's num_sge field is set. * * Returns zero on success, or a negative errno on failure. */ @@ -681,6 +662,19 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, u32 xdr_pad; int ret; + /* Set up the (persistently-mapped) transport header SGE. */ + sctxt->sc_send_wr.num_sge = 1; + sctxt->sc_sges[0].length = sctxt->sc_hdrbuf.len; + + /* If there is a Reply chunk, nothing follows the transport + * header, and we're done here. + */ + if (rctxt && rctxt->rc_reply_chunk) + return 0; + + /* For pull-up, svc_rdma_send() will sync the transport header. + * No additional DMA mapping is necessary. + */ if (svc_rdma_pull_up_needed(rdma, rctxt, xdr)) return svc_rdma_pull_up_reply_msg(rdma, sctxt, rctxt, xdr); @@ -782,12 +776,9 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, { int ret; - if (!rctxt->rc_reply_chunk) { - ret = svc_rdma_map_reply_msg(rdma, sctxt, rctxt, - &rqstp->rq_res); - if (ret < 0) - return ret; - } + ret = svc_rdma_map_reply_msg(rdma, sctxt, rctxt, &rqstp->rq_res); + if (ret < 0) + return ret; svc_rdma_save_io_pages(rqstp, sctxt); @@ -797,8 +788,6 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, } else { sctxt->sc_send_wr.opcode = IB_WR_SEND; } - dprintk("svcrdma: posting Send WR with %u sge(s)\n", - sctxt->sc_send_wr.num_sge); return svc_rdma_send(rdma, &sctxt->sc_send_wr); } @@ -832,11 +821,11 @@ static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, *p = err_chunk; trace_svcrdma_err_chunk(*rdma_argp); - svc_rdma_sync_reply_hdr(rdma, ctxt, ctxt->sc_hdrbuf.len); - svc_rdma_save_io_pages(rqstp, ctxt); + ctxt->sc_send_wr.num_sge = 1; ctxt->sc_send_wr.opcode = IB_WR_SEND; + ctxt->sc_sges[0].length = ctxt->sc_hdrbuf.len; return svc_rdma_send(rdma, &ctxt->sc_send_wr); } @@ -921,7 +910,6 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) goto err0; } - svc_rdma_sync_reply_hdr(rdma, sctxt, sctxt->sc_hdrbuf.len); ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp); if (ret < 0) goto err1; From 0dabe948f28274e7956a625a24f205016b810693 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 3 Mar 2020 13:28:14 -0500 Subject: [PATCH 370/809] svcrdma: Avoid DMA mapping small RPC Replies On some platforms, DMA mapping part of a page is more costly than copying bytes. Indeed, not involving the I/O MMU can help the RPC/RDMA transport scale better for tiny I/Os across more RDMA devices. This is because interaction with the I/O MMU is eliminated for each of these small I/Os. Without the explicit unmapping, the NIC no longer needs to do a costly internal TLB shoot down for buffers that are just a handful of bytes. Since pull-up is now a more a frequent operation, I've introduced a trace point in the pull-up path. It can be used for debugging or user-space tools that count pull-up frequency. Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_rdma.h | 1 + include/trace/events/rpcrdma.h | 18 ++++++++++++++++++ net/sunrpc/xprtrdma/svc_rdma_sendto.c | 13 ++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index a3fa5b4fa2e4..78fe2ac6dc6c 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -52,6 +52,7 @@ /* Default and maximum inline threshold sizes */ enum { + RPCRDMA_PULLUP_THRESH = RPCRDMA_V1_DEF_INLINE_SIZE >> 1, RPCRDMA_DEF_INLINE_THRESH = 4096, RPCRDMA_MAX_INLINE_THRESH = 65536 }; diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 74b68547eefb..9238d233f8cf 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -1639,6 +1639,24 @@ TRACE_EVENT(svcrdma_dma_map_rwctx, ) ); +TRACE_EVENT(svcrdma_send_pullup, + TP_PROTO( + unsigned int len + ), + + TP_ARGS(len), + + TP_STRUCT__entry( + __field(unsigned int, len) + ), + + TP_fast_assign( + __entry->len = len; + ), + + TP_printk("len=%u", __entry->len) +); + TRACE_EVENT(svcrdma_send_failed, TP_PROTO( const struct svc_rqst *rqst, diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 7b9853214769..90cba3058f04 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -541,6 +541,7 @@ static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma, /** * svc_rdma_pull_up_needed - Determine whether to use pull-up * @rdma: controlling transport + * @sctxt: send_ctxt for the Send WR * @rctxt: Write and Reply chunks provided by client * @xdr: xdr_buf containing RPC message to transmit * @@ -549,11 +550,20 @@ static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma, * %false otherwise */ static bool svc_rdma_pull_up_needed(struct svcxprt_rdma *rdma, + struct svc_rdma_send_ctxt *sctxt, const struct svc_rdma_recv_ctxt *rctxt, struct xdr_buf *xdr) { int elements; + /* For small messages, copying bytes is cheaper than DMA mapping. + */ + if (sctxt->sc_hdrbuf.len + xdr->len < RPCRDMA_PULLUP_THRESH) + return true; + + /* Check whether the xdr_buf has more elements than can + * fit in a single RDMA Send. + */ /* xdr->head */ elements = 1; @@ -636,6 +646,7 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, memcpy(dst, tailbase, taillen); sctxt->sc_sges[0].length += xdr->len; + trace_svcrdma_send_pullup(sctxt->sc_sges[0].length); return 0; } @@ -675,7 +686,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, /* For pull-up, svc_rdma_send() will sync the transport header. * No additional DMA mapping is necessary. */ - if (svc_rdma_pull_up_needed(rdma, rctxt, xdr)) + if (svc_rdma_pull_up_needed(rdma, sctxt, rctxt, xdr)) return svc_rdma_pull_up_reply_msg(rdma, sctxt, rctxt, xdr); ++sctxt->sc_cur_sge_no; From 9e55eef4ab1bf1810443bb3989a07a68e1f5d084 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:19:54 -0500 Subject: [PATCH 371/809] SUNRPC: Refactor xs_sendpages() Re-locate xs_sendpages() so that it can be shared with server code. Signed-off-by: Chuck Lever --- include/linux/sunrpc/xdr.h | 14 ---- net/sunrpc/socklib.c | 141 +++++++++++++++++++++++++++++++++++ net/sunrpc/socklib.h | 15 ++++ net/sunrpc/svcsock.c | 1 + net/sunrpc/xprtsock.c | 149 +++++-------------------------------- 5 files changed, 177 insertions(+), 143 deletions(-) create mode 100644 net/sunrpc/socklib.h diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 9c8b73b509a1..8529d6e33137 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -188,20 +188,6 @@ extern int xdr_buf_read_mic(struct xdr_buf *, struct xdr_netobj *, unsigned int) extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); -/* - * Helper structure for copying from an sk_buff. - */ -struct xdr_skb_reader { - struct sk_buff *skb; - unsigned int offset; - size_t count; - __wsum csum; -}; - -typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, size_t len); - -extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); - extern int xdr_encode_word(struct xdr_buf *, unsigned int, u32); extern int xdr_decode_word(struct xdr_buf *, unsigned int, u32 *); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 1a864f1ed119..3fc8af8bb961 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -14,9 +14,24 @@ #include #include #include +#include #include #include +#include "socklib.h" + +/* + * Helper structure for copying from an sk_buff. + */ +struct xdr_skb_reader { + struct sk_buff *skb; + unsigned int offset; + size_t count; + __wsum csum; +}; + +typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, + size_t len); /** * xdr_skb_read_bits - copy some data bits from skb to internal buffer @@ -186,3 +201,129 @@ no_checksum: return 0; } EXPORT_SYMBOL_GPL(csum_partial_copy_to_xdr); + +static inline int xprt_sendmsg(struct socket *sock, struct msghdr *msg, + size_t seek) +{ + if (seek) + iov_iter_advance(&msg->msg_iter, seek); + return sock_sendmsg(sock, msg); +} + +static int xprt_send_kvec(struct socket *sock, struct msghdr *msg, + struct kvec *vec, size_t seek) +{ + iov_iter_kvec(&msg->msg_iter, WRITE, vec, 1, vec->iov_len); + return xprt_sendmsg(sock, msg, seek); +} + +static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg, + struct xdr_buf *xdr, size_t base) +{ + int err; + + err = xdr_alloc_bvec(xdr, GFP_KERNEL); + if (err < 0) + return err; + + iov_iter_bvec(&msg->msg_iter, WRITE, xdr->bvec, xdr_buf_pagecount(xdr), + xdr->page_len + xdr->page_base); + return xprt_sendmsg(sock, msg, base + xdr->page_base); +} + +/* Common case: + * - stream transport + * - sending from byte 0 of the message + * - the message is wholly contained in @xdr's head iovec + */ +static int xprt_send_rm_and_kvec(struct socket *sock, struct msghdr *msg, + rpc_fraghdr marker, struct kvec *vec, + size_t base) +{ + struct kvec iov[2] = { + [0] = { + .iov_base = &marker, + .iov_len = sizeof(marker) + }, + [1] = *vec, + }; + size_t len = iov[0].iov_len + iov[1].iov_len; + + iov_iter_kvec(&msg->msg_iter, WRITE, iov, 2, len); + return xprt_sendmsg(sock, msg, base); +} + +/** + * xprt_sock_sendmsg - write an xdr_buf directly to a socket + * @sock: open socket to send on + * @msg: socket message metadata + * @xdr: xdr_buf containing this request + * @base: starting position in the buffer + * @marker: stream record marker field + * @sent_p: return the total number of bytes successfully queued for sending + * + * Return values: + * On success, returns zero and fills in @sent_p. + * %-ENOTSOCK if @sock is not a struct socket. + */ +int xprt_sock_sendmsg(struct socket *sock, struct msghdr *msg, + struct xdr_buf *xdr, unsigned int base, + rpc_fraghdr marker, unsigned int *sent_p) +{ + unsigned int rmsize = marker ? sizeof(marker) : 0; + unsigned int remainder = rmsize + xdr->len - base; + unsigned int want; + int err = 0; + + *sent_p = 0; + + if (unlikely(!sock)) + return -ENOTSOCK; + + msg->msg_flags |= MSG_MORE; + want = xdr->head[0].iov_len + rmsize; + if (base < want) { + unsigned int len = want - base; + + remainder -= len; + if (remainder == 0) + msg->msg_flags &= ~MSG_MORE; + if (rmsize) + err = xprt_send_rm_and_kvec(sock, msg, marker, + &xdr->head[0], base); + else + err = xprt_send_kvec(sock, msg, &xdr->head[0], base); + if (remainder == 0 || err != len) + goto out; + *sent_p += err; + base = 0; + } else { + base -= want; + } + + if (base < xdr->page_len) { + unsigned int len = xdr->page_len - base; + + remainder -= len; + if (remainder == 0) + msg->msg_flags &= ~MSG_MORE; + err = xprt_send_pagedata(sock, msg, xdr, base); + if (remainder == 0 || err != len) + goto out; + *sent_p += err; + base = 0; + } else { + base -= xdr->page_len; + } + + if (base >= xdr->tail[0].iov_len) + return 0; + msg->msg_flags &= ~MSG_MORE; + err = xprt_send_kvec(sock, msg, &xdr->tail[0], base); +out: + if (err > 0) { + *sent_p += err; + err = 0; + } + return err; +} diff --git a/net/sunrpc/socklib.h b/net/sunrpc/socklib.h new file mode 100644 index 000000000000..c48114ad6f00 --- /dev/null +++ b/net/sunrpc/socklib.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 1995-1997 Olaf Kirch + * Copyright (C) 2020, Oracle. + */ + +#ifndef _NET_SUNRPC_SOCKLIB_H_ +#define _NET_SUNRPC_SOCKLIB_H_ + +int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb); +int xprt_sock_sendmsg(struct socket *sock, struct msghdr *msg, + struct xdr_buf *xdr, unsigned int base, + rpc_fraghdr marker, unsigned int *sent_p); + +#endif /* _NET_SUNRPC_SOCKLIB_H_ */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 758ab10690de..1cc5c224392b 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -55,6 +55,7 @@ #include #include +#include "socklib.h" #include "sunrpc.h" #define RPCDBG_FACILITY RPCDBG_SVCXPRT diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index d86c664ea6af..1a7c0856c5b6 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -54,6 +54,7 @@ #include +#include "socklib.h" #include "sunrpc.h" static void xs_close(struct rpc_xprt *xprt); @@ -749,125 +750,6 @@ xs_stream_start_connect(struct sock_xprt *transport) #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) -static int xs_sendmsg(struct socket *sock, struct msghdr *msg, size_t seek) -{ - if (seek) - iov_iter_advance(&msg->msg_iter, seek); - return sock_sendmsg(sock, msg); -} - -static int xs_send_kvec(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t seek) -{ - iov_iter_kvec(&msg->msg_iter, WRITE, vec, 1, vec->iov_len); - return xs_sendmsg(sock, msg, seek); -} - -static int xs_send_pagedata(struct socket *sock, struct msghdr *msg, struct xdr_buf *xdr, size_t base) -{ - int err; - - err = xdr_alloc_bvec(xdr, GFP_KERNEL); - if (err < 0) - return err; - - iov_iter_bvec(&msg->msg_iter, WRITE, xdr->bvec, - xdr_buf_pagecount(xdr), - xdr->page_len + xdr->page_base); - return xs_sendmsg(sock, msg, base + xdr->page_base); -} - -#define xs_record_marker_len() sizeof(rpc_fraghdr) - -/* Common case: - * - stream transport - * - sending from byte 0 of the message - * - the message is wholly contained in @xdr's head iovec - */ -static int xs_send_rm_and_kvec(struct socket *sock, struct msghdr *msg, - rpc_fraghdr marker, struct kvec *vec, size_t base) -{ - struct kvec iov[2] = { - [0] = { - .iov_base = &marker, - .iov_len = sizeof(marker) - }, - [1] = *vec, - }; - size_t len = iov[0].iov_len + iov[1].iov_len; - - iov_iter_kvec(&msg->msg_iter, WRITE, iov, 2, len); - return xs_sendmsg(sock, msg, base); -} - -/** - * xs_sendpages - write pages directly to a socket - * @sock: socket to send on - * @addr: UDP only -- address of destination - * @addrlen: UDP only -- length of destination address - * @xdr: buffer containing this request - * @base: starting position in the buffer - * @rm: stream record marker field - * @sent_p: return the total number of bytes successfully queued for sending - * - */ -static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, rpc_fraghdr rm, int *sent_p) -{ - struct msghdr msg = { - .msg_name = addr, - .msg_namelen = addrlen, - .msg_flags = XS_SENDMSG_FLAGS | MSG_MORE, - }; - unsigned int rmsize = rm ? sizeof(rm) : 0; - unsigned int remainder = rmsize + xdr->len - base; - unsigned int want; - int err = 0; - - if (unlikely(!sock)) - return -ENOTSOCK; - - want = xdr->head[0].iov_len + rmsize; - if (base < want) { - unsigned int len = want - base; - remainder -= len; - if (remainder == 0) - msg.msg_flags &= ~MSG_MORE; - if (rmsize) - err = xs_send_rm_and_kvec(sock, &msg, rm, - &xdr->head[0], base); - else - err = xs_send_kvec(sock, &msg, &xdr->head[0], base); - if (remainder == 0 || err != len) - goto out; - *sent_p += err; - base = 0; - } else - base -= want; - - if (base < xdr->page_len) { - unsigned int len = xdr->page_len - base; - remainder -= len; - if (remainder == 0) - msg.msg_flags &= ~MSG_MORE; - err = xs_send_pagedata(sock, &msg, xdr, base); - if (remainder == 0 || err != len) - goto out; - *sent_p += err; - base = 0; - } else - base -= xdr->page_len; - - if (base >= xdr->tail[0].iov_len) - return 0; - msg.msg_flags &= ~MSG_MORE; - err = xs_send_kvec(sock, &msg, &xdr->tail[0], base); -out: - if (err > 0) { - *sent_p += err; - err = 0; - } - return err; -} - /** * xs_nospace - handle transmit was incomplete * @req: pointer to RPC request @@ -959,8 +841,11 @@ static int xs_local_send_request(struct rpc_rqst *req) struct xdr_buf *xdr = &req->rq_snd_buf; rpc_fraghdr rm = xs_stream_record_marker(xdr); unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen; + struct msghdr msg = { + .msg_flags = XS_SENDMSG_FLAGS, + }; + unsigned int uninitialized_var(sent); int status; - int sent = 0; /* Close the stream if the previous transmission was incomplete */ if (xs_send_request_was_aborted(transport, req)) { @@ -972,8 +857,8 @@ static int xs_local_send_request(struct rpc_rqst *req) req->rq_svec->iov_base, req->rq_svec->iov_len); req->rq_xtime = ktime_get(); - status = xs_sendpages(transport->sock, NULL, 0, xdr, - transport->xmit.offset, rm, &sent); + status = xprt_sock_sendmsg(transport->sock, &msg, xdr, + transport->xmit.offset, rm, &sent); dprintk("RPC: %s(%u) = %d\n", __func__, xdr->len - transport->xmit.offset, status); @@ -1025,7 +910,12 @@ static int xs_udp_send_request(struct rpc_rqst *req) struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; - int sent = 0; + struct msghdr msg = { + .msg_name = xs_addr(xprt), + .msg_namelen = xprt->addrlen, + .msg_flags = XS_SENDMSG_FLAGS, + }; + unsigned int uninitialized_var(sent); int status; xs_pktdump("packet data:", @@ -1039,8 +929,7 @@ static int xs_udp_send_request(struct rpc_rqst *req) return -EBADSLT; req->rq_xtime = ktime_get(); - status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen, - xdr, 0, 0, &sent); + status = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, 0, &sent); dprintk("RPC: xs_udp_send_request(%u) = %d\n", xdr->len, status); @@ -1106,9 +995,12 @@ static int xs_tcp_send_request(struct rpc_rqst *req) struct xdr_buf *xdr = &req->rq_snd_buf; rpc_fraghdr rm = xs_stream_record_marker(xdr); unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen; + struct msghdr msg = { + .msg_flags = XS_SENDMSG_FLAGS, + }; bool vm_wait = false; + unsigned int uninitialized_var(sent); int status; - int sent; /* Close the stream if the previous transmission was incomplete */ if (xs_send_request_was_aborted(transport, req)) { @@ -1129,9 +1021,8 @@ static int xs_tcp_send_request(struct rpc_rqst *req) * called sendmsg(). */ req->rq_xtime = ktime_get(); while (1) { - sent = 0; - status = xs_sendpages(transport->sock, NULL, 0, xdr, - transport->xmit.offset, rm, &sent); + status = xprt_sock_sendmsg(transport->sock, &msg, xdr, + transport->xmit.offset, rm, &sent); dprintk("RPC: xs_tcp_send_request(%u) = %d\n", xdr->len - transport->xmit.offset, status); From da1661b93bf489cdbc8bcea919b165d31b4810bf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Mar 2020 15:20:33 -0500 Subject: [PATCH 372/809] SUNRPC: Teach server to use xprt_sock_sendmsg for socket sends xprt_sock_sendmsg uses the more efficient iov_iter-enabled kernel socket API, and is a pre-requisite for server send-side support for TLS. Note that svc_process no longer needs to reserve a word for the stream record marker, since the TCP transport now provides the record marker automatically in a separate buffer. The dprintk() in svc_send_common is also removed. It didn't seem crucial for field troubleshooting. If more is needed there, a trace point could be added in xprt_sock_sendmsg(). Signed-off-by: Chuck Lever --- net/sunrpc/sunrpc.h | 4 - net/sunrpc/svc.c | 4 - net/sunrpc/svcsock.c | 199 +++++++++++++----------------------------- net/sunrpc/xprtsock.c | 39 ++------- 4 files changed, 71 insertions(+), 175 deletions(-) diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index c9bacb3c930f..47a756503d11 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -50,10 +50,6 @@ static inline int sock_is_loopback(struct sock *sk) return loopback; } -int svc_send_common(struct socket *sock, struct xdr_buf *xdr, - struct page *headpage, unsigned long headoffset, - struct page *tailpage, unsigned long tailoffset); - int rpc_clients_notifier_register(void); void rpc_clients_notifier_unregister(void); #endif /* _NET_SUNRPC_SUNRPC_H */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 18676d36f490..9ed3126600ce 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1529,10 +1529,6 @@ svc_process(struct svc_rqst *rqstp) goto out_drop; } - /* Reserve space for the record marker */ - if (rqstp->rq_prot == IPPROTO_TCP) - svc_putnl(resv, 0); - /* Returns 1 for send, 0 for drop */ if (likely(svc_process_common(rqstp, argv, resv))) return svc_send(rqstp); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1cc5c224392b..519cf9c4f8fd 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -175,111 +175,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) } } -/* - * send routine intended to be shared by the fore- and back-channel - */ -int svc_send_common(struct socket *sock, struct xdr_buf *xdr, - struct page *headpage, unsigned long headoffset, - struct page *tailpage, unsigned long tailoffset) -{ - int result; - int size; - struct page **ppage = xdr->pages; - size_t base = xdr->page_base; - unsigned int pglen = xdr->page_len; - unsigned int flags = MSG_MORE | MSG_SENDPAGE_NOTLAST; - int slen; - int len = 0; - - slen = xdr->len; - - /* send head */ - if (slen == xdr->head[0].iov_len) - flags = 0; - len = kernel_sendpage(sock, headpage, headoffset, - xdr->head[0].iov_len, flags); - if (len != xdr->head[0].iov_len) - goto out; - slen -= xdr->head[0].iov_len; - if (slen == 0) - goto out; - - /* send page data */ - size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen; - while (pglen > 0) { - if (slen == size) - flags = 0; - result = kernel_sendpage(sock, *ppage, base, size, flags); - if (result > 0) - len += result; - if (result != size) - goto out; - slen -= size; - pglen -= size; - size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen; - base = 0; - ppage++; - } - - /* send tail */ - if (xdr->tail[0].iov_len) { - result = kernel_sendpage(sock, tailpage, tailoffset, - xdr->tail[0].iov_len, 0); - if (result > 0) - len += result; - } - -out: - return len; -} - - -/* - * Generic sendto routine - */ -static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) -{ - struct svc_sock *svsk = - container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); - struct socket *sock = svsk->sk_sock; - union { - struct cmsghdr hdr; - long all[SVC_PKTINFO_SPACE / sizeof(long)]; - } buffer; - struct cmsghdr *cmh = &buffer.hdr; - int len = 0; - unsigned long tailoff; - unsigned long headoff; - RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); - - if (rqstp->rq_prot == IPPROTO_UDP) { - struct msghdr msg = { - .msg_name = &rqstp->rq_addr, - .msg_namelen = rqstp->rq_addrlen, - .msg_control = cmh, - .msg_controllen = sizeof(buffer), - .msg_flags = MSG_MORE, - }; - - svc_set_cmsg_data(rqstp, cmh); - - if (sock_sendmsg(sock, &msg) < 0) - goto out; - } - - tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1); - headoff = 0; - len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff, - rqstp->rq_respages[0], tailoff); - -out: - dprintk("svc: socket %p sendto([%p %zu... ], %d) = %d (addr %s)\n", - svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, - xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf))); - - return len; -} - static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset, unsigned int length) { @@ -607,17 +502,43 @@ out_free: return 0; } -static int -svc_udp_sendto(struct svc_rqst *rqstp) +/** + * svc_udp_sendto - Send out a reply on a UDP socket + * @rqstp: completed svc_rqst + * + * Returns the number of bytes sent, or a negative errno. + */ +static int svc_udp_sendto(struct svc_rqst *rqstp) { - int error; + struct svc_xprt *xprt = rqstp->rq_xprt; + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); + struct xdr_buf *xdr = &rqstp->rq_res; + union { + struct cmsghdr hdr; + long all[SVC_PKTINFO_SPACE / sizeof(long)]; + } buffer; + struct cmsghdr *cmh = &buffer.hdr; + struct msghdr msg = { + .msg_name = &rqstp->rq_addr, + .msg_namelen = rqstp->rq_addrlen, + .msg_control = cmh, + .msg_controllen = sizeof(buffer), + }; + unsigned int uninitialized_var(sent); + int err; - error = svc_sendto(rqstp, &rqstp->rq_res); - if (error == -ECONNREFUSED) + svc_set_cmsg_data(rqstp, cmh); + + err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent); + xdr_free_bvec(xdr); + if (err == -ECONNREFUSED) { /* ICMP error on earlier request. */ - error = svc_sendto(rqstp, &rqstp->rq_res); - - return error; + err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent); + xdr_free_bvec(xdr); + } + if (err < 0) + return err; + return sent; } static int svc_udp_has_wspace(struct svc_xprt *xprt) @@ -1136,35 +1057,39 @@ err_noclose: return 0; /* record not complete */ } -/* - * Send out data on TCP socket. +/** + * svc_tcp_sendto - Send out a reply on a TCP socket + * @rqstp: completed svc_rqst + * + * Returns the number of bytes sent, or a negative errno. */ static int svc_tcp_sendto(struct svc_rqst *rqstp) { - struct xdr_buf *xbufp = &rqstp->rq_res; - int sent; - __be32 reclen; + struct svc_xprt *xprt = rqstp->rq_xprt; + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); + struct xdr_buf *xdr = &rqstp->rq_res; + rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | + (u32)xdr->len); + struct msghdr msg = { + .msg_flags = 0, + }; + unsigned int uninitialized_var(sent); + int err; - /* Set up the first element of the reply kvec. - * Any other kvecs that may be in use have been taken - * care of by the server implementation itself. - */ - reclen = htonl(0x80000000|((xbufp->len ) - 4)); - memcpy(xbufp->head[0].iov_base, &reclen, 4); - - sent = svc_sendto(rqstp, &rqstp->rq_res); - if (sent != xbufp->len) { - printk(KERN_NOTICE - "rpc-srv/tcp: %s: %s %d when sending %d bytes " - "- shutting down socket\n", - rqstp->rq_xprt->xpt_server->sv_name, - (sent<0)?"got error":"sent only", - sent, xbufp->len); - set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags); - svc_xprt_enqueue(rqstp->rq_xprt); - sent = -EAGAIN; - } + err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent); + xdr_free_bvec(xdr); + if (err < 0 || sent != (xdr->len + sizeof(marker))) + goto out_close; return sent; + +out_close: + pr_notice("rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n", + xprt->xpt_server->sv_name, + (err < 0) ? "got error" : "sent", + (err < 0) ? err : sent, xdr->len); + set_bit(XPT_CLOSE, &xprt->xpt_flags); + svc_xprt_enqueue(xprt); + return -EAGAIN; } static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 1a7c0856c5b6..17cb902e5153 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2527,46 +2527,25 @@ static void bc_free(struct rpc_task *task) free_page((unsigned long)buf); } -/* - * Use the svc_sock to send the callback. Must be called with svsk->sk_mutex - * held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request. - */ static int bc_sendto(struct rpc_rqst *req) { - int len; - struct xdr_buf *xbufp = &req->rq_snd_buf; + struct xdr_buf *xdr = &req->rq_snd_buf; struct sock_xprt *transport = container_of(req->rq_xprt, struct sock_xprt, xprt); - unsigned long headoff; - unsigned long tailoff; - struct page *tailpage; struct msghdr msg = { - .msg_flags = MSG_MORE + .msg_flags = 0, }; rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | - (u32)xbufp->len); - struct kvec iov = { - .iov_base = &marker, - .iov_len = sizeof(marker), - }; + (u32)xdr->len); + unsigned int sent = 0; + int err; req->rq_xtime = ktime_get(); - - len = kernel_sendmsg(transport->sock, &msg, &iov, 1, iov.iov_len); - if (len != iov.iov_len) + err = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, marker, &sent); + xdr_free_bvec(xdr); + if (err < 0 || sent != (xdr->len + sizeof(marker))) return -EAGAIN; - - tailpage = NULL; - if (xbufp->tail[0].iov_len) - tailpage = virt_to_page(xbufp->tail[0].iov_base); - tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK; - headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK; - len = svc_send_common(transport->sock, xbufp, - virt_to_page(xbufp->head[0].iov_base), headoff, - tailpage, tailoff); - if (len != xbufp->len) - return -EAGAIN; - return len; + return sent; } /* From a451b12311aa8c96c6f6e01c783a86995dc3ec6b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:38 -0500 Subject: [PATCH 373/809] nfsd: Don't add locks to closed or closing open stateids In NFSv4, the lock stateids are tied to the lockowner, and the open stateid, so that the action of closing the file also results in either an automatic loss of the locks, or an error of the form NFS4ERR_LOCKS_HELD. In practice this means we must not add new locks to the open stateid after the close process has been invoked. In fact doing so, can result in the following panic: kernel BUG at lib/list_debug.c:51! invalid opcode: 0000 [#1] SMP NOPTI CPU: 2 PID: 1085 Comm: nfsd Not tainted 5.6.0-rc3+ #2 Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.14410784.B64.1908150010 08/15/2019 RIP: 0010:__list_del_entry_valid.cold+0x31/0x55 Code: 1a 3d 9b e8 74 10 c2 ff 0f 0b 48 c7 c7 f0 1a 3d 9b e8 66 10 c2 ff 0f 0b 48 89 f2 48 89 fe 48 c7 c7 b0 1a 3d 9b e8 52 10 c2 ff <0f> 0b 48 89 fe 4c 89 c2 48 c7 c7 78 1a 3d 9b e8 3e 10 c2 ff 0f 0b RSP: 0018:ffffb296c1d47d90 EFLAGS: 00010246 RAX: 0000000000000054 RBX: ffff8ba032456ec8 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff8ba039e99cc8 RDI: ffff8ba039e99cc8 RBP: ffff8ba032456e60 R08: 0000000000000781 R09: 0000000000000003 R10: 0000000000000000 R11: 0000000000000001 R12: ffff8ba009a4abe0 R13: ffff8ba032456e8c R14: 0000000000000000 R15: ffff8ba00adb01d8 FS: 0000000000000000(0000) GS:ffff8ba039e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fb213f0b008 CR3: 00000001347de006 CR4: 00000000003606e0 Call Trace: release_lock_stateid+0x2b/0x80 [nfsd] nfsd4_free_stateid+0x1e9/0x210 [nfsd] nfsd4_proc_compound+0x414/0x700 [nfsd] ? nfs4svc_decode_compoundargs+0x407/0x4c0 [nfsd] nfsd_dispatch+0xc1/0x200 [nfsd] svc_process_common+0x476/0x6f0 [sunrpc] ? svc_sock_secure_port+0x12/0x30 [sunrpc] ? svc_recv+0x313/0x9c0 [sunrpc] ? nfsd_svc+0x2d0/0x2d0 [nfsd] svc_process+0xd4/0x110 [sunrpc] nfsd+0xe3/0x140 [nfsd] kthread+0xf9/0x130 ? nfsd_destroy+0x50/0x50 [nfsd] ? kthread_park+0x90/0x90 ret_from_fork+0x1f/0x40 The fix is to ensure that lock creation tests for whether or not the open stateid is unhashed, and to fail if that is the case. Fixes: 659aefb68eca ("nfsd: Ensure we don't recognise lock stateids after freeing them") Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 73 ++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c1f347bbf8f4..169829db2817 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -494,6 +494,8 @@ find_any_file(struct nfs4_file *f) { struct nfsd_file *ret; + if (!f) + return NULL; spin_lock(&f->fi_lock); ret = __nfs4_get_fd(f, O_RDWR); if (!ret) { @@ -1309,6 +1311,12 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop) nfs4_free_stateowner(sop); } +static bool +nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) +{ + return list_empty(&stp->st_perfile); +} + static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_file *fp = stp->st_stid.sc_file; @@ -1379,9 +1387,11 @@ static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) { lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); + if (!unhash_ol_stateid(stp)) + return false; list_del_init(&stp->st_locks); nfs4_unhash_stid(&stp->st_stid); - return unhash_ol_stateid(stp); + return true; } static void release_lock_stateid(struct nfs4_ol_stateid *stp) @@ -1446,13 +1456,12 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, struct list_head *reaplist) { - bool unhashed; - lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); - unhashed = unhash_ol_stateid(stp); + if (!unhash_ol_stateid(stp)) + return false; release_open_stateid_locks(stp, reaplist); - return unhashed; + return true; } static void release_open_stateid(struct nfs4_ol_stateid *stp) @@ -6394,21 +6403,21 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, } static struct nfs4_ol_stateid * -find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) +find_lock_stateid(const struct nfs4_lockowner *lo, + const struct nfs4_ol_stateid *ost) { struct nfs4_ol_stateid *lst; - struct nfs4_client *clp = lo->lo_owner.so_client; - lockdep_assert_held(&clp->cl_lock); + lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); - list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { - if (lst->st_stid.sc_type != NFS4_LOCK_STID) - continue; - if (lst->st_stid.sc_file == fp) { - refcount_inc(&lst->st_stid.sc_count); - return lst; + /* If ost is not hashed, ost->st_locks will not be valid */ + if (!nfs4_ol_stateid_unhashed(ost)) + list_for_each_entry(lst, &ost->st_locks, st_locks) { + if (lst->st_stateowner == &lo->lo_owner) { + refcount_inc(&lst->st_stid.sc_count); + return lst; + } } - } return NULL; } @@ -6424,11 +6433,11 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); retry: spin_lock(&clp->cl_lock); - spin_lock(&fp->fi_lock); - retstp = find_lock_stateid(lo, fp); + if (nfs4_ol_stateid_unhashed(open_stp)) + goto out_close; + retstp = find_lock_stateid(lo, open_stp); if (retstp) - goto out_unlock; - + goto out_found; refcount_inc(&stp->st_stid.sc_count); stp->st_stid.sc_type = NFS4_LOCK_STID; stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); @@ -6437,22 +6446,26 @@ retry: stp->st_access_bmap = 0; stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_openstp = open_stp; + spin_lock(&fp->fi_lock); list_add(&stp->st_locks, &open_stp->st_locks); list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); list_add(&stp->st_perfile, &fp->fi_stateids); -out_unlock: spin_unlock(&fp->fi_lock); spin_unlock(&clp->cl_lock); - if (retstp) { - if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { - nfs4_put_stid(&retstp->st_stid); - goto retry; - } - /* To keep mutex tracking happy */ - mutex_unlock(&stp->st_mutex); - stp = retstp; - } return stp; +out_found: + spin_unlock(&clp->cl_lock); + if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { + nfs4_put_stid(&retstp->st_stid); + goto retry; + } + /* To keep mutex tracking happy */ + mutex_unlock(&stp->st_mutex); + return retstp; +out_close: + spin_unlock(&clp->cl_lock); + mutex_unlock(&stp->st_mutex); + return NULL; } static struct nfs4_ol_stateid * @@ -6467,7 +6480,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, *new = false; spin_lock(&clp->cl_lock); - lst = find_lock_stateid(lo, fi); + lst = find_lock_stateid(lo, ost); spin_unlock(&clp->cl_lock); if (lst != NULL) { if (nfsd4_lock_ol_stateid(lst) == nfs_ok) From f01274a9335307eca729b5d12609976afcf21530 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:39 -0500 Subject: [PATCH 374/809] nfsd: Add tracing to nfsd_set_fh_dentry() Add tracing to allow us to figure out where any stale filehandle issues may be originating from. Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- fs/nfsd/nfsfh.c | 13 ++++++++++--- fs/nfsd/trace.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index b319080288c3..37bc8f5f4514 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -14,6 +14,7 @@ #include "nfsd.h" #include "vfs.h" #include "auth.h" +#include "trace.h" #define NFSDDBG_FACILITY NFSDDBG_FH @@ -209,11 +210,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) } error = nfserr_stale; - if (PTR_ERR(exp) == -ENOENT) - return error; + if (IS_ERR(exp)) { + trace_nfsd_set_fh_dentry_badexport(rqstp, fhp, PTR_ERR(exp)); + + if (PTR_ERR(exp) == -ENOENT) + return error; - if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); + } if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) { /* Elevate privileges so that the lack of 'r' or 'x' @@ -267,6 +271,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, data_left, fileid_type, nfsd_acceptable, exp); + if (IS_ERR_OR_NULL(dentry)) + trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp, + dentry ? PTR_ERR(dentry) : -ESTALE); } if (dentry == NULL) goto out; diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 06dd0d337049..9abd1591a841 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -50,6 +50,36 @@ TRACE_EVENT(nfsd_compound_status, __get_str(name), __entry->status) ) +DECLARE_EVENT_CLASS(nfsd_fh_err_class, + TP_PROTO(struct svc_rqst *rqstp, + struct svc_fh *fhp, + int status), + TP_ARGS(rqstp, fhp, status), + TP_STRUCT__entry( + __field(u32, xid) + __field(u32, fh_hash) + __field(int, status) + ), + TP_fast_assign( + __entry->xid = be32_to_cpu(rqstp->rq_xid); + __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle); + __entry->status = status; + ), + TP_printk("xid=0x%08x fh_hash=0x%08x status=%d", + __entry->xid, __entry->fh_hash, + __entry->status) +) + +#define DEFINE_NFSD_FH_ERR_EVENT(name) \ +DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \ + TP_PROTO(struct svc_rqst *rqstp, \ + struct svc_fh *fhp, \ + int status), \ + TP_ARGS(rqstp, fhp, status)) + +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport); +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle); + DECLARE_EVENT_CLASS(nfsd_io_class, TP_PROTO(struct svc_rqst *rqstp, struct svc_fh *fhp, From cf749f3cc734c459e835bb1cbfcadbce3c03291c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:40 -0500 Subject: [PATCH 375/809] nfsd: Add tracepoints for exp_find_key() and exp_get_by_name() Add tracepoints for upcalls. Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- fs/nfsd/export.c | 9 +++++++-- fs/nfsd/trace.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 15422c951fd1..e867db0bb380 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -23,6 +23,7 @@ #include "netns.h" #include "pnfs.h" #include "filecache.h" +#include "trace.h" #define NFSDDBG_FACILITY NFSDDBG_EXPORT @@ -832,8 +833,10 @@ exp_find_key(struct cache_detail *cd, struct auth_domain *clp, int fsid_type, if (ek == NULL) return ERR_PTR(-ENOMEM); err = cache_check(cd, &ek->h, reqp); - if (err) + if (err) { + trace_nfsd_exp_find_key(&key, err); return ERR_PTR(err); + } return ek; } @@ -855,8 +858,10 @@ exp_get_by_name(struct cache_detail *cd, struct auth_domain *clp, if (exp == NULL) return ERR_PTR(-ENOMEM); err = cache_check(cd, &exp->h, reqp); - if (err) + if (err) { + trace_nfsd_exp_get_by_name(&key, err); return ERR_PTR(err); + } return exp; } diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 9abd1591a841..3b9277d7b5f2 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -9,6 +9,7 @@ #define _NFSD_TRACE_H #include +#include "export.h" #include "nfsfh.h" TRACE_EVENT(nfsd_compound, @@ -80,6 +81,51 @@ DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \ DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport); DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle); +TRACE_EVENT(nfsd_exp_find_key, + TP_PROTO(const struct svc_expkey *key, + int status), + TP_ARGS(key, status), + TP_STRUCT__entry( + __field(int, fsidtype) + __array(u32, fsid, 6) + __string(auth_domain, key->ek_client->name) + __field(int, status) + ), + TP_fast_assign( + __entry->fsidtype = key->ek_fsidtype; + memcpy(__entry->fsid, key->ek_fsid, 4*6); + __assign_str(auth_domain, key->ek_client->name); + __entry->status = status; + ), + TP_printk("fsid=%x::%s domain=%s status=%d", + __entry->fsidtype, + __print_array(__entry->fsid, 6, 4), + __get_str(auth_domain), + __entry->status + ) +); + +TRACE_EVENT(nfsd_exp_get_by_name, + TP_PROTO(const struct svc_export *key, + int status), + TP_ARGS(key, status), + TP_STRUCT__entry( + __string(path, key->ex_path.dentry->d_name.name) + __string(auth_domain, key->ex_client->name) + __field(int, status) + ), + TP_fast_assign( + __assign_str(path, key->ex_path.dentry->d_name.name); + __assign_str(auth_domain, key->ex_client->name); + __entry->status = status; + ), + TP_printk("path=%s domain=%s status=%d", + __get_str(path), + __get_str(auth_domain), + __entry->status + ) +); + DECLARE_EVENT_CLASS(nfsd_io_class, TP_PROTO(struct svc_rqst *rqstp, struct svc_fh *fhp, From 6a30e47fa0c358cc84002e6a429f5f229e0b7b07 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:41 -0500 Subject: [PATCH 376/809] nfsd: Add tracepoints for update of the expkey and export cache entries Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- fs/nfsd/export.c | 24 +++++++++++++++--------- fs/nfsd/trace.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index e867db0bb380..6e6cbeb7ac2b 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -141,7 +141,9 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) if (len == 0) { set_bit(CACHE_NEGATIVE, &key.h.flags); ek = svc_expkey_update(cd, &key, ek); - if (!ek) + if (ek) + trace_nfsd_expkey_update(ek, NULL); + else err = -ENOMEM; } else { err = kern_path(buf, 0, &key.ek_path); @@ -151,7 +153,9 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) dprintk("Found the path %s\n", buf); ek = svc_expkey_update(cd, &key, ek); - if (!ek) + if (ek) + trace_nfsd_expkey_update(ek, buf); + else err = -ENOMEM; path_put(&key.ek_path); } @@ -644,15 +648,17 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) } expp = svc_export_lookup(&exp); - if (expp) - expp = svc_export_update(&exp, expp); - else + if (!expp) { err = -ENOMEM; - cache_flush(); - if (expp == NULL) - err = -ENOMEM; - else + goto out4; + } + expp = svc_export_update(&exp, expp); + if (expp) { + trace_nfsd_export_update(expp); + cache_flush(); exp_put(expp); + } else + err = -ENOMEM; out4: nfsd4_fslocs_free(&exp.ex_fslocs); kfree(exp.ex_uuid); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 3b9277d7b5f2..78c574251c60 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -105,6 +105,32 @@ TRACE_EVENT(nfsd_exp_find_key, ) ); +TRACE_EVENT(nfsd_expkey_update, + TP_PROTO(const struct svc_expkey *key, const char *exp_path), + TP_ARGS(key, exp_path), + TP_STRUCT__entry( + __field(int, fsidtype) + __array(u32, fsid, 6) + __string(auth_domain, key->ek_client->name) + __string(path, exp_path) + __field(bool, cache) + ), + TP_fast_assign( + __entry->fsidtype = key->ek_fsidtype; + memcpy(__entry->fsid, key->ek_fsid, 4*6); + __assign_str(auth_domain, key->ek_client->name); + __assign_str(path, exp_path); + __entry->cache = !test_bit(CACHE_NEGATIVE, &key->h.flags); + ), + TP_printk("fsid=%x::%s domain=%s path=%s cache=%s", + __entry->fsidtype, + __print_array(__entry->fsid, 6, 4), + __get_str(auth_domain), + __get_str(path), + __entry->cache ? "pos" : "neg" + ) +); + TRACE_EVENT(nfsd_exp_get_by_name, TP_PROTO(const struct svc_export *key, int status), @@ -126,6 +152,26 @@ TRACE_EVENT(nfsd_exp_get_by_name, ) ); +TRACE_EVENT(nfsd_export_update, + TP_PROTO(const struct svc_export *key), + TP_ARGS(key), + TP_STRUCT__entry( + __string(path, key->ex_path.dentry->d_name.name) + __string(auth_domain, key->ex_client->name) + __field(bool, cache) + ), + TP_fast_assign( + __assign_str(path, key->ex_path.dentry->d_name.name); + __assign_str(auth_domain, key->ex_client->name); + __entry->cache = !test_bit(CACHE_NEGATIVE, &key->h.flags); + ), + TP_printk("path=%s domain=%s cache=%s", + __get_str(path), + __get_str(auth_domain), + __entry->cache ? "pos" : "neg" + ) +); + DECLARE_EVENT_CLASS(nfsd_io_class, TP_PROTO(struct svc_rqst *rqstp, struct svc_fh *fhp, From 65286b883c6de6b30928c837c47c167e82bde0b2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:42 -0500 Subject: [PATCH 377/809] nfsd: export upcalls must not return ESTALE when mountd is down If the rpc.mountd daemon goes down, then that should not cause all exports to start failing with ESTALE errors. Let's explicitly distinguish between the cache upcall cases that need to time out, and those that do not. Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- fs/nfs/dns_resolve.c | 11 ++++--- fs/nfsd/export.c | 12 +++++++ fs/nfsd/nfs4idmap.c | 14 ++++++++ include/linux/sunrpc/cache.h | 3 ++ net/sunrpc/auth_gss/svcauth_gss.c | 12 +++++++ net/sunrpc/cache.c | 53 +++++++++++++++---------------- net/sunrpc/svcauth_unix.c | 12 +++++++ 7 files changed, 85 insertions(+), 32 deletions(-) diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 89bd5581f317..963800037609 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c @@ -152,12 +152,13 @@ static int nfs_dns_upcall(struct cache_detail *cd, struct cache_head *ch) { struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); - int ret; - ret = nfs_cache_upcall(cd, key->hostname); - if (ret) - ret = sunrpc_cache_pipe_upcall(cd, ch); - return ret; + if (test_and_set_bit(CACHE_PENDING, &ch->flags)) + return 0; + if (!nfs_cache_upcall(cd, key->hostname)) + return 0; + clear_bit(CACHE_PENDING, &ch->flags); + return sunrpc_cache_pipe_upcall_timeout(cd, ch); } static int nfs_dns_match(struct cache_head *ca, diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 6e6cbeb7ac2b..cb777fe82988 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -51,6 +51,11 @@ static void expkey_put(struct kref *ref) kfree_rcu(key, ek_rcu); } +static int expkey_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h); +} + static void expkey_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) @@ -254,6 +259,7 @@ static const struct cache_detail svc_expkey_cache_template = { .hash_size = EXPKEY_HASHMAX, .name = "nfsd.fh", .cache_put = expkey_put, + .cache_upcall = expkey_upcall, .cache_request = expkey_request, .cache_parse = expkey_parse, .cache_show = expkey_show, @@ -335,6 +341,11 @@ static void svc_export_put(struct kref *ref) kfree_rcu(exp, ex_rcu); } +static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h); +} + static void svc_export_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) @@ -774,6 +785,7 @@ static const struct cache_detail svc_export_cache_template = { .hash_size = EXPORT_HASHMAX, .name = "nfsd.export", .cache_put = svc_export_put, + .cache_upcall = svc_export_upcall, .cache_request = svc_export_request, .cache_parse = svc_export_parse, .cache_show = svc_export_show, diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index d1f285245af8..9460be8a8321 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -122,6 +122,12 @@ idtoname_hash(struct ent *ent) return hash; } +static int +idtoname_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall_timeout(cd, h); +} + static void idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, int *blen) @@ -184,6 +190,7 @@ static const struct cache_detail idtoname_cache_template = { .hash_size = ENT_HASHMAX, .name = "nfs4.idtoname", .cache_put = ent_put, + .cache_upcall = idtoname_upcall, .cache_request = idtoname_request, .cache_parse = idtoname_parse, .cache_show = idtoname_show, @@ -295,6 +302,12 @@ nametoid_hash(struct ent *ent) return hash_str(ent->name, ENT_HASHBITS); } +static int +nametoid_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall_timeout(cd, h); +} + static void nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, int *blen) @@ -347,6 +360,7 @@ static const struct cache_detail nametoid_cache_template = { .hash_size = ENT_HASHMAX, .name = "nfs4.nametoid", .cache_put = ent_put, + .cache_upcall = nametoid_upcall, .cache_request = nametoid_request, .cache_parse = nametoid_parse, .cache_show = nametoid_show, diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 0f64de7caa39..656882a50991 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -179,6 +179,9 @@ sunrpc_cache_update(struct cache_detail *detail, extern int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h); +extern int +sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail, + struct cache_head *h); extern void cache_clean_deferred(void *owner); diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index e93f06ec180d..54ae5be62f6a 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -180,6 +180,11 @@ static struct cache_head *rsi_alloc(void) return NULL; } +static int rsi_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall_timeout(cd, h); +} + static void rsi_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) @@ -278,6 +283,7 @@ static const struct cache_detail rsi_cache_template = { .hash_size = RSI_HASHMAX, .name = "auth.rpcsec.init", .cache_put = rsi_put, + .cache_upcall = rsi_upcall, .cache_request = rsi_request, .cache_parse = rsi_parse, .match = rsi_match, @@ -424,6 +430,11 @@ rsc_alloc(void) return NULL; } +static int rsc_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return -EINVAL; +} + static int rsc_parse(struct cache_detail *cd, char *mesg, int mlen) { @@ -550,6 +561,7 @@ static const struct cache_detail rsc_cache_template = { .hash_size = RSC_HASHMAX, .name = "auth.rpcsec.context", .cache_put = rsc_put, + .cache_upcall = rsc_upcall, .cache_parse = rsc_parse, .match = rsc_match, .init = rsc_init, diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 8a8e3528293c..7f2e5d818e05 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -38,7 +38,6 @@ static bool cache_defer_req(struct cache_req *req, struct cache_head *item); static void cache_revisit_request(struct cache_head *item); -static bool cache_listeners_exist(struct cache_detail *detail); static void cache_init(struct cache_head *h, struct cache_detail *detail) { @@ -225,13 +224,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, } EXPORT_SYMBOL_GPL(sunrpc_cache_update); -static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) -{ - if (cd->cache_upcall) - return cd->cache_upcall(cd, h); - return sunrpc_cache_pipe_upcall(cd, h); -} - static inline int cache_is_valid(struct cache_head *h) { if (!test_bit(CACHE_VALID, &h->flags)) @@ -304,17 +296,14 @@ int cache_check(struct cache_detail *detail, (h->expiry_time != 0 && age > refresh_age/2)) { dprintk("RPC: Want update, refage=%lld, age=%lld\n", refresh_age, age); - if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { - switch (cache_make_upcall(detail, h)) { - case -EINVAL: - rv = try_to_negate_entry(detail, h); - break; - case -EAGAIN: - cache_fresh_unlocked(h, detail); - break; - } - } else if (!cache_listeners_exist(detail)) + switch (detail->cache_upcall(detail, h)) { + case -EINVAL: rv = try_to_negate_entry(detail, h); + break; + case -EAGAIN: + cache_fresh_unlocked(h, detail); + break; + } } if (rv == -EAGAIN) { @@ -1196,20 +1185,12 @@ static bool cache_listeners_exist(struct cache_detail *detail) * * Each request is at most one page long. */ -int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) +static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) { - char *buf; struct cache_request *crq; int ret = 0; - if (!detail->cache_request) - return -EINVAL; - - if (!cache_listeners_exist(detail)) { - warn_no_listener(detail); - return -EINVAL; - } if (test_bit(CACHE_CLEANED, &h->flags)) /* Too late to make an upcall */ return -EAGAIN; @@ -1243,8 +1224,26 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) } return ret; } + +int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) +{ + if (test_and_set_bit(CACHE_PENDING, &h->flags)) + return 0; + return cache_pipe_upcall(detail, h); +} EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); +int sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail, + struct cache_head *h) +{ + if (!cache_listeners_exist(detail)) { + warn_no_listener(detail); + return -EINVAL; + } + return sunrpc_cache_pipe_upcall(detail, h); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall_timeout); + /* * parse a message from user-space and pass it * to an appropriate cache diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 04aa80a2d752..6c8f802c4261 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -148,6 +148,11 @@ static struct cache_head *ip_map_alloc(void) return NULL; } +static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h); +} + static void ip_map_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) @@ -467,6 +472,11 @@ static struct cache_head *unix_gid_alloc(void) return NULL; } +static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall_timeout(cd, h); +} + static void unix_gid_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) @@ -584,6 +594,7 @@ static const struct cache_detail unix_gid_cache_template = { .hash_size = GID_HASHMAX, .name = "auth.unix.gid", .cache_put = unix_gid_put, + .cache_upcall = unix_gid_upcall, .cache_request = unix_gid_request, .cache_parse = unix_gid_parse, .cache_show = unix_gid_show, @@ -881,6 +892,7 @@ static const struct cache_detail ip_map_cache_template = { .hash_size = IP_HASHMAX, .name = "auth.unix.ip", .cache_put = ip_map_put, + .cache_upcall = ip_map_upcall, .cache_request = ip_map_request, .cache_parse = ip_map_parse, .cache_show = ip_map_show, From 277f27e2f27752cd1a7901443d72e908ddea8a2e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:43 -0500 Subject: [PATCH 378/809] SUNRPC/cache: Allow garbage collection of invalid cache entries If the cache entry never gets initialised, we want the garbage collector to be able to evict it. Otherwise if the upcall daemon fails to initialise the entry, we end up never expiring it. Signed-off-by: Trond Myklebust [ cel: resolved a merge conflict ] Signed-off-by: Chuck Lever --- include/linux/sunrpc/cache.h | 3 --- net/sunrpc/cache.c | 36 +++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 656882a50991..532cdbda43da 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -209,9 +209,6 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd) static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h) { - if (!test_bit(CACHE_VALID, &h->flags)) - return false; - return (h->expiry_time < seconds_since_boot()) || (detail->flush_time >= h->last_refresh); } diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 7f2e5d818e05..cd76ef2d26b8 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -64,13 +64,14 @@ static struct cache_head *sunrpc_cache_find_rcu(struct cache_detail *detail, rcu_read_lock(); hlist_for_each_entry_rcu(tmp, head, cache_list) { - if (detail->match(tmp, key)) { - if (cache_is_expired(detail, tmp)) - continue; - tmp = cache_get_rcu(tmp); - rcu_read_unlock(); - return tmp; - } + if (!detail->match(tmp, key)) + continue; + if (test_bit(CACHE_VALID, &tmp->flags) && + cache_is_expired(detail, tmp)) + continue; + tmp = cache_get_rcu(tmp); + rcu_read_unlock(); + return tmp; } rcu_read_unlock(); return NULL; @@ -114,17 +115,18 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail, /* check if entry appeared while we slept */ hlist_for_each_entry_rcu(tmp, head, cache_list, lockdep_is_held(&detail->hash_lock)) { - if (detail->match(tmp, key)) { - if (cache_is_expired(detail, tmp)) { - sunrpc_begin_cache_remove_entry(tmp, detail); - freeme = tmp; - break; - } - cache_get(tmp); - spin_unlock(&detail->hash_lock); - cache_put(new, detail); - return tmp; + if (!detail->match(tmp, key)) + continue; + if (test_bit(CACHE_VALID, &tmp->flags) && + cache_is_expired(detail, tmp)) { + sunrpc_begin_cache_remove_entry(tmp, detail); + freeme = tmp; + break; } + cache_get(tmp); + spin_unlock(&detail->hash_lock); + cache_put(new, detail); + return tmp; } hlist_add_head_rcu(&new->cache_list, head); From 78a947f50aaabd8d49e634a84f451c0933af853a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Mar 2020 18:21:44 -0500 Subject: [PATCH 379/809] sunrpc: Add tracing for cache events Add basic tracing for debugging the sunrpc cache events. Signed-off-by: Trond Myklebust Signed-off-by: Chuck Lever --- include/trace/events/sunrpc.h | 33 ++++++++++++++++++++++++++++++++ net/sunrpc/cache.c | 36 ++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 1577223add43..ffd2215950dc 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -1335,6 +1335,39 @@ DECLARE_EVENT_CLASS(svc_deferred_event, DEFINE_SVC_DEFERRED_EVENT(drop); DEFINE_SVC_DEFERRED_EVENT(revisit); +DECLARE_EVENT_CLASS(cache_event, + TP_PROTO( + const struct cache_detail *cd, + const struct cache_head *h + ), + + TP_ARGS(cd, h), + + TP_STRUCT__entry( + __field(const struct cache_head *, h) + __string(name, cd->name) + ), + + TP_fast_assign( + __entry->h = h; + __assign_str(name, cd->name); + ), + + TP_printk("cache=%s entry=%p", __get_str(name), __entry->h) +); +#define DEFINE_CACHE_EVENT(name) \ + DEFINE_EVENT(cache_event, name, \ + TP_PROTO( \ + const struct cache_detail *cd, \ + const struct cache_head *h \ + ), \ + TP_ARGS(cd, h)) +DEFINE_CACHE_EVENT(cache_entry_expired); +DEFINE_CACHE_EVENT(cache_entry_upcall); +DEFINE_CACHE_EVENT(cache_entry_update); +DEFINE_CACHE_EVENT(cache_entry_make_negative); +DEFINE_CACHE_EVENT(cache_entry_no_listener); + #endif /* _TRACE_SUNRPC_H */ #include diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index cd76ef2d26b8..af0ddd28b081 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "netns.h" #define RPCDBG_FACILITY RPCDBG_CACHE @@ -120,6 +121,7 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail, if (test_bit(CACHE_VALID, &tmp->flags) && cache_is_expired(detail, tmp)) { sunrpc_begin_cache_remove_entry(tmp, detail); + trace_cache_entry_expired(detail, tmp); freeme = tmp; break; } @@ -176,6 +178,25 @@ static void cache_fresh_unlocked(struct cache_head *head, } } +static void cache_make_negative(struct cache_detail *detail, + struct cache_head *h) +{ + set_bit(CACHE_NEGATIVE, &h->flags); + trace_cache_entry_make_negative(detail, h); +} + +static void cache_entry_update(struct cache_detail *detail, + struct cache_head *h, + struct cache_head *new) +{ + if (!test_bit(CACHE_NEGATIVE, &new->flags)) { + detail->update(h, new); + trace_cache_entry_update(detail, h); + } else { + cache_make_negative(detail, h); + } +} + struct cache_head *sunrpc_cache_update(struct cache_detail *detail, struct cache_head *new, struct cache_head *old, int hash) { @@ -188,10 +209,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, if (!test_bit(CACHE_VALID, &old->flags)) { spin_lock(&detail->hash_lock); if (!test_bit(CACHE_VALID, &old->flags)) { - if (test_bit(CACHE_NEGATIVE, &new->flags)) - set_bit(CACHE_NEGATIVE, &old->flags); - else - detail->update(old, new); + cache_entry_update(detail, old, new); cache_fresh_locked(old, new->expiry_time, detail); spin_unlock(&detail->hash_lock); cache_fresh_unlocked(old, detail); @@ -209,10 +227,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, detail->init(tmp, old); spin_lock(&detail->hash_lock); - if (test_bit(CACHE_NEGATIVE, &new->flags)) - set_bit(CACHE_NEGATIVE, &tmp->flags); - else - detail->update(tmp, new); + cache_entry_update(detail, tmp, new); hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]); detail->entries++; cache_get(tmp); @@ -254,7 +269,7 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h spin_lock(&detail->hash_lock); rv = cache_is_valid(h); if (rv == -EAGAIN) { - set_bit(CACHE_NEGATIVE, &h->flags); + cache_make_negative(detail, h); cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY, detail); rv = -ENOENT; @@ -460,6 +475,7 @@ static int cache_clean(void) continue; sunrpc_begin_cache_remove_entry(ch, current_detail); + trace_cache_entry_expired(current_detail, ch); rv = 1; break; } @@ -1215,6 +1231,7 @@ static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) if (test_bit(CACHE_PENDING, &h->flags)) { crq->item = cache_get(h); list_add_tail(&crq->q.list, &detail->queue); + trace_cache_entry_upcall(detail, h); } else /* Lost a race, no longer PENDING, so don't enqueue */ ret = -EAGAIN; @@ -1240,6 +1257,7 @@ int sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail, { if (!cache_listeners_exist(detail)) { warn_no_listener(detail); + trace_cache_entry_no_listener(detail, h); return -EINVAL; } return sunrpc_cache_pipe_upcall(detail, h); From 3ac3711adb88f238ae562dcd3c6d064d23331404 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 5 Mar 2020 18:27:36 -0500 Subject: [PATCH 380/809] NFSD: Fix NFS server build errors yuehaibing@huawei.com reports the following build errors arise when CONFIG_NFSD_V4_2_INTER_SSC is set and the NFS client is not built into the kernel: fs/nfsd/nfs4proc.o: In function `nfsd4_do_copy': nfs4proc.c:(.text+0x23b7): undefined reference to `nfs42_ssc_close' fs/nfsd/nfs4proc.o: In function `nfsd4_copy': nfs4proc.c:(.text+0x5d2a): undefined reference to `nfs_sb_deactive' fs/nfsd/nfs4proc.o: In function `nfsd4_do_async_copy': nfs4proc.c:(.text+0x61d5): undefined reference to `nfs42_ssc_open' nfs4proc.c:(.text+0x6389): undefined reference to `nfs_sb_deactive' The new inter-server copy code invokes client functions. Until the NFS server has infrastructure to load the appropriate NFS client modules to handle inter-server copy requests, let's constrain the way this feature is built. Reported-by: YueHaibing Fixes: ce0887ac96d3 ("NFSD add nfs4 inter ssc to nfsd4_copy") Signed-off-by: Chuck Lever Tested-by: YueHaibing # build-tested --- fs/nfsd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index f368f3215f88..99d2cae91bd6 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -136,7 +136,7 @@ config NFSD_FLEXFILELAYOUT config NFSD_V4_2_INTER_SSC bool "NFSv4.2 inter server to server COPY" - depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 + depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 && NFS_FS=y help This option enables support for NFSv4.2 inter server to server copy where the destination server calls the NFSv4.2 From 6cbfad5f201b3204d74b5c749edf03c3ce14bab4 Mon Sep 17 00:00:00 2001 From: Petr Vorel Date: Fri, 13 Mar 2020 13:39:57 +0100 Subject: [PATCH 381/809] nfsd: remove read permission bit for ctl sysctl It's meant to be write-only. Fixes: 89c905beccbb ("nfsd: allow forced expiration of NFSv4 clients") Signed-off-by: Petr Vorel Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 169829db2817..3a24b3c328c3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2645,7 +2645,7 @@ static const struct file_operations client_ctl_fops = { static const struct tree_descr client_files[] = { [0] = {"info", &client_info_fops, S_IRUSR}, [1] = {"states", &client_states_fops, S_IRUSR}, - [2] = {"ctl", &client_ctl_fops, S_IRUSR|S_IWUSR}, + [2] = {"ctl", &client_ctl_fops, S_IWUSR}, [3] = {""}, }; From 32302085a8d90859c40cf1a5e8313f575d06ec75 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Mar 2020 12:40:02 +0100 Subject: [PATCH 382/809] ext2: fix debug reference to ext2_xattr_cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a debug-only build error in ext2/xattr.c: When building without extra debugging, (and with another patch that uses no_printk() instead of for the ext2-xattr debug-print macros, this build error happens: ../fs/ext2/xattr.c: In function ‘ext2_xattr_cache_insert’: ../fs/ext2/xattr.c:869:18: error: ‘ext2_xattr_cache’ undeclared (first use in this function); did you mean ‘ext2_xattr_list’? atomic_read(&ext2_xattr_cache->c_entry_count)); Fix the problem by removing cached entry count from the debug message since otherwise we'd have to export the mbcache structure just for that. Fixes: be0726d33cb8 ("ext2: convert to mbcache2") Reported-by: Randy Dunlap Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 9ad07c7ef0b3..6d9731b03715 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -872,8 +872,7 @@ ext2_xattr_cache_insert(struct mb_cache *cache, struct buffer_head *bh) true); if (error) { if (error == -EBUSY) { - ea_bdebug(bh, "already in cache (%d cache entries)", - atomic_read(&ext2_xattr_cache->c_entry_count)); + ea_bdebug(bh, "already in cache"); error = 0; } } else From 3670664b5da555a2a481449b3baafff113b0ac35 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 9 Jan 2020 18:39:12 +1100 Subject: [PATCH 383/809] tty: evh_bytechan: Fix out of bounds accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ev_byte_channel_send() assumes that its third argument is a 16 byte array. Some places where it is called it may not be (or we can't easily tell if it is). Newer compilers have started producing warnings about this, so make sure we actually pass a 16 byte array. There may be more elegant solutions to this, but the driver is quite old and hasn't been updated in many years. The warnings (from a powerpc allyesconfig build) are: In file included from include/linux/byteorder/big_endian.h:5, from arch/powerpc/include/uapi/asm/byteorder.h:14, from include/asm-generic/bitops/le.h:6, from arch/powerpc/include/asm/bitops.h:250, from include/linux/bitops.h:29, from include/linux/kernel.h:12, from include/asm-generic/bug.h:19, from arch/powerpc/include/asm/bug.h:109, from include/linux/bug.h:5, from include/linux/mmdebug.h:5, from include/linux/gfp.h:5, from include/linux/slab.h:15, from drivers/tty/ehv_bytechan.c:24: drivers/tty/ehv_bytechan.c: In function ‘ehv_bc_udbg_putc’: arch/powerpc/include/asm/epapr_hcalls.h:298:20: warning: array subscript 1 is outside array bounds of ‘const char[1]’ [-Warray-bounds] 298 | r6 = be32_to_cpu(p[1]); include/uapi/linux/byteorder/big_endian.h:40:51: note: in definition of macro ‘__be32_to_cpu’ 40 | #define __be32_to_cpu(x) ((__force __u32)(__be32)(x)) | ^ arch/powerpc/include/asm/epapr_hcalls.h:298:7: note: in expansion of macro ‘be32_to_cpu’ 298 | r6 = be32_to_cpu(p[1]); | ^~~~~~~~~~~ drivers/tty/ehv_bytechan.c:166:13: note: while referencing ‘data’ 166 | static void ehv_bc_udbg_putc(char c) | ^~~~~~~~~~~~~~~~ Fixes: dcd83aaff1c8 ("tty/powerpc: introduce the ePAPR embedded hypervisor byte channel driver") Signed-off-by: Stephen Rothwell Tested-by: Laurentiu Tudor [mpe: Trim warnings from change log] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200109183912.5fcb52aa@canb.auug.org.au --- drivers/tty/ehv_bytechan.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 769e0a5d1dfc..3c6dd06ec5fb 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -136,6 +136,21 @@ static int find_console_handle(void) return 1; } +static unsigned int local_ev_byte_channel_send(unsigned int handle, + unsigned int *count, + const char *p) +{ + char buffer[EV_BYTE_CHANNEL_MAX_BYTES]; + unsigned int c = *count; + + if (c < sizeof(buffer)) { + memcpy(buffer, p, c); + memset(&buffer[c], 0, sizeof(buffer) - c); + p = buffer; + } + return ev_byte_channel_send(handle, count, p); +} + /*************************** EARLY CONSOLE DRIVER ***************************/ #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC @@ -154,7 +169,7 @@ static void byte_channel_spin_send(const char data) do { count = 1; - ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, + ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, &count, &data); } while (ret == EV_EAGAIN); } @@ -221,7 +236,7 @@ static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s, while (count) { len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES); do { - ret = ev_byte_channel_send(handle, &len, s); + ret = local_ev_byte_channel_send(handle, &len, s); } while (ret == EV_EAGAIN); count -= len; s += len; @@ -401,7 +416,7 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc) CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE), EV_BYTE_CHANNEL_MAX_BYTES); - ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); + ret = local_ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); /* 'len' is valid only if the return code is 0 or EV_EAGAIN */ if (!ret || (ret == EV_EAGAIN)) From aa4113340ae6c2811e046f08c2bc21011d20a072 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 23 Jan 2020 11:19:25 +0000 Subject: [PATCH 384/809] powerpc/fsl_booke: Avoid creating duplicate tlb1 entry In the current implementation, the call to loadcam_multi() is wrapped between switch_to_as1() and restore_to_as0() calls so, when it tries to create its own temporary AS=1 TLB1 entry, it ends up duplicating the existing one created by switch_to_as1(). Add a check to skip creating the temporary entry if already running in AS=1. Fixes: d9e1831a4202 ("powerpc/85xx: Load all early TLB entries at once") Cc: stable@vger.kernel.org # v4.4+ Signed-off-by: Laurentiu Tudor Acked-by: Scott Wood Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200123111914.2565-1-laurentiu.tudor@nxp.com --- arch/powerpc/mm/nohash/tlb_low.S | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/nohash/tlb_low.S b/arch/powerpc/mm/nohash/tlb_low.S index 2ca407cedbe7..eaeee402f96e 100644 --- a/arch/powerpc/mm/nohash/tlb_low.S +++ b/arch/powerpc/mm/nohash/tlb_low.S @@ -397,7 +397,7 @@ _GLOBAL(set_context) * extern void loadcam_entry(unsigned int index) * * Load TLBCAM[index] entry in to the L2 CAM MMU - * Must preserve r7, r8, r9, and r10 + * Must preserve r7, r8, r9, r10 and r11 */ _GLOBAL(loadcam_entry) mflr r5 @@ -433,6 +433,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) */ _GLOBAL(loadcam_multi) mflr r8 + /* Don't switch to AS=1 if already there */ + mfmsr r11 + andi. r11,r11,MSR_IS + bne 10f /* * Set up temporary TLB entry that is the same as what we're @@ -458,6 +462,7 @@ _GLOBAL(loadcam_multi) mtmsr r6 isync +10: mr r9,r3 add r10,r3,r4 2: bl loadcam_entry @@ -466,6 +471,10 @@ _GLOBAL(loadcam_multi) mr r3,r9 blt 2b + /* Don't return to AS=0 if we were in AS=1 at function start */ + andi. r11,r11,MSR_IS + bne 3f + /* Return to AS=0 and clear the temporary entry */ mfmsr r6 rlwinm. r6,r6,0,~(MSR_IS|MSR_DS) @@ -481,6 +490,7 @@ _GLOBAL(loadcam_multi) tlbwe isync +3: mtlr r8 blr #endif From 9451c79bc39e610882bdd12370f01af5004a3c4f Mon Sep 17 00:00:00 2001 From: Ilie Halip Date: Fri, 20 Sep 2019 18:39:51 +0300 Subject: [PATCH 385/809] powerpc/pmac/smp: Avoid unused-variable warnings When building with ppc64_defconfig, the compiler reports that these 2 variables are not used: warning: unused variable 'core99_l2_cache' [-Wunused-variable] warning: unused variable 'core99_l3_cache' [-Wunused-variable] They are only used when CONFIG_PPC64 is not defined. Move them into a section which does the same macro check. Reported-by: Nathan Chancellor Signed-off-by: Ilie Halip [mpe: Move them into core99_init_caches() which is their only user] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190920153951.25762-1-ilie.halip@gmail.com --- arch/powerpc/platforms/powermac/smp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index f95fbdee6efe..4a2a1b2529b3 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -660,13 +660,13 @@ static void smp_core99_gpio_tb_freeze(int freeze) #endif /* !CONFIG_PPC64 */ -/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ -volatile static long int core99_l2_cache; -volatile static long int core99_l3_cache; - static void core99_init_caches(int cpu) { #ifndef CONFIG_PPC64 + /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ + volatile static long int core99_l2_cache; + volatile static long int core99_l3_cache; + if (!cpu_has_feature(CPU_FTR_L2CR)) return; From a4037d1f1fc4e92b69d7196d4568c33078d465ea Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 3 Mar 2020 16:56:04 +0800 Subject: [PATCH 386/809] powerpc/pmac/smp: Drop unnecessary volatile qualifier core99_l2_cache/core99_l3_cache do not need to be marked as volatile, remove it. Signed-off-by: YueHaibing Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200303085604.24952-1-yuehaibing@huawei.com --- arch/powerpc/platforms/powermac/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 4a2a1b2529b3..d2900689d642 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -664,8 +664,8 @@ static void core99_init_caches(int cpu) { #ifndef CONFIG_PPC64 /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ - volatile static long int core99_l2_cache; - volatile static long int core99_l3_cache; + static long int core99_l2_cache; + static long int core99_l3_cache; if (!cpu_has_feature(CPU_FTR_L2CR)) return; From 47bf235f324c696395c30541fe4fcf99fcd24188 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 28 Feb 2020 00:00:09 +0000 Subject: [PATCH 387/809] selftests/powerpc: Add tlbie_test in .gitignore The commit identified below added tlbie_test but forgot to add it in .gitignore. Fixes: 93cad5f78995 ("selftests/powerpc: Add test case for tlbie vs mtpidr ordering issue") Cc: stable@vger.kernel.org # v5.4+ Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/259f9c06ed4563c4fa4fa8ffa652347278d769e7.1582847784.git.christophe.leroy@c-s.fr --- tools/testing/selftests/powerpc/mm/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/powerpc/mm/.gitignore b/tools/testing/selftests/powerpc/mm/.gitignore index 0ebeaea22641..97f7922c52c5 100644 --- a/tools/testing/selftests/powerpc/mm/.gitignore +++ b/tools/testing/selftests/powerpc/mm/.gitignore @@ -6,3 +6,4 @@ segv_errors wild_bctr large_vm_fork_separation bad_accesses +tlbie_test From 993cfecc59e57de237ae27fadc84ed24efa87a4d Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Mon, 2 Mar 2020 11:04:10 +1000 Subject: [PATCH 388/809] powerpc/64s/radix: Fix CONFIG_SMP=n build Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200302010410.2957362-1-npiggin@gmail.com --- arch/powerpc/mm/book3s64/radix_pgtable.c | 1 + arch/powerpc/mm/book3s64/radix_tlb.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index dd1bea45325c..2a9a0cd79490 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/mm/book3s64/radix_tlb.c b/arch/powerpc/mm/book3s64/radix_tlb.c index 03f43c924e00..758ade2c2b6e 100644 --- a/arch/powerpc/mm/book3s64/radix_tlb.c +++ b/arch/powerpc/mm/book3s64/radix_tlb.c @@ -587,6 +587,11 @@ void radix__local_flush_all_mm(struct mm_struct *mm) preempt_enable(); } EXPORT_SYMBOL(radix__local_flush_all_mm); + +static void __flush_all_mm(struct mm_struct *mm, bool fullmm) +{ + radix__local_flush_all_mm(mm); +} #endif /* CONFIG_SMP */ void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr, @@ -777,7 +782,7 @@ void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) EXPORT_SYMBOL(radix__flush_tlb_page); #else /* CONFIG_SMP */ -#define radix__flush_all_mm radix__local_flush_all_mm +static inline void exit_flush_lazy_tlbs(struct mm_struct *mm) { } #endif /* CONFIG_SMP */ static void do_tlbiel_kernel(void *info) From 59ed2adf393109c56d383e568f2e57bb5ad6d901 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 26 Feb 2020 15:53:02 +1000 Subject: [PATCH 389/809] powerpc/lib: Fix emulate_step() std test We should be checking that the instruction was stepped *and* that the target register has the right value. Signed-off-by: Nicholas Piggin Reviewed-by: Ravi Bangoria [mpe: Write change log] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200226055302.1577954-1-npiggin@gmail.com --- arch/powerpc/lib/test_emulate_step.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c index 42347067739c..00d70253cb5b 100644 --- a/arch/powerpc/lib/test_emulate_step.c +++ b/arch/powerpc/lib/test_emulate_step.c @@ -160,7 +160,7 @@ static void __init test_std(void) /* std r5, 0(r3) */ stepped = emulate_step(®s, TEST_STD(5, 3, 0)); - if (stepped == 1 || regs.gpr[5] == a) + if (stepped == 1 && regs.gpr[5] == a) show_result("std", "PASS"); else show_result("std", "FAIL"); From 30a790653d8ac46d3116abe99ba745a7b0c27b8b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 17 Mar 2020 15:34:21 +0100 Subject: [PATCH 390/809] rtc: mt2712: fix build without PM_SLEEP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix this build error when PM_SLEEP is not selected: drivers/rtc/rtc-mt2712.c:412:10: error: ‘mt2712_pm_ops’ undeclared here (not in a function); did you mean ‘mt2712_rtc_ops’? 412 | .pm = &mt2712_pm_ops, | ^~~~~~~~~~~~~ Link: https://lore.kernel.org/r/20200317143421.9551-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mt2712.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-mt2712.c b/drivers/rtc/rtc-mt2712.c index 62c20241426d..581b8731fb8a 100644 --- a/drivers/rtc/rtc-mt2712.c +++ b/drivers/rtc/rtc-mt2712.c @@ -409,7 +409,9 @@ static struct platform_driver mt2712_rtc_driver = { .driver = { .name = "mt2712-rtc", .of_match_table = mt2712_rtc_of_match, +#ifdef CONFIG_PM_SLEEP .pm = &mt2712_pm_ops, +#endif }, .probe = mt2712_rtc_probe, }; From ab9a7e27044b87ff2be47b8f8e095400e7fccc44 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 10 Mar 2020 12:09:12 +0000 Subject: [PATCH 391/809] random: avoid warnings for !CONFIG_NUMA builds As crng_initialize_secondary() is only called by do_numa_crng_init(), and the latter is under ifdeffery for CONFIG_NUMA, when CONFIG_NUMA is not selected the compiler will warn that the former is unused: | drivers/char/random.c:820:13: warning: 'crng_initialize_secondary' defined but not used [-Wunused-function] | 820 | static void crng_initialize_secondary(struct crng_state *crng) | | ^~~~~~~~~~~~~~~~~~~~~~~~~ Stephen reports that this happens for x86_64 noallconfig builds. We could move crng_initialize_secondary() and crng_init_try_arch() under the CONFIG_NUMA ifdeffery, but this has the unfortunate property of separating them from crng_initialize_primary() and crng_init_try_arch_early() respectively. Instead, let's mark crng_initialize_secondary() as __maybe_unused. Link: https://lore.kernel.org/r/20200310121747.GA49602@lakrids.cambridge.arm.com Fixes: 5cbe0f13b51a ("random: split primary/secondary crng init paths") Reported-by: Stephen Rothwell Signed-off-by: Mark Rutland Cc: Theodore Ts'o Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index f43f65c2195d..0d10e31fd342 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -817,7 +817,7 @@ static bool __init crng_init_try_arch_early(struct crng_state *crng) return arch_init; } -static void crng_initialize_secondary(struct crng_state *crng) +static void __maybe_unused crng_initialize_secondary(struct crng_state *crng) { memcpy(&crng->state[0], "expand 32-byte k", 16); _get_random_bytes(&crng->state[4], sizeof(__u32) * 12); From 663e36f07666ff924012defa521f88875f6e5402 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 19 Mar 2020 10:18:49 -0400 Subject: [PATCH 392/809] nfsd4: kill warnings on testing stateids with mismatched clientids It's normal for a client to test a stateid from a previous instance, e.g. after a network partition. Signed-off-by: J. Bruce Fields Reviewed-by: Benjamin Coddington Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3a24b3c328c3..e32ecedece0f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5531,15 +5531,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || CLOSE_STATEID(stateid)) return status; - /* Client debugging aid. */ - if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { - char addr_str[INET6_ADDRSTRLEN]; - rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, - sizeof(addr_str)); - pr_warn_ratelimited("NFSD: client %s testing state ID " - "with incorrect client ID\n", addr_str); + if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) return status; - } spin_lock(&cl->cl_lock); s = find_stateid_locked(cl, stateid); if (!s) From 69afd267982e733a555fede4e85fe30329ed0588 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 19 Mar 2020 11:30:38 -0400 Subject: [PATCH 393/809] nfsd: fsnotify on rmdir under nfsd/clients/ Userspace should be able to monitor nfsd/clients/ to see when clients come and go, but we're failing to send fsnotify events. Cc: stable@kernel.org Signed-off-by: J. Bruce Fields Signed-off-by: Chuck Lever --- fs/nfsd/nfsctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index e109a1007704..3bb2db947d29 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1333,6 +1333,7 @@ void nfsd_client_rmdir(struct dentry *dentry) dget(dentry); ret = simple_rmdir(dir, dentry); WARN_ON_ONCE(ret); + fsnotify_rmdir(dir, dentry); d_delete(dentry); inode_unlock(dir); } From bf2cbe044da275021b2de5917240411a19e5c50d Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 19 Feb 2020 22:10:12 -0700 Subject: [PATCH 394/809] tracing: Use address-of operator on section symbols Clang warns: ../kernel/trace/trace.c:9335:33: warning: array comparison always evaluates to true [-Wtautological-compare] if (__stop___trace_bprintk_fmt != __start___trace_bprintk_fmt) ^ 1 warning generated. These are not true arrays, they are linker defined symbols, which are just addresses. Using the address of operator silences the warning and does not change the runtime result of the check (tested with some print statements compiled in with clang + ld.lld and gcc + ld.bfd in QEMU). Link: http://lkml.kernel.org/r/20200220051011.26113-1-natechancellor@gmail.com Link: https://github.com/ClangBuiltLinux/linux/issues/893 Suggested-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 6b11e4e2150c..02be4ddd4ad5 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -9334,7 +9334,7 @@ __init static int tracer_alloc_buffers(void) goto out_free_buffer_mask; /* Only allocate trace_printk buffers if a trace_printk exists */ - if (__stop___trace_bprintk_fmt != __start___trace_bprintk_fmt) + if (&__stop___trace_bprintk_fmt != &__start___trace_bprintk_fmt) /* Must be called before global_trace.buffer is allocated */ trace_printk_init_buffers(); From 8c77f0ba41566b5a54a49c53107cc855d89ff4c1 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 18 Mar 2020 11:13:45 -0400 Subject: [PATCH 395/809] selftest/ftrace: Fix function trigger test to handle trace not disabling the tracer The ftrace selftest "ftrace - test for function traceon/off triggers" enables all events and reads the trace file. Now that the trace file does not disable tracing, and will attempt to continually read new data that is added, the selftest gets stuck reading the trace file. This is because the data added to the trace file will fill up quicker than the reading of it. By only enabling scheduling events, the read can keep up with the writes. Instead of enabling all events, only enable the scheduler events. Link: http://lkml.kernel.org/r/20200318111345.0516642e@gandalf.local.home Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- .../selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc index 0c04282d33dd..1947387fe976 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc @@ -41,7 +41,7 @@ fi echo '** ENABLE EVENTS' -echo 1 > events/enable +echo 1 > events/sched/enable echo '** ENABLE TRACING' enable_tracing From ff895103a84abc85a5f43ecabc7f67cf36e1348f Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:23 -0400 Subject: [PATCH 396/809] tracing: Save off entry when peeking at next entry In order to have the iterator read the buffer even when it's still updating, it requires that the ring buffer iterator saves each event in a separate location outside the ring buffer such that its use is immutable. There's one use case that saves off the event returned from the ring buffer interator and calls it again to look at the next event, before going back to use the first event. As the ring buffer iterator will only have a single copy, this use case will no longer be supported. Instead, have the one use case create its own buffer to store the first event when looking at the next event. This way, when looking at the first event again, it wont be corrupted by the second read. Link: http://lkml.kernel.org/r/20200317213415.722539921@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- include/linux/trace_events.h | 2 ++ kernel/trace/trace.c | 40 +++++++++++++++++++++++++++++++++++- kernel/trace/trace_output.c | 15 ++++++-------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 6c7a10a6d71e..5c6943354049 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -85,6 +85,8 @@ struct trace_iterator { struct mutex mutex; struct ring_buffer_iter **buffer_iter; unsigned long iter_flags; + void *temp; /* temp holder */ + unsigned int temp_size; /* trace_seq for __print_flags() and __print_symbolic() etc. */ struct trace_seq tmp_seq; diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 02be4ddd4ad5..819e31d0d66c 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3466,7 +3466,31 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu, struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, int *ent_cpu, u64 *ent_ts) { - return __find_next_entry(iter, ent_cpu, NULL, ent_ts); + /* __find_next_entry will reset ent_size */ + int ent_size = iter->ent_size; + struct trace_entry *entry; + + /* + * The __find_next_entry() may call peek_next_entry(), which may + * call ring_buffer_peek() that may make the contents of iter->ent + * undefined. Need to copy iter->ent now. + */ + if (iter->ent && iter->ent != iter->temp) { + if (!iter->temp || iter->temp_size < iter->ent_size) { + kfree(iter->temp); + iter->temp = kmalloc(iter->ent_size, GFP_KERNEL); + if (!iter->temp) + return NULL; + } + memcpy(iter->temp, iter->ent, iter->ent_size); + iter->temp_size = iter->ent_size; + iter->ent = iter->temp; + } + entry = __find_next_entry(iter, ent_cpu, NULL, ent_ts); + /* Put back the original ent_size */ + iter->ent_size = ent_size; + + return entry; } /* Find the next real entry, and increment the iterator to the next entry */ @@ -4197,6 +4221,18 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) if (!iter->buffer_iter) goto release; + /* + * trace_find_next_entry() may need to save off iter->ent. + * It will place it into the iter->temp buffer. As most + * events are less than 128, allocate a buffer of that size. + * If one is greater, then trace_find_next_entry() will + * allocate a new buffer to adjust for the bigger iter->ent. + * It's not critical if it fails to get allocated here. + */ + iter->temp = kmalloc(128, GFP_KERNEL); + if (iter->temp) + iter->temp_size = 128; + /* * We make a copy of the current tracer to avoid concurrent * changes on it while we are reading. @@ -4269,6 +4305,7 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) fail: mutex_unlock(&trace_types_lock); kfree(iter->trace); + kfree(iter->temp); kfree(iter->buffer_iter); release: seq_release_private(inode, file); @@ -4344,6 +4381,7 @@ static int tracing_release(struct inode *inode, struct file *file) mutex_destroy(&iter->mutex); free_cpumask_var(iter->started); + kfree(iter->temp); kfree(iter->trace); kfree(iter->buffer_iter); seq_release_private(inode, file); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index e25a7da79c6b..9a121e147102 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -617,22 +617,19 @@ int trace_print_context(struct trace_iterator *iter) int trace_print_lat_context(struct trace_iterator *iter) { + struct trace_entry *entry, *next_entry; struct trace_array *tr = iter->tr; - /* trace_find_next_entry will reset ent_size */ - int ent_size = iter->ent_size; struct trace_seq *s = &iter->seq; - u64 next_ts; - struct trace_entry *entry = iter->ent, - *next_entry = trace_find_next_entry(iter, NULL, - &next_ts); unsigned long verbose = (tr->trace_flags & TRACE_ITER_VERBOSE); + u64 next_ts; - /* Restore the original ent_size */ - iter->ent_size = ent_size; - + next_entry = trace_find_next_entry(iter, NULL, &next_ts); if (!next_entry) next_ts = iter->ts; + /* trace_find_next_entry() may change iter->ent */ + entry = iter->ent; + if (verbose) { char comm[TASK_COMM_LEN]; From ead6ecfddea54f4754c97f64ab7198cc1d8c0daa Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:24 -0400 Subject: [PATCH 397/809] ring-buffer: Have ring_buffer_empty() not depend on tracing stopped It was complained about that when the trace file is read, that the tracing is disabled, as the iterator expects writing to the buffer it reads is not updated. Several steps are needed to make the iterator handle a writer, by testing if things have changed as it reads. This step is to make ring_buffer_empty() expect the buffer to be changing. Note if the current location of the iterator is overwritten, then it will return false as new data is being added. Note, that this means that data will be skipped. Link: http://lkml.kernel.org/r/20200317213415.870741809@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/ring_buffer.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 61f0e92ace99..1718520a2809 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3590,16 +3590,37 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter) struct buffer_page *reader; struct buffer_page *head_page; struct buffer_page *commit_page; + struct buffer_page *curr_commit_page; unsigned commit; + u64 curr_commit_ts; + u64 commit_ts; cpu_buffer = iter->cpu_buffer; - - /* Remember, trace recording is off when iterator is in use */ reader = cpu_buffer->reader_page; head_page = cpu_buffer->head_page; commit_page = cpu_buffer->commit_page; - commit = rb_page_commit(commit_page); + commit_ts = commit_page->page->time_stamp; + /* + * When the writer goes across pages, it issues a cmpxchg which + * is a mb(), which will synchronize with the rmb here. + * (see rb_tail_page_update()) + */ + smp_rmb(); + commit = rb_page_commit(commit_page); + /* We want to make sure that the commit page doesn't change */ + smp_rmb(); + + /* Make sure commit page didn't change */ + curr_commit_page = READ_ONCE(cpu_buffer->commit_page); + curr_commit_ts = READ_ONCE(curr_commit_page->page->time_stamp); + + /* If the commit page changed, then there's more data */ + if (curr_commit_page != commit_page || + curr_commit_ts != commit_ts) + return 0; + + /* Still racy, as it may return a false positive, but that's OK */ return ((iter->head_page == commit_page && iter->head == commit) || (iter->head_page == reader && commit_page == head_page && head_page->read == commit && From bc1a72afdc4a91844928831cac85731566e03bc6 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:25 -0400 Subject: [PATCH 398/809] ring-buffer: Rename ring_buffer_read() to read_buffer_iter_advance() When the ring buffer was first created, the iterator followed the normal producer/consumer operations where it had both a peek() operation, that just returned the event at the current location, and a read(), that would return the event at the current location and also increment the iterator such that the next peek() or read() will return the next event. The only use of the ring_buffer_read() is currently to move the iterator to the next location and nothing now actually reads the event it returns. Rename this function to its actual use case to ring_buffer_iter_advance(), which also adds the "iter" part to the name, which is more meaningful. As the timestamp returned by ring_buffer_read() was never used, there's no reason that this new version should bother having returning it. It will also become a void function. Link: http://lkml.kernel.org/r/20200317213416.018928618@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- include/linux/ring_buffer.h | 3 +-- kernel/trace/ring_buffer.c | 23 ++++++----------------- kernel/trace/trace.c | 4 ++-- kernel/trace/trace_functions_graph.c | 2 +- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index df0124eabece..0ae603b79b0e 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -135,8 +135,7 @@ void ring_buffer_read_finish(struct ring_buffer_iter *iter); struct ring_buffer_event * ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts); -struct ring_buffer_event * -ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts); +void ring_buffer_iter_advance(struct ring_buffer_iter *iter); void ring_buffer_iter_reset(struct ring_buffer_iter *iter); int ring_buffer_iter_empty(struct ring_buffer_iter *iter); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 1718520a2809..f57eeaa80e3e 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -4318,35 +4318,24 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter) EXPORT_SYMBOL_GPL(ring_buffer_read_finish); /** - * ring_buffer_read - read the next item in the ring buffer by the iterator + * ring_buffer_iter_advance - advance the iterator to the next location * @iter: The ring buffer iterator - * @ts: The time stamp of the event read. * - * This reads the next event in the ring buffer and increments the iterator. + * Move the location of the iterator such that the next read will + * be the next location of the iterator. */ -struct ring_buffer_event * -ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts) +void ring_buffer_iter_advance(struct ring_buffer_iter *iter) { - struct ring_buffer_event *event; struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; unsigned long flags; raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); - again: - event = rb_iter_peek(iter, ts); - if (!event) - goto out; - - if (event->type_len == RINGBUF_TYPE_PADDING) - goto again; rb_advance_iter(iter); - out: - raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - return event; + raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); } -EXPORT_SYMBOL_GPL(ring_buffer_read); +EXPORT_SYMBOL_GPL(ring_buffer_iter_advance); /** * ring_buffer_size - return the size of the ring buffer (in bytes) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 819e31d0d66c..47889123be7f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3378,7 +3378,7 @@ static void trace_iterator_increment(struct trace_iterator *iter) iter->idx++; if (buf_iter) - ring_buffer_read(buf_iter, NULL); + ring_buffer_iter_advance(buf_iter); } static struct trace_entry * @@ -3562,7 +3562,7 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu) if (ts >= iter->array_buffer->time_start) break; entries++; - ring_buffer_read(buf_iter, NULL); + ring_buffer_iter_advance(buf_iter); } per_cpu_ptr(iter->array_buffer->data, cpu)->skipped_entries = entries; diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 7d71546ba00a..4a9c49c08ec9 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -482,7 +482,7 @@ get_return_for_leaf(struct trace_iterator *iter, /* this is a leaf, now advance the iterator */ if (ring_iter) - ring_buffer_read(ring_iter, NULL); + ring_buffer_iter_advance(ring_iter); return next; } From 28e3fc56a471bbac39d24571e11dde64b15de988 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:26 -0400 Subject: [PATCH 399/809] ring-buffer: Add page_stamp to iterator for synchronization Have the ring_buffer_iter structure contain a page_stamp, such that it can be used to see if the writer entered the page the iterator is on. When going to a new page, the iterator will record the time stamp of that page. When reading events, it can copy the event to an internal buffer on the iterator (to be implemented later), then check the page's time stamp with its own to see if the writer entered the page. If so, it will need to try to read the event again. Link: http://lkml.kernel.org/r/20200317213416.163549674@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/ring_buffer.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index f57eeaa80e3e..e689bdcb53e8 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -507,6 +507,7 @@ struct ring_buffer_iter { struct buffer_page *cache_reader_page; unsigned long cache_read; u64 read_stamp; + u64 page_stamp; }; /** @@ -1959,7 +1960,7 @@ static void rb_inc_iter(struct ring_buffer_iter *iter) else rb_inc_page(cpu_buffer, &iter->head_page); - iter->read_stamp = iter->head_page->page->time_stamp; + iter->page_stamp = iter->read_stamp = iter->head_page->page->time_stamp; iter->head = 0; } @@ -3551,10 +3552,13 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) iter->cache_reader_page = iter->head_page; iter->cache_read = cpu_buffer->read; - if (iter->head) + if (iter->head) { iter->read_stamp = cpu_buffer->read_stamp; - else + iter->page_stamp = cpu_buffer->reader_page->page->time_stamp; + } else { iter->read_stamp = iter->head_page->page->time_stamp; + iter->page_stamp = iter->read_stamp; + } } /** From 785888c544e0433f601df18ff98a3215b380b9c3 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:27 -0400 Subject: [PATCH 400/809] ring-buffer: Have rb_iter_head_event() handle concurrent writer Have the ring_buffer_iter structure have a place to store an event, such that it can not be overwritten by a writer, and load it in such a way via rb_iter_head_event() that it will return NULL and reset the iter to the start of the current page if a writer updated the page. Link: http://lkml.kernel.org/r/20200317213416.306959216@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/ring_buffer.c | 108 ++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index e689bdcb53e8..3d718add73c1 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -503,11 +503,13 @@ struct trace_buffer { struct ring_buffer_iter { struct ring_buffer_per_cpu *cpu_buffer; unsigned long head; + unsigned long next_event; struct buffer_page *head_page; struct buffer_page *cache_reader_page; unsigned long cache_read; u64 read_stamp; u64 page_stamp; + struct ring_buffer_event *event; }; /** @@ -1914,17 +1916,61 @@ rb_reader_event(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->reader_page->read); } -static __always_inline struct ring_buffer_event * -rb_iter_head_event(struct ring_buffer_iter *iter) -{ - return __rb_page_index(iter->head_page, iter->head); -} - static __always_inline unsigned rb_page_commit(struct buffer_page *bpage) { return local_read(&bpage->page->commit); } +static struct ring_buffer_event * +rb_iter_head_event(struct ring_buffer_iter *iter) +{ + struct ring_buffer_event *event; + struct buffer_page *iter_head_page = iter->head_page; + unsigned long commit; + unsigned length; + + /* + * When the writer goes across pages, it issues a cmpxchg which + * is a mb(), which will synchronize with the rmb here. + * (see rb_tail_page_update() and __rb_reserve_next()) + */ + commit = rb_page_commit(iter_head_page); + smp_rmb(); + event = __rb_page_index(iter_head_page, iter->head); + length = rb_event_length(event); + + /* + * READ_ONCE() doesn't work on functions and we don't want the + * compiler doing any crazy optimizations with length. + */ + barrier(); + + if ((iter->head + length) > commit || length > BUF_MAX_DATA_SIZE) + /* Writer corrupted the read? */ + goto reset; + + memcpy(iter->event, event, length); + /* + * If the page stamp is still the same after this rmb() then the + * event was safely copied without the writer entering the page. + */ + smp_rmb(); + + /* Make sure the page didn't change since we read this */ + if (iter->page_stamp != iter_head_page->page->time_stamp || + commit > rb_page_commit(iter_head_page)) + goto reset; + + iter->next_event = iter->head + length; + return iter->event; + reset: + /* Reset to the beginning */ + iter->page_stamp = iter->read_stamp = iter->head_page->page->time_stamp; + iter->head = 0; + iter->next_event = 0; + return NULL; +} + /* Size is determined by what has been committed */ static __always_inline unsigned rb_page_size(struct buffer_page *bpage) { @@ -1962,6 +2008,7 @@ static void rb_inc_iter(struct ring_buffer_iter *iter) iter->page_stamp = iter->read_stamp = iter->head_page->page->time_stamp; iter->head = 0; + iter->next_event = 0; } /* @@ -3548,6 +3595,7 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) /* Iterator usage is expected to have record disabled */ iter->head_page = cpu_buffer->reader_page; iter->head = cpu_buffer->reader_page->read; + iter->next_event = iter->head; iter->cache_reader_page = iter->head_page; iter->cache_read = cpu_buffer->read; @@ -3625,7 +3673,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter) return 0; /* Still racy, as it may return a false positive, but that's OK */ - return ((iter->head_page == commit_page && iter->head == commit) || + return ((iter->head_page == commit_page && iter->head >= commit) || (iter->head_page == reader && commit_page == head_page && head_page->read == commit && iter->head == rb_page_commit(cpu_buffer->reader_page))); @@ -3853,15 +3901,22 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) static void rb_advance_iter(struct ring_buffer_iter *iter) { struct ring_buffer_per_cpu *cpu_buffer; - struct ring_buffer_event *event; - unsigned length; cpu_buffer = iter->cpu_buffer; + /* If head == next_event then we need to jump to the next event */ + if (iter->head == iter->next_event) { + /* If the event gets overwritten again, there's nothing to do */ + if (rb_iter_head_event(iter) == NULL) + return; + } + + iter->head = iter->next_event; + /* * Check if we are at the end of the buffer. */ - if (iter->head >= rb_page_size(iter->head_page)) { + if (iter->next_event >= rb_page_size(iter->head_page)) { /* discarded commits can make the page empty */ if (iter->head_page == cpu_buffer->commit_page) return; @@ -3869,27 +3924,7 @@ static void rb_advance_iter(struct ring_buffer_iter *iter) return; } - event = rb_iter_head_event(iter); - - length = rb_event_length(event); - - /* - * This should not be called to advance the header if we are - * at the tail of the buffer. - */ - if (RB_WARN_ON(cpu_buffer, - (iter->head_page == cpu_buffer->commit_page) && - (iter->head + length > rb_commit_index(cpu_buffer)))) - return; - - rb_update_iter_read_stamp(iter, event); - - iter->head += length; - - /* check for end of page padding */ - if ((iter->head >= rb_page_size(iter->head_page)) && - (iter->head_page != cpu_buffer->commit_page)) - rb_inc_iter(iter); + rb_update_iter_read_stamp(iter, iter->event); } static int rb_lost_events(struct ring_buffer_per_cpu *cpu_buffer) @@ -4017,6 +4052,8 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) } event = rb_iter_head_event(iter); + if (!event) + goto again; switch (event->type_len) { case RINGBUF_TYPE_PADDING: @@ -4233,10 +4270,16 @@ ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags) if (!cpumask_test_cpu(cpu, buffer->cpumask)) return NULL; - iter = kmalloc(sizeof(*iter), flags); + iter = kzalloc(sizeof(*iter), flags); if (!iter) return NULL; + iter->event = kmalloc(BUF_MAX_DATA_SIZE, flags); + if (!iter->event) { + kfree(iter); + return NULL; + } + cpu_buffer = buffer->buffers[cpu]; iter->cpu_buffer = cpu_buffer; @@ -4317,6 +4360,7 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter) atomic_dec(&cpu_buffer->record_disabled); atomic_dec(&cpu_buffer->buffer->resize_disabled); + kfree(iter->event); kfree(iter); } EXPORT_SYMBOL_GPL(ring_buffer_read_finish); From ff84c50cfb4b8dc68c982fb6c05a524e1539ee2f Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:28 -0400 Subject: [PATCH 401/809] ring-buffer: Do not die if rb_iter_peek() fails more than thrice As the iterator will be reading a live buffer, and if the event being read is on a page that a writer crosses, it will fail and try again, the condition in rb_iter_peek() that only allows a retry to happen three times is no longer valid. Allow rb_iter_peek() to retry more than three times without killing the ring buffer, but only if rb_iter_head_event() had failed at least once. Link: http://lkml.kernel.org/r/20200317213416.452888193@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/ring_buffer.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 3d718add73c1..475338fda969 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -4012,6 +4012,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_event *event; int nr_loops = 0; + bool failed = false; if (ts) *ts = 0; @@ -4038,10 +4039,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) * to a data event, we should never loop more than three times. * Once for going to next page, once on time extend, and * finally once to get the event. - * (We never hit the following condition more than thrice). + * We should never hit the following condition more than thrice, + * unless the buffer is very small, and there's a writer + * that is causing the reader to fail getting an event. */ - if (RB_WARN_ON(cpu_buffer, ++nr_loops > 3)) + if (++nr_loops > 3) { + RB_WARN_ON(cpu_buffer, !failed); return NULL; + } if (rb_per_cpu_empty(cpu_buffer)) return NULL; @@ -4052,8 +4057,10 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) } event = rb_iter_head_event(iter); - if (!event) + if (!event) { + failed = true; goto again; + } switch (event->type_len) { case RINGBUF_TYPE_PADDING: From 153368ce1bd0ccb47812a3185e824445a7024ea5 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 17 Mar 2020 17:32:29 -0400 Subject: [PATCH 402/809] ring-buffer: Optimize rb_iter_head_event() As it is fine to perform several "peeks" of event data in the ring buffer via the iterator before moving it forward, do not re-read the event, just return what was read before. Otherwise, it can cause inconsistent results, especially when testing multiple CPU buffers to interleave them. Link: http://lkml.kernel.org/r/20200317213416.592032170@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/ring_buffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 475338fda969..5979327254f9 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1929,6 +1929,9 @@ rb_iter_head_event(struct ring_buffer_iter *iter) unsigned long commit; unsigned length; + if (iter->head != iter->next_event) + return iter->event; + /* * When the writer goes across pages, it issues a cmpxchg which * is a mb(), which will synchronize with the rmb here. From a0968a025c04702427a4aee2c618f451a5098cd8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 4 Mar 2020 22:04:02 +1100 Subject: [PATCH 403/809] selftests/powerpc: Add a test of sigreturn vs VDSO There's two different paths through the sigreturn code, depending on whether the VDSO is mapped or not. We recently discovered a bug in the unmapped case, because it's not commonly used these days. So add a test that sends itself a signal, then moves the VDSO, takes another signal and finally unmaps the VDSO before sending itself another signal. That tests the standard signal path, the code that handles the VDSO being moved, and also the signal path in the case where the VDSO is unmapped. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200304110402.6038-1-mpe@ellerman.id.au --- .../selftests/powerpc/signal/.gitignore | 1 + .../testing/selftests/powerpc/signal/Makefile | 2 +- .../selftests/powerpc/signal/sigreturn_vdso.c | 127 ++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/signal/sigreturn_vdso.c diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore index dca5852a1546..03dafa795255 100644 --- a/tools/testing/selftests/powerpc/signal/.gitignore +++ b/tools/testing/selftests/powerpc/signal/.gitignore @@ -1,3 +1,4 @@ signal signal_tm sigfuz +sigreturn_vdso diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile index 113838fbbe7f..63b57583e07d 100644 --- a/tools/testing/selftests/powerpc/signal/Makefile +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_GEN_PROGS := signal signal_tm sigfuz +TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso CFLAGS += -maltivec $(OUTPUT)/signal_tm: CFLAGS += -mhtm diff --git a/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c b/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c new file mode 100644 index 000000000000..e282fff0fe25 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test that we can take signals with and without the VDSO mapped, which trigger + * different paths in the signal handling code. + * + * See handle_rt_signal64() and setup_trampoline() in signal_64.c + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +// Ensure assert() is not compiled out +#undef NDEBUG +#include + +#include "utils.h" + +static int search_proc_maps(char *needle, unsigned long *low, unsigned long *high) +{ + unsigned long start, end; + static char buf[4096]; + char name[128]; + FILE *f; + int rc = -1; + + f = fopen("/proc/self/maps", "r"); + if (!f) { + perror("fopen"); + return -1; + } + + while (fgets(buf, sizeof(buf), f)) { + rc = sscanf(buf, "%lx-%lx %*c%*c%*c%*c %*x %*d:%*d %*d %127s\n", + &start, &end, name); + if (rc == 2) + continue; + + if (rc != 3) { + printf("sscanf errored\n"); + rc = -1; + break; + } + + if (strstr(name, needle)) { + *low = start; + *high = end - 1; + rc = 0; + break; + } + } + + fclose(f); + + return rc; +} + +static volatile sig_atomic_t took_signal = 0; + +static void sigusr1_handler(int sig) +{ + took_signal++; +} + +int test_sigreturn_vdso(void) +{ + unsigned long low, high, size; + struct sigaction act; + char *p; + + act.sa_handler = sigusr1_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + assert(sigaction(SIGUSR1, &act, NULL) == 0); + + // Confirm the VDSO is mapped, and work out where it is + assert(search_proc_maps("[vdso]", &low, &high) == 0); + size = high - low + 1; + printf("VDSO is at 0x%lx-0x%lx (%lu bytes)\n", low, high, size); + + kill(getpid(), SIGUSR1); + assert(took_signal == 1); + printf("Signal delivered OK with VDSO mapped\n"); + + // Remap the VDSO somewhere else + p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + assert(p != MAP_FAILED); + assert(mremap((void *)low, size, size, MREMAP_MAYMOVE|MREMAP_FIXED, p) != MAP_FAILED); + assert(search_proc_maps("[vdso]", &low, &high) == 0); + size = high - low + 1; + printf("VDSO moved to 0x%lx-0x%lx (%lu bytes)\n", low, high, size); + + kill(getpid(), SIGUSR1); + assert(took_signal == 2); + printf("Signal delivered OK with VDSO moved\n"); + + assert(munmap((void *)low, size) == 0); + printf("Unmapped VDSO\n"); + + // Confirm the VDSO is not mapped anymore + assert(search_proc_maps("[vdso]", &low, &high) != 0); + + // Make the stack executable + assert(search_proc_maps("[stack]", &low, &high) == 0); + size = high - low + 1; + mprotect((void *)low, size, PROT_READ|PROT_WRITE|PROT_EXEC); + printf("Remapped the stack executable\n"); + + kill(getpid(), SIGUSR1); + assert(took_signal == 3); + printf("Signal delivered OK with VDSO unmapped\n"); + + return 0; +} + +int main(void) +{ + return test_harness(test_sigreturn_vdso, "sigreturn_vdso"); +} From 61da50b76b62fd815aa82d853bf82bf4f69568f5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 1 Mar 2020 22:17:38 +1100 Subject: [PATCH 404/809] powerpc/kuap: PPC_KUAP_DEBUG should depend on PPC_KUAP Currently you can enable PPC_KUAP_DEBUG when PPC_KUAP is disabled, even though the former has not effect without the latter. Fix it so that PPC_KUAP_DEBUG can only be enabled when PPC_KUAP is enabled, not when the platform could support KUAP (PPC_HAVE_KUAP). Fixes: 890274c2dc4c ("powerpc/64s: Implement KUAP for Radix MMU") Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200301111738.22497-1-mpe@ellerman.id.au --- arch/powerpc/platforms/Kconfig.cputype | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 4208724e9f28..0c3c1902135c 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -397,7 +397,7 @@ config PPC_KUAP config PPC_KUAP_DEBUG bool "Extra debugging for Kernel Userspace Access Protection" - depends on PPC_HAVE_KUAP && (PPC_RADIX_MMU || PPC_32) + depends on PPC_KUAP && (PPC_RADIX_MMU || PPC_32) help Add extra debugging for Kernel Userspace Access Protection (KUAP) If you're unsure, say N. From 915b7f6f9a5e232c138bb36743a1fdb0fcf2c432 Mon Sep 17 00:00:00 2001 From: Gustavo Luiz Duarte Date: Tue, 11 Feb 2020 00:38:30 -0300 Subject: [PATCH 405/809] selftests/powerpc: Add tm-signal-pagefault test This test triggers a TM Bad Thing by raising a signal in transactional state and forcing a pagefault to happen in kernelspace when the kernel signal handling code first touches the user signal stack. This is inspired by the test tm-signal-context-force-tm but uses userfaultfd to make the test deterministic. While this test always triggers the bug in one run, I had to execute tm-signal-context-force-tm several times (the test runs 5000 times each execution) to trigger the same bug. tm-signal-context-force-tm is kept instead of replaced because, while this test is more reliable and triggers the same bug, tm-signal-context-force-tm has a better coverage, in the sense that by running the test several times it might trigger the pagefault and/or be preempted at different places. v3: skip test if userfaultfd is unavailable. Signed-off-by: Gustavo Luiz Duarte Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200211033831.11165-2-gustavold@linux.ibm.com --- tools/testing/selftests/powerpc/tm/.gitignore | 1 + tools/testing/selftests/powerpc/tm/Makefile | 3 +- .../powerpc/tm/tm-signal-pagefault.c | 284 ++++++++++++++++++ 3 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-pagefault.c diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 98f2708d86cc..e1c72a4a3e91 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -13,6 +13,7 @@ tm-signal-context-chk-vmx tm-signal-context-chk-vsx tm-signal-context-force-tm tm-signal-sigreturn-nt +tm-signal-pagefault tm-vmx-unavail tm-unavailable tm-trap diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index b15a1a325bd0..b1d99736f8b8 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -5,7 +5,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable tm-trap \ $(SIGNAL_CONTEXT_CHK_TESTS) tm-sigreturn tm-signal-sigreturn-nt \ - tm-signal-context-force-tm tm-poison + tm-signal-context-force-tm tm-poison tm-signal-pagefault top_srcdir = ../../../../.. include ../../lib.mk @@ -22,6 +22,7 @@ $(OUTPUT)/tm-resched-dscr: ../pmu/lib.c $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64 $(OUTPUT)/tm-signal-context-force-tm: CFLAGS += -pthread -m64 +$(OUTPUT)/tm-signal-pagefault: CFLAGS += -pthread -m64 SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-pagefault.c b/tools/testing/selftests/powerpc/tm/tm-signal-pagefault.c new file mode 100644 index 000000000000..5908bc6abe60 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-pagefault.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020, Gustavo Luiz Duarte, IBM Corp. + * + * This test starts a transaction and triggers a signal, forcing a pagefault to + * happen when the kernel signal handling code touches the user signal stack. + * + * In order to avoid pre-faulting the signal stack memory and to force the + * pagefault to happen precisely in the kernel signal handling code, the + * pagefault handling is done in userspace using the userfaultfd facility. + * + * Further pagefaults are triggered by crafting the signal handler's ucontext + * to point to additional memory regions managed by the userfaultfd, so using + * the same mechanism used to avoid pre-faulting the signal stack memory. + * + * On failure (bug is present) kernel crashes or never returns control back to + * userspace. If bug is not present, tests completes almost immediately. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tm.h" + + +#define UF_MEM_SIZE 655360 /* 10 x 64k pages */ + +/* Memory handled by userfaultfd */ +static char *uf_mem; +static size_t uf_mem_offset = 0; + +/* + * Data that will be copied into the faulting pages (instead of zero-filled + * pages). This is used to make the test more reliable and avoid segfaulting + * when we return from the signal handler. Since we are making the signal + * handler's ucontext point to newly allocated memory, when that memory is + * paged-in it will contain the expected content. + */ +static char backing_mem[UF_MEM_SIZE]; + +static size_t pagesize; + +/* + * Return a chunk of at least 'size' bytes of memory that will be handled by + * userfaultfd. If 'backing_data' is not NULL, its content will be save to + * 'backing_mem' and then copied into the faulting pages when the page fault + * is handled. + */ +void *get_uf_mem(size_t size, void *backing_data) +{ + void *ret; + + if (uf_mem_offset + size > UF_MEM_SIZE) { + fprintf(stderr, "Requesting more uf_mem than expected!\n"); + exit(EXIT_FAILURE); + } + + ret = &uf_mem[uf_mem_offset]; + + /* Save the data that will be copied into the faulting page */ + if (backing_data != NULL) + memcpy(&backing_mem[uf_mem_offset], backing_data, size); + + /* Reserve the requested amount of uf_mem */ + uf_mem_offset += size; + /* Keep uf_mem_offset aligned to the page size (round up) */ + uf_mem_offset = (uf_mem_offset + pagesize - 1) & ~(pagesize - 1); + + return ret; +} + +void *fault_handler_thread(void *arg) +{ + struct uffd_msg msg; /* Data read from userfaultfd */ + long uffd; /* userfaultfd file descriptor */ + struct uffdio_copy uffdio_copy; + struct pollfd pollfd; + ssize_t nread, offset; + + uffd = (long) arg; + + for (;;) { + pollfd.fd = uffd; + pollfd.events = POLLIN; + if (poll(&pollfd, 1, -1) == -1) { + perror("poll() failed"); + exit(EXIT_FAILURE); + } + + nread = read(uffd, &msg, sizeof(msg)); + if (nread == 0) { + fprintf(stderr, "read(): EOF on userfaultfd\n"); + exit(EXIT_FAILURE); + } + + if (nread == -1) { + perror("read() failed"); + exit(EXIT_FAILURE); + } + + /* We expect only one kind of event */ + if (msg.event != UFFD_EVENT_PAGEFAULT) { + fprintf(stderr, "Unexpected event on userfaultfd\n"); + exit(EXIT_FAILURE); + } + + /* + * We need to handle page faults in units of pages(!). + * So, round faulting address down to page boundary. + */ + uffdio_copy.dst = msg.arg.pagefault.address & ~(pagesize-1); + + offset = (char *) uffdio_copy.dst - uf_mem; + uffdio_copy.src = (unsigned long) &backing_mem[offset]; + + uffdio_copy.len = pagesize; + uffdio_copy.mode = 0; + uffdio_copy.copy = 0; + if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1) { + perror("ioctl-UFFDIO_COPY failed"); + exit(EXIT_FAILURE); + } + } +} + +void setup_uf_mem(void) +{ + long uffd; /* userfaultfd file descriptor */ + pthread_t thr; + struct uffdio_api uffdio_api; + struct uffdio_register uffdio_register; + int ret; + + pagesize = sysconf(_SC_PAGE_SIZE); + + /* Create and enable userfaultfd object */ + uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (uffd == -1) { + perror("userfaultfd() failed"); + exit(EXIT_FAILURE); + } + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) { + perror("ioctl-UFFDIO_API failed"); + exit(EXIT_FAILURE); + } + + /* + * Create a private anonymous mapping. The memory will be demand-zero + * paged, that is, not yet allocated. When we actually touch the memory + * the related page will be allocated via the userfaultfd mechanism. + */ + uf_mem = mmap(NULL, UF_MEM_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (uf_mem == MAP_FAILED) { + perror("mmap() failed"); + exit(EXIT_FAILURE); + } + + /* + * Register the memory range of the mapping we've just mapped to be + * handled by the userfaultfd object. In 'mode' we request to track + * missing pages (i.e. pages that have not yet been faulted-in). + */ + uffdio_register.range.start = (unsigned long) uf_mem; + uffdio_register.range.len = UF_MEM_SIZE; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) { + perror("ioctl-UFFDIO_REGISTER"); + exit(EXIT_FAILURE); + } + + /* Create a thread that will process the userfaultfd events */ + ret = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd); + if (ret != 0) { + fprintf(stderr, "pthread_create(): Error. Returned %d\n", ret); + exit(EXIT_FAILURE); + } +} + +/* + * Assumption: the signal was delivered while userspace was in transactional or + * suspended state, i.e. uc->uc_link != NULL. + */ +void signal_handler(int signo, siginfo_t *si, void *uc) +{ + ucontext_t *ucp = uc; + + /* Skip 'trap' after returning, otherwise we get a SIGTRAP again */ + ucp->uc_link->uc_mcontext.regs->nip += 4; + + ucp->uc_mcontext.v_regs = + get_uf_mem(sizeof(elf_vrreg_t), ucp->uc_mcontext.v_regs); + + ucp->uc_link->uc_mcontext.v_regs = + get_uf_mem(sizeof(elf_vrreg_t), ucp->uc_link->uc_mcontext.v_regs); + + ucp->uc_link = get_uf_mem(sizeof(ucontext_t), ucp->uc_link); +} + +bool have_userfaultfd(void) +{ + long rc; + + errno = 0; + rc = syscall(__NR_userfaultfd, -1); + + return rc == 0 || errno != ENOSYS; +} + +int tm_signal_pagefault(void) +{ + struct sigaction sa; + stack_t ss; + + SKIP_IF(!have_htm()); + SKIP_IF(!have_userfaultfd()); + + setup_uf_mem(); + + /* + * Set an alternative stack that will generate a page fault when the + * signal is raised. The page fault will be treated via userfaultfd, + * i.e. via fault_handler_thread. + */ + ss.ss_sp = get_uf_mem(SIGSTKSZ, NULL); + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + if (sigaltstack(&ss, NULL) == -1) { + perror("sigaltstack() failed"); + exit(EXIT_FAILURE); + } + + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = signal_handler; + if (sigaction(SIGTRAP, &sa, NULL) == -1) { + perror("sigaction() failed"); + exit(EXIT_FAILURE); + } + + /* Trigger a SIGTRAP in transactional state */ + asm __volatile__( + "tbegin.;" + "beq 1f;" + "trap;" + "1: ;" + : : : "memory"); + + /* Trigger a SIGTRAP in suspended state */ + asm __volatile__( + "tbegin.;" + "beq 1f;" + "tsuspend.;" + "trap;" + "tresume.;" + "1: ;" + : : : "memory"); + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + /* + * Depending on kernel config, the TM Bad Thing might not result in a + * crash, instead the kernel never returns control back to userspace, so + * set a tight timeout. If the test passes it completes almost + * immediately. + */ + test_harness_set_timeout(2); + return test_harness(tm_signal_pagefault, "tm_signal_pagefault"); +} From a28e1c0505a09c3a2d81fed1c8453ac2d8d02b3a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 13 Mar 2020 09:15:22 +0100 Subject: [PATCH 406/809] gpio: Move devres calls to devres file These two devres functions devm_gpiochip_[add|remove]() were in the wrong file. They should be in gpiolib-devres.c not gpiolib.c. Link: https://lore.kernel.org/r/20200313081522.35143-1-linus.walleij@linaro.org Reviewed-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-devres.c | 46 +++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib.c | 46 ----------------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 72b6001c56ef..5c91c4365da1 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -478,3 +478,49 @@ void devm_gpio_free(struct device *dev, unsigned int gpio) &gpio)); } EXPORT_SYMBOL_GPL(devm_gpio_free); + +static void devm_gpio_chip_release(struct device *dev, void *res) +{ + struct gpio_chip *gc = *(struct gpio_chip **)res; + + gpiochip_remove(gc); +} + +/** + * devm_gpiochip_add_data() - Resource managed gpiochip_add_data() + * @dev: pointer to the device that gpio_chip belongs to. + * @gc: the GPIO chip to register + * @data: driver-private data associated with this chip + * + * Context: potentially before irqs will work + * + * The gpio chip automatically be released when the device is unbound. + * + * Returns: + * A negative errno if the chip can't be registered, such as because the + * gc->base is invalid or already associated with a different chip. + * Otherwise it returns zero as a success code. + */ +int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc, + void *data) +{ + struct gpio_chip **ptr; + int ret; + + ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = gpiochip_add_data(gc, data); + if (ret < 0) { + devres_free(ptr); + return ret; + } + + *ptr = gc; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_gpiochip_add_data); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 02f8b2b81199..00890f38f95f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1838,52 +1838,6 @@ void gpiochip_remove(struct gpio_chip *chip) } EXPORT_SYMBOL_GPL(gpiochip_remove); -static void devm_gpio_chip_release(struct device *dev, void *res) -{ - struct gpio_chip *chip = *(struct gpio_chip **)res; - - gpiochip_remove(chip); -} - -/** - * devm_gpiochip_add_data() - Resource managed gpiochip_add_data() - * @dev: pointer to the device that gpio_chip belongs to. - * @chip: the chip to register, with chip->base initialized - * @data: driver-private data associated with this chip - * - * Context: potentially before irqs will work - * - * The gpio chip automatically be released when the device is unbound. - * - * Returns: - * A negative errno if the chip can't be registered, such as because the - * chip->base is invalid or already associated with a different chip. - * Otherwise it returns zero as a success code. - */ -int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip, - void *data) -{ - struct gpio_chip **ptr; - int ret; - - ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - ret = gpiochip_add_data(chip, data); - if (ret < 0) { - devres_free(ptr); - return ret; - } - - *ptr = chip; - devres_add(dev, ptr); - - return 0; -} -EXPORT_SYMBOL_GPL(devm_gpiochip_add_data); - /** * gpiochip_find() - iterator for locating a specific gpio_chip * @data: data to pass to match function From fd50924917f98f11554e3bf55b0d062e09bce541 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Feb 2020 12:46:37 +0100 Subject: [PATCH 407/809] ARM/dma-mapping: remove get_coherent_dma_mask The core DMA code already checks for valid DMA masks earlier on, and doesn't allow NULL struct device pointers. Remove the now not required checks. Signed-off-by: Christoph Hellwig --- arch/arm/mm/dma-mapping.c | 41 ++++----------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 9414d72f664b..72ddc3d0f5eb 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -219,7 +219,7 @@ const struct dma_map_ops arm_coherent_dma_ops = { }; EXPORT_SYMBOL(arm_coherent_dma_ops); -static int __dma_supported(struct device *dev, u64 mask, bool warn) +static int __dma_supported(struct device *dev, u64 mask) { unsigned long max_dma_pfn = min(max_pfn - 1, arm_dma_pfn_limit); @@ -227,41 +227,11 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn) * Translate the device's DMA mask to a PFN limit. This * PFN number includes the page which we can DMA to. */ - if (dma_to_pfn(dev, mask) < max_dma_pfn) { - if (warn) - dev_warn(dev, "Coherent DMA mask %#llx (pfn %#lx-%#lx) covers a smaller range of system memory than the DMA zone pfn 0x0-%#lx\n", - mask, - dma_to_pfn(dev, 0), dma_to_pfn(dev, mask) + 1, - max_dma_pfn + 1); + if (dma_to_pfn(dev, mask) < max_dma_pfn) return 0; - } - return 1; } -static u64 get_coherent_dma_mask(struct device *dev) -{ - u64 mask = (u64)DMA_BIT_MASK(32); - - if (dev) { - mask = dev->coherent_dma_mask; - - /* - * Sanity check the DMA mask - it must be non-zero, and - * must be able to be satisfied by a DMA allocation. - */ - if (mask == 0) { - dev_warn(dev, "coherent DMA mask is unset\n"); - return 0; - } - - if (!__dma_supported(dev, mask, true)) - return 0; - } - - return mask; -} - static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag) { /* @@ -688,7 +658,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, pgprot_t prot, bool is_coherent, unsigned long attrs, const void *caller) { - u64 mask = get_coherent_dma_mask(dev); + u64 mask = dev->coherent_dma_mask; struct page *page = NULL; void *addr; bool allowblock, cma; @@ -712,9 +682,6 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, } #endif - if (!mask) - return NULL; - buf = kzalloc(sizeof(*buf), gfp & ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM)); if (!buf) @@ -1095,7 +1062,7 @@ void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, */ int arm_dma_supported(struct device *dev, u64 mask) { - return __dma_supported(dev, mask, false); + return __dma_supported(dev, mask); } static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent) From 7607cb733fbb6dfac88c4a85c113e8104c91733e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Feb 2020 12:50:23 +0100 Subject: [PATCH 408/809] ARM/dma-mapping: take the bus limit into account in __dma_alloc The DMA coherent allocator needs to take bus limits into account for picking the zone that the memory is allocated from. Reported-by: Roger Quadros Signed-off-by: Christoph Hellwig Tested-by: Peter Ujfalusi Tested-by: Roger Quadros --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 72ddc3d0f5eb..87aba505554a 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -658,7 +658,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, pgprot_t prot, bool is_coherent, unsigned long attrs, const void *caller) { - u64 mask = dev->coherent_dma_mask; + u64 mask = min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); struct page *page = NULL; void *addr; bool allowblock, cma; From fd27a526bb381f43dded6db30b3b016468ab0e6c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Feb 2020 12:48:59 +0100 Subject: [PATCH 409/809] ARM/dma-mapping: merge __dma_supported into arm_dma_supported Merge __dma_supported into its only caller, and move the resulting function so that it doesn't need a forward declaration. Also mark it static as there are no callers outside of dma-mapping.c. Signed-off-by: Christoph Hellwig --- arch/arm/include/asm/dma-iommu.h | 2 -- arch/arm/mm/dma-mapping.c | 41 +++++++++++++------------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h index 772f48ef84b7..86405cc81385 100644 --- a/arch/arm/include/asm/dma-iommu.h +++ b/arch/arm/include/asm/dma-iommu.h @@ -33,7 +33,5 @@ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping); void arm_iommu_detach_device(struct device *dev); -int arm_dma_supported(struct device *dev, u64 mask); - #endif /* __KERNEL__ */ #endif diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 87aba505554a..8a8949174b1c 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -179,6 +179,23 @@ static void arm_dma_sync_single_for_device(struct device *dev, __dma_page_cpu_to_dev(page, offset, size, dir); } +/* + * Return whether the given device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during bus mastering, then you would pass 0x00ffffff as the mask + * to this function. + */ +static int arm_dma_supported(struct device *dev, u64 mask) +{ + unsigned long max_dma_pfn = min(max_pfn - 1, arm_dma_pfn_limit); + + /* + * Translate the device's DMA mask to a PFN limit. This + * PFN number includes the page which we can DMA to. + */ + return dma_to_pfn(dev, mask) >= max_dma_pfn; +} + const struct dma_map_ops arm_dma_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free, @@ -219,19 +236,6 @@ const struct dma_map_ops arm_coherent_dma_ops = { }; EXPORT_SYMBOL(arm_coherent_dma_ops); -static int __dma_supported(struct device *dev, u64 mask) -{ - unsigned long max_dma_pfn = min(max_pfn - 1, arm_dma_pfn_limit); - - /* - * Translate the device's DMA mask to a PFN limit. This - * PFN number includes the page which we can DMA to. - */ - if (dma_to_pfn(dev, mask) < max_dma_pfn) - return 0; - return 1; -} - static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag) { /* @@ -1054,17 +1058,6 @@ void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, dir); } -/* - * Return whether the given device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during bus mastering, then you would pass 0x00ffffff as the mask - * to this function. - */ -int arm_dma_supported(struct device *dev, u64 mask) -{ - return __dma_supported(dev, mask); -} - static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent) { /* From 53624f9b75e2e37f65c37d5d87d495013b27daee Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 19 Mar 2020 11:05:29 +0530 Subject: [PATCH 410/809] dt-bindings: clock: Add YAML schemas for the QCOM MSS clock bindings The Modem Subsystem clock provider have a bunch of generic properties that are needed in a device tree. Add a YAML schemas for those. Add clock ids for GCC MSS and MSS clocks which are required to bring the modem out of reset. Signed-off-by: Taniya Das Link: https://lkml.kernel.org/r/1584596131-22741-2-git-send-email-tdas@codeaurora.org Reviewed-by: Rob Herring Tested-by: Sibi Sankar Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,sc7180-mss.yaml | 62 +++++++++++++++++++ include/dt-bindings/clock/qcom,gcc-sc7180.h | 7 ++- include/dt-bindings/clock/qcom,mss-sc7180.h | 12 ++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sc7180-mss.yaml create mode 100644 include/dt-bindings/clock/qcom,mss-sc7180.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-mss.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-mss.yaml new file mode 100644 index 000000000000..0dd5d25ae7d7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sc7180-mss.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sc7180-mss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Modem Clock Controller Binding for SC7180 + +maintainers: + - Taniya Das + +description: | + Qualcomm modem clock control module which supports the clocks on SC7180. + + See also: + - dt-bindings/clock/qcom,mss-sc7180.h + +properties: + compatible: + const: qcom,sc7180-mss + + clocks: + items: + - description: gcc_mss_mfab_axi clock from GCC + - description: gcc_mss_nav_axi clock from GCC + - description: gcc_mss_cfg_ahb clock from GCC + + clock-names: + items: + - const: gcc_mss_mfab_axis + - const: gcc_mss_nav_axi + - const: cfg_ahb + + '#clock-cells': + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + #include + clock-controller@41a8000 { + compatible = "qcom,sc7180-mss"; + reg = <0 0x041a8000 0 0x8000>; + clocks = <&gcc GCC_MSS_MFAB_AXIS_CLK>, + <&gcc GCC_MSS_NAV_AXI_CLK>, + <&gcc GCC_MSS_CFG_AHB_CLK>; + clock-names = "gcc_mss_mfab_axis", + "gcc_mss_nav_axi", + "cfg_ahb"; + #clock-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,gcc-sc7180.h b/include/dt-bindings/clock/qcom,gcc-sc7180.h index e8029b2e92d7..1258fd05db68 100644 --- a/include/dt-bindings/clock/qcom,gcc-sc7180.h +++ b/include/dt-bindings/clock/qcom,gcc-sc7180.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _DT_BINDINGS_CLK_QCOM_GCC_SC7180_H @@ -132,6 +132,11 @@ #define GCC_VIDEO_GPLL0_DIV_CLK_SRC 122 #define GCC_VIDEO_THROTTLE_AXI_CLK 123 #define GCC_VIDEO_XO_CLK 124 +#define GCC_MSS_CFG_AHB_CLK 125 +#define GCC_MSS_MFAB_AXIS_CLK 126 +#define GCC_MSS_NAV_AXI_CLK 127 +#define GCC_MSS_Q6_MEMNOC_AXI_CLK 128 +#define GCC_MSS_SNOC_AXI_CLK 129 /* GCC resets */ #define GCC_QUSB2PHY_PRIM_BCR 0 diff --git a/include/dt-bindings/clock/qcom,mss-sc7180.h b/include/dt-bindings/clock/qcom,mss-sc7180.h new file mode 100644 index 000000000000..f15a9ded2961 --- /dev/null +++ b/include/dt-bindings/clock/qcom,mss-sc7180.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_MSS_SC7180_H +#define _DT_BINDINGS_CLK_QCOM_MSS_SC7180_H + +#define MSS_AXI_CRYPTO_CLK 0 +#define MSS_AXI_NAV_CLK 1 + +#endif From 253a0af508e0ca80bd767e541421a7a7998a3e1e Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 19 Mar 2020 11:05:30 +0530 Subject: [PATCH 411/809] clk: qcom: gcc: Add support for modem clocks in GCC Add the required modem clocks in global clock controller which are required to bring the modem out of reset. Signed-off-by: Taniya Das Link: https://lkml.kernel.org/r/1584596131-22741-3-git-send-email-tdas@codeaurora.org Tested-by: Sibi Sankar Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sc7180.c | 72 ++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-sc7180.c b/drivers/clk/qcom/gcc-sc7180.c index 7f59fb8da033..6a51b5b5fc19 100644 --- a/drivers/clk/qcom/gcc-sc7180.c +++ b/drivers/clk/qcom/gcc-sc7180.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -2165,6 +2165,71 @@ static struct clk_branch gcc_video_xo_clk = { }, }; +static struct clk_branch gcc_mss_cfg_ahb_clk = { + .halt_reg = 0x8a000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8a000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mss_mfab_axis_clk = { + .halt_reg = 0x8a004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_mfab_axis_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mss_nav_axi_clk = { + .halt_reg = 0x8a00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8a00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_nav_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mss_snoc_axi_clk = { + .halt_reg = 0x8a150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8a150, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_snoc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mss_q6_memnoc_axi_clk = { + .halt_reg = 0x8a154, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8a154, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_q6_memnoc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc ufs_phy_gdsc = { .gdscr = 0x77004, .pd = { @@ -2336,6 +2401,11 @@ static struct clk_regmap *gcc_sc7180_clocks[] = { [GPLL7] = &gpll7.clkr, [GPLL4] = &gpll4.clkr, [GPLL1] = &gpll1.clkr, + [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr, + [GCC_MSS_MFAB_AXIS_CLK] = &gcc_mss_mfab_axis_clk.clkr, + [GCC_MSS_NAV_AXI_CLK] = &gcc_mss_nav_axi_clk.clkr, + [GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr, + [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr, }; static const struct qcom_reset_map gcc_sc7180_resets[] = { From 8def929c4097d9014c37d6a3649b21d38ad607d7 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 19 Mar 2020 11:05:31 +0530 Subject: [PATCH 412/809] clk: qcom: Add modem clock controller driver for SC7180 Add support for the modem clock controller found on SC7180 based devices. This would allow modem drivers to probe and control their clocks. Signed-off-by: Taniya Das Link: https://lkml.kernel.org/r/1584596131-22741-4-git-send-email-tdas@codeaurora.org Tested-by: Sibi Sankar Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 9 +++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/mss-sc7180.c | 143 ++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 drivers/clk/qcom/mss-sc7180.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index af406a7c4aca..11ec6f466467 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -280,6 +280,15 @@ config SC_GPUCC_7180 Say Y if you want to support graphics controller devices and functionality such as 3D graphics. +config SC_MSS_7180 + tristate "SC7180 Modem Clock Controller" + select SC_GCC_7180 + help + Support for the Modem Subsystem clock controller on Qualcomm + Technologies, Inc on SC7180 devices. + Say Y if you want to use the Modem branch clocks of the Modem + subsystem clock controller to reset the MSS subsystem. + config SC_VIDEOCC_7180 tristate "SC7180 Video Clock Controller" select SC_GCC_7180 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index bd6556b829c0..691efbf7e81f 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o +obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o diff --git a/drivers/clk/qcom/mss-sc7180.c b/drivers/clk/qcom/mss-sc7180.c new file mode 100644 index 000000000000..673fa1a4f734 --- /dev/null +++ b/drivers/clk/qcom/mss-sc7180.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch mss_axi_nav_clk = { + .halt_reg = 0x20bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x20bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mss_axi_nav_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "gcc_mss_nav_axi", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mss_axi_crypto_clk = { + .halt_reg = 0x20cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x20cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mss_axi_crypto_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "gcc_mss_mfab_axis", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct regmap_config mss_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = 0x41aa0cc, +}; + +static struct clk_regmap *mss_sc7180_clocks[] = { + [MSS_AXI_CRYPTO_CLK] = &mss_axi_crypto_clk.clkr, + [MSS_AXI_NAV_CLK] = &mss_axi_nav_clk.clkr, +}; + +static const struct qcom_cc_desc mss_sc7180_desc = { + .config = &mss_regmap_config, + .clks = mss_sc7180_clocks, + .num_clks = ARRAY_SIZE(mss_sc7180_clocks), +}; + +static int mss_sc7180_probe(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + ret = pm_clk_create(&pdev->dev); + if (ret) + goto disable_pm_runtime; + + ret = pm_clk_add(&pdev->dev, "cfg_ahb"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to acquire iface clock\n"); + goto destroy_pm_clk; + } + + ret = qcom_cc_probe(pdev, &mss_sc7180_desc); + if (ret < 0) + goto destroy_pm_clk; + + return 0; + +destroy_pm_clk: + pm_clk_destroy(&pdev->dev); + +disable_pm_runtime: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int mss_sc7180_remove(struct platform_device *pdev) +{ + pm_clk_destroy(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops mss_sc7180_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static const struct of_device_id mss_sc7180_match_table[] = { + { .compatible = "qcom,sc7180-mss" }, + { } +}; +MODULE_DEVICE_TABLE(of, mss_sc7180_match_table); + +static struct platform_driver mss_sc7180_driver = { + .probe = mss_sc7180_probe, + .remove = mss_sc7180_remove, + .driver = { + .name = "sc7180-mss", + .of_match_table = mss_sc7180_match_table, + .pm = &mss_sc7180_pm_ops, + }, +}; + +static int __init mss_sc7180_init(void) +{ + return platform_driver_register(&mss_sc7180_driver); +} +subsys_initcall(mss_sc7180_init); + +static void __exit mss_sc7180_exit(void) +{ + platform_driver_unregister(&mss_sc7180_driver); +} +module_exit(mss_sc7180_exit); + +MODULE_DESCRIPTION("QTI MSS SC7180 Driver"); +MODULE_LICENSE("GPL v2"); From 1aec193ea41d672d11592714cdda8167eb3b38fc Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 18 Mar 2020 14:16:56 +0100 Subject: [PATCH 413/809] ipq806x: gcc: Added the enable regs and mask for PRNG Kernel got hanged while reading from /dev/hwrng at the time of PRNG clock enable Fixes: 24d8fba44af3 "clk: qcom: Add support for IPQ8064's global clock controller (GCC)" Signed-off-by: Abhishek Sahu Signed-off-by: Ansuel Smith Link: https://lkml.kernel.org/r/20200318131657.345-1-ansuelsmth@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-ipq806x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index b0eee0903807..a8456e09c44d 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -1224,6 +1224,8 @@ static struct clk_rcg prng_src = { .parent_map = gcc_pxo_pll8_map, }, .clkr = { + .enable_reg = 0x2e80, + .enable_mask = BIT(11), .hw.init = &(struct clk_init_data){ .name = "prng_src", .parent_names = gcc_pxo_pll8, From 8411aa5059edd584f7022f1dc300aa2f8f89fd06 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Tue, 17 Mar 2020 13:53:31 -0700 Subject: [PATCH 414/809] clk: qcom: gcc: Add USB3 PIPE clock and GDSC for SM8150 This adds the USB3 PIPE clock and GDSC structures, so that the USB driver can vote for these resources to be enabled/disabled when required. Both are needed for SS and HS USB paths to operate properly. The GDSC will allow the USB system to be brought out of reset, while the PIPE clock is needed for data transactions between the PHY and controller. Signed-off-by: Wesley Cheng Link: https://lkml.kernel.org/r/1584478412-7798-2-git-send-email-wcheng@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sm8150.c | 52 +++++++++++++++++++++ include/dt-bindings/clock/qcom,gcc-sm8150.h | 4 ++ 2 files changed, 56 insertions(+) diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index 20877214acff..ef98fdc51755 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -21,6 +21,7 @@ #include "clk-rcg.h" #include "clk-regmap.h" #include "reset.h" +#include "gdsc.h" enum { P_BI_TCXO, @@ -3171,6 +3172,18 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { }, }; +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0xf058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_usb3_sec_clkref_clk = { .halt_reg = 0x8c028, .halt_check = BRANCH_HALT, @@ -3218,6 +3231,18 @@ static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { }, }; +static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x10058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + /* * Clock ON depends on external parent 'config noc', so cant poll * delay and also mark as crtitical for video boot @@ -3292,6 +3317,24 @@ static struct clk_branch gcc_video_xo_clk = { }, }; +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR, +}; + +static struct gdsc usb30_sec_gdsc = { + .gdscr = 0x10004, + .pd = { + .name = "usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR, +}; + static struct clk_regmap *gcc_sm8150_clocks[] = { [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, @@ -3480,10 +3523,12 @@ static struct clk_regmap *gcc_sm8150_clocks[] = { [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, [GCC_USB3_SEC_CLKREF_CLK] = &gcc_usb3_sec_clkref_clk.clkr, [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr, [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr, [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr, [GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr, [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, @@ -3527,6 +3572,11 @@ static const struct qcom_reset_map gcc_sm8150_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, }; +static struct gdsc *gcc_sm8150_gdscs[] = { + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, +}; + static const struct regmap_config gcc_sm8150_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -3541,6 +3591,8 @@ static const struct qcom_cc_desc gcc_sm8150_desc = { .num_clks = ARRAY_SIZE(gcc_sm8150_clocks), .resets = gcc_sm8150_resets, .num_resets = ARRAY_SIZE(gcc_sm8150_resets), + .gdscs = gcc_sm8150_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm8150_gdscs), }; static const struct of_device_id gcc_sm8150_match_table[] = { diff --git a/include/dt-bindings/clock/qcom,gcc-sm8150.h b/include/dt-bindings/clock/qcom,gcc-sm8150.h index 90d60ef94c64..3e1a91876610 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8150.h @@ -240,4 +240,8 @@ #define GCC_USB30_SEC_BCR 27 #define GCC_USB_PHY_CFG_AHB2PHY_BCR 28 +/* GCC GDSCRs */ +#define USB30_PRIM_GDSC 4 +#define USB30_SEC_GDSC 5 + #endif From dc6a81c3382f74fe94eb0b8c616493598926efff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=90=B0=E6=9D=B0=20=28Zhou=20Yanjie=29?= Date: Tue, 17 Mar 2020 23:11:33 +0800 Subject: [PATCH 415/809] clk: Ingenic: Add support for TCU of X1000. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X1000 has a different TCU, since X1000 OST has been independent of TCU. This patch is add TCU support of X1000, and prepare for later OST driver. Signed-off-by: 周琰杰 (Zhou Yanjie) Link: https://lkml.kernel.org/r/1584457893-40418-3-git-send-email-zhouyanjie@wanyeetech.com Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/tcu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c index ad7daa494fd4..879990762f57 100644 --- a/drivers/clk/ingenic/tcu.c +++ b/drivers/clk/ingenic/tcu.c @@ -317,10 +317,17 @@ static const struct ingenic_soc_info jz4770_soc_info = { .has_tcu_clk = false, }; +static const struct ingenic_soc_info x1000_soc_info = { + .num_channels = 8, + .has_ost = false, /* X1000 has OST, but it not belong TCU */ + .has_tcu_clk = false, +}; + static const struct of_device_id ingenic_tcu_of_match[] __initconst = { { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, { .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, }, + { .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, }, { /* sentinel */ } }; @@ -471,3 +478,4 @@ static void __init ingenic_tcu_init(struct device_node *np) CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init); CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init); CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init); +CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init); From 6673db4f3f261b8ea955f0130eb8cc28b57f500b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=90=B0=E6=9D=B0=20=28Zhou=20Yanjie=29?= Date: Fri, 21 Feb 2020 00:24:43 +0800 Subject: [PATCH 416/809] clk: JZ4780: Add function for enable the second core. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add "jz4780_core1_enable()" for enable the second core of JZ4780, prepare for later commits. Tested-by: H. Nikolaus Schaller Tested-by: Paul Boddie Signed-off-by: 周琰杰 (Zhou Yanjie) Reviewed-by: Jiaxun Yang Link: https://lkml.kernel.org/r/1582215889-113034-3-git-send-email-zhouyanjie@wanyeetech.com Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/jz4780-cgu.c | 55 +++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c index ea905ff72bf0..c758f1643067 100644 --- a/drivers/clk/ingenic/jz4780-cgu.c +++ b/drivers/clk/ingenic/jz4780-cgu.c @@ -9,14 +9,16 @@ #include #include #include +#include #include + #include #include "cgu.h" #include "pm.h" /* CGU register offsets */ #define CGU_REG_CLOCKCONTROL 0x00 -#define CGU_REG_PLLCONTROL 0x0c +#define CGU_REG_LCR 0x04 #define CGU_REG_APLL 0x10 #define CGU_REG_MPLL 0x14 #define CGU_REG_EPLL 0x18 @@ -46,8 +48,8 @@ #define CGU_REG_CLOCKSTATUS 0xd4 /* bits within the OPCR register */ -#define OPCR_SPENDN0 (1 << 7) -#define OPCR_SPENDN1 (1 << 6) +#define OPCR_SPENDN0 BIT(7) +#define OPCR_SPENDN1 BIT(6) /* bits within the USBPCR register */ #define USBPCR_USB_MODE BIT(31) @@ -88,6 +90,13 @@ #define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT) #define USBVBFIL_USBVBFIL_MASK (0xffff) +/* bits within the LCR register */ +#define LCR_PD_SCPU BIT(31) +#define LCR_SCPUS BIT(27) + +/* bits within the CLKGR1 register */ +#define CLKGR1_CORE1 BIT(15) + static struct ingenic_cgu *cgu; static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw) @@ -205,6 +214,42 @@ static const struct clk_ops jz4780_otg_phy_ops = { .set_rate = jz4780_otg_phy_set_rate, }; +static int jz4780_core1_enable(struct clk_hw *hw) +{ + struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); + struct ingenic_cgu *cgu = ingenic_clk->cgu; + const unsigned int timeout = 5000; + unsigned long flags; + int retval; + u32 lcr, clkgr1; + + spin_lock_irqsave(&cgu->lock, flags); + + lcr = readl(cgu->base + CGU_REG_LCR); + lcr &= ~LCR_PD_SCPU; + writel(lcr, cgu->base + CGU_REG_LCR); + + clkgr1 = readl(cgu->base + CGU_REG_CLKGR1); + clkgr1 &= ~CLKGR1_CORE1; + writel(clkgr1, cgu->base + CGU_REG_CLKGR1); + + spin_unlock_irqrestore(&cgu->lock, flags); + + /* wait for the CPU to be powered up */ + retval = readl_poll_timeout(cgu->base + CGU_REG_LCR, lcr, + !(lcr & LCR_SCPUS), 10, timeout); + if (retval == -ETIMEDOUT) { + pr_err("%s: Wait for power up core1 timeout\n", __func__); + return retval; + } + + return 0; +} + +static const struct clk_ops jz4780_core1_ops = { + .enable = jz4780_core1_enable, +}; + static const s8 pll_od_encoding[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, @@ -699,9 +744,9 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { }, [JZ4780_CLK_CORE1] = { - "core1", CGU_CLK_GATE, + "core1", CGU_CLK_CUSTOM, .parents = { JZ4780_CLK_CPU, -1, -1, -1 }, - .gate = { CGU_REG_CLKGR1, 15 }, + .custom = { &jz4780_core1_ops }, }, }; From cf891c6be1ce287ea7043ee958555ec633fab71d Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 27 Feb 2020 11:05:28 +0530 Subject: [PATCH 417/809] dt-bindings: clock: Add binding documentation for TI EHRPWM TBCLK Add DT bindings for TI EHRPWM's TimeBase clock (TBCLK) on TI's AM654 SoC. Signed-off-by: Vignesh Raghavendra Link: https://lkml.kernel.org/r/20200227053529.16479-2-vigneshr@ti.com Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/ti,am654-ehrpwm-tbclk.yaml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml diff --git a/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml b/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml new file mode 100644 index 000000000000..869b18ac88d7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti,am654-ehrpwm-tbclk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI EHRPWM Time Base Clock + +maintainers: + - Vignesh Raghavendra + +properties: + compatible: + items: + - const: ti,am654-ehrpwm-tbclk + - const: syscon + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - reg + +examples: + - | + ehrpwm_tbclk: syscon@4140 { + compatible = "ti,am654-ehrpwm-tbclk", "syscon"; + reg = <0x4140 0x18>; + #clock-cells = <1>; + }; From 1aa0817e43c525c3ee035786a17a19077a0bb06a Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 27 Feb 2020 11:05:29 +0530 Subject: [PATCH 418/809] clk: keystone: Add new driver to handle syscon based clocks On TI's AM654/J721e SoCs, certain clocks can be gated/ungated by setting a single bit in SoC's System Control Module registers. Sometime more than one clock control can be in the same register. Add a driver to support such clocks using syscon framework. Driver currently supports controlling EHRPWM's TimeBase clock(TBCLK) for AM654 SoC. Signed-off-by: Vignesh Raghavendra Link: https://lkml.kernel.org/r/20200227053529.16479-3-vigneshr@ti.com Signed-off-by: Stephen Boyd --- drivers/clk/keystone/Kconfig | 8 ++ drivers/clk/keystone/Makefile | 1 + drivers/clk/keystone/syscon-clk.c | 172 ++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/clk/keystone/syscon-clk.c diff --git a/drivers/clk/keystone/Kconfig b/drivers/clk/keystone/Kconfig index 38aeefb1e808..ab613f28b502 100644 --- a/drivers/clk/keystone/Kconfig +++ b/drivers/clk/keystone/Kconfig @@ -26,3 +26,11 @@ config TI_SCI_CLK_PROBE_FROM_FW This is mostly only useful for debugging purposes, and will increase the boot time of the device. If you want the clocks probed from firmware, say Y. Otherwise, say N. + +config TI_SYSCON_CLK + tristate "Syscon based clock driver for K2/K3 SoCs" + depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST + default ARCH_KEYSTONE || ARCH_K3 + help + This adds clock driver support for syscon based gate + clocks on TI's K2 and K3 SoCs. diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile index d044de6f965c..0e426e648f7c 100644 --- a/drivers/clk/keystone/Makefile +++ b/drivers/clk/keystone/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_COMMON_CLK_KEYSTONE) += pll.o gate.o obj-$(CONFIG_TI_SCI_CLK) += sci-clk.o +obj-$(CONFIG_TI_SYSCON_CLK) += syscon-clk.o diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c new file mode 100644 index 000000000000..8d7dbea3bd30 --- /dev/null +++ b/drivers/clk/keystone/syscon-clk.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include +#include +#include +#include +#include + +struct ti_syscon_gate_clk_priv { + struct clk_hw hw; + struct regmap *regmap; + u32 reg; + u32 idx; +}; + +struct ti_syscon_gate_clk_data { + char *name; + u32 offset; + u32 bit_idx; +}; + +static struct +ti_syscon_gate_clk_priv *to_ti_syscon_gate_clk_priv(struct clk_hw *hw) +{ + return container_of(hw, struct ti_syscon_gate_clk_priv, hw); +} + +static int ti_syscon_gate_clk_enable(struct clk_hw *hw) +{ + struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw); + + return regmap_write_bits(priv->regmap, priv->reg, priv->idx, + priv->idx); +} + +static void ti_syscon_gate_clk_disable(struct clk_hw *hw) +{ + struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw); + + regmap_write_bits(priv->regmap, priv->reg, priv->idx, 0); +} + +static int ti_syscon_gate_clk_is_enabled(struct clk_hw *hw) +{ + unsigned int val; + struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw); + + regmap_read(priv->regmap, priv->reg, &val); + + return !!(val & priv->idx); +} + +static const struct clk_ops ti_syscon_gate_clk_ops = { + .enable = ti_syscon_gate_clk_enable, + .disable = ti_syscon_gate_clk_disable, + .is_enabled = ti_syscon_gate_clk_is_enabled, +}; + +static struct clk_hw +*ti_syscon_gate_clk_register(struct device *dev, struct regmap *regmap, + const struct ti_syscon_gate_clk_data *data) +{ + struct ti_syscon_gate_clk_priv *priv; + struct clk_init_data init; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + + init.name = data->name; + init.ops = &ti_syscon_gate_clk_ops; + init.parent_names = NULL; + init.num_parents = 0; + init.flags = 0; + + priv->regmap = regmap; + priv->reg = data->offset; + priv->idx = BIT(data->bit_idx); + priv->hw.init = &init; + + ret = devm_clk_hw_register(dev, &priv->hw); + if (ret) + return ERR_PTR(ret); + + return &priv->hw; +} + +static int ti_syscon_gate_clk_probe(struct platform_device *pdev) +{ + const struct ti_syscon_gate_clk_data *data, *p; + struct clk_hw_onecell_data *hw_data; + struct device *dev = &pdev->dev; + struct regmap *regmap; + int num_clks, i; + + data = device_get_match_data(dev); + if (!data) + return -EINVAL; + + regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(regmap)) { + if (PTR_ERR(regmap) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(dev, "failed to find parent regmap\n"); + return PTR_ERR(regmap); + } + + num_clks = 0; + for (p = data; p->name; p++) + num_clks++; + + hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks), + GFP_KERNEL); + if (!hw_data) + return -ENOMEM; + + hw_data->num = num_clks; + + for (i = 0; i < num_clks; i++) { + hw_data->hws[i] = ti_syscon_gate_clk_register(dev, regmap, + &data[i]); + if (IS_ERR(hw_data->hws[i])) + dev_warn(dev, "failed to register %s\n", + data[i].name); + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + hw_data); +} + +#define TI_SYSCON_CLK_GATE(_name, _offset, _bit_idx) \ + { \ + .name = _name, \ + .offset = (_offset), \ + .bit_idx = (_bit_idx), \ + } + +static const struct ti_syscon_gate_clk_data am654_clk_data[] = { + TI_SYSCON_CLK_GATE("ehrpwm_tbclk0", 0x0, 0), + TI_SYSCON_CLK_GATE("ehrpwm_tbclk1", 0x4, 0), + TI_SYSCON_CLK_GATE("ehrpwm_tbclk2", 0x8, 0), + TI_SYSCON_CLK_GATE("ehrpwm_tbclk3", 0xc, 0), + TI_SYSCON_CLK_GATE("ehrpwm_tbclk4", 0x10, 0), + TI_SYSCON_CLK_GATE("ehrpwm_tbclk5", 0x14, 0), + { /* Sentinel */ }, +}; + +static const struct of_device_id ti_syscon_gate_clk_ids[] = { + { + .compatible = "ti,am654-ehrpwm-tbclk", + .data = &am654_clk_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, ti_syscon_gate_clk_ids); + +static struct platform_driver ti_syscon_gate_clk_driver = { + .probe = ti_syscon_gate_clk_probe, + .driver = { + .name = "ti-syscon-gate-clk", + .of_match_table = ti_syscon_gate_clk_ids, + }, +}; +module_platform_driver(ti_syscon_gate_clk_driver); + +MODULE_AUTHOR("Vignesh Raghavendra "); +MODULE_DESCRIPTION("Syscon backed gate-clock driver"); +MODULE_LICENSE("GPL"); From c067b46d731a764fc46ecc466c2967088c97089e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 13 Feb 2020 13:19:51 -0300 Subject: [PATCH 419/809] clk: ingenic/jz4770: Exit with error if CGU init failed Exit jz4770_cgu_init() if the 'cgu' pointer we get is NULL, since the pointer is passed as argument to functions later on. Fixes: 7a01c19007ad ("clk: Add Ingenic jz4770 CGU driver") Cc: stable@vger.kernel.org Signed-off-by: Paul Cercueil Reported-by: kbuild test robot Reported-by: Dan Carpenter Link: https://lkml.kernel.org/r/20200213161952.37460-1-paul@crapouillou.net Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/jz4770-cgu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c index 956dd653a43d..c051ecba5cf8 100644 --- a/drivers/clk/ingenic/jz4770-cgu.c +++ b/drivers/clk/ingenic/jz4770-cgu.c @@ -432,8 +432,10 @@ static void __init jz4770_cgu_init(struct device_node *np) cgu = ingenic_cgu_new(jz4770_cgu_clocks, ARRAY_SIZE(jz4770_cgu_clocks), np); - if (!cgu) + if (!cgu) { pr_err("%s: failed to initialise CGU\n", __func__); + return; + } retval = ingenic_cgu_register_clocks(cgu); if (retval) From edcc42945dee85e9dec3737f3dbf59d917ae5418 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 13 Feb 2020 13:19:52 -0300 Subject: [PATCH 420/809] clk: ingenic/TCU: Fix round_rate returning error When requesting a rate superior to the parent's rate, it would return -EINVAL instead of simply returning the parent's rate like it should. Fixes: 4f89e4b8f121 ("clk: ingenic: Add driver for the TCU clocks") Cc: stable@vger.kernel.org Signed-off-by: Paul Cercueil Link: https://lkml.kernel.org/r/20200213161952.37460-2-paul@crapouillou.net Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/tcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c index 879990762f57..153a954b0d2f 100644 --- a/drivers/clk/ingenic/tcu.c +++ b/drivers/clk/ingenic/tcu.c @@ -189,7 +189,7 @@ static long ingenic_tcu_round_rate(struct clk_hw *hw, unsigned long req_rate, u8 prescale; if (req_rate > rate) - return -EINVAL; + return rate; prescale = ingenic_tcu_get_prescale(rate, req_rate); From a37a5a9d715f0dc30761bf469f85bc5e02240cf5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 15:55:07 +0200 Subject: [PATCH 421/809] clk: Fix trivia typo in comment exlusive => exclusive Fix trivia typo in comment exlusive => exclusive. Signed-off-by: Andy Shevchenko Link: https://lkml.kernel.org/r/20200310135507.87959-1-andriy.shevchenko@linux.intel.com Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f0f2b599fd7e..1aa21178068f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -774,7 +774,7 @@ static void clk_core_rate_restore_protect(struct clk_core *core, int count) * clk_rate_exclusive_get - get exclusivity over the clk rate control * @clk: the clk over which the exclusity of rate control is requested * - * clk_rate_exlusive_get() begins a critical section during which a clock + * clk_rate_exclusive_get() begins a critical section during which a clock * consumer cannot tolerate any other consumer making any operation on the * clock which could result in a rate change or rate glitch. Exclusive clocks * cannot have their rate changed, either directly or indirectly due to changes From 78c7d8f96b6f61f4974c927097895005ee1140db Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Feb 2020 11:33:24 +0100 Subject: [PATCH 422/809] dt-bindings: clock: Create YAML schema for ICST clocks The ICST clocks used in the ARM Integrator, Versatile and RealView platforms are updated to use YAML schema, and two new ICST clocks used by the Integrator IM-PD1 logical module are added in the process. Cc: devicetree@vger.kernel.org Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Link: https://lkml.kernel.org/r/20200219103326.81120-1-linus.walleij@linaro.org [sboyd@kernel.org: Fix some typos] Signed-off-by: Stephen Boyd --- .../bindings/clock/arm,syscon-icst.yaml | 103 ++++++++++++++++++ .../bindings/clock/arm-integrator.txt | 34 ------ .../bindings/clock/arm-syscon-icst.txt | 70 ------------ 3 files changed, 103 insertions(+), 104 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml delete mode 100644 Documentation/devicetree/bindings/clock/arm-integrator.txt delete mode 100644 Documentation/devicetree/bindings/clock/arm-syscon-icst.txt diff --git a/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml b/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml new file mode 100644 index 000000000000..de9a465096db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/arm,syscon-icst.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM System Controller ICST Clocks + +maintainers: + - Linus Walleij + +description: | + The ICS525 and ICS307 oscillators are produced by Integrated + Devices Technology (IDT). ARM integrated these oscillators deeply into their + reference designs by adding special control registers that manage such + oscillators to their system controllers. + + The various ARM system controllers contain logic to serialize and initialize + an ICST clock request after a write to the 32 bit register at an offset + into the system controller. Furthermore, to even be able to alter one of + these frequencies, the system controller must first be unlocked by + writing a special token to another offset in the system controller. + + Some ARM hardware contain special versions of the serial interface that only + connects the low 8 bits of the VDW (missing one bit), hard-wires RDW to + different values and sometimes also hard-wires the output divider. They + therefore have special compatible strings as per this table (the OD value is + the value on the pins, not the resulting output divider). + + In the core modules and logic tiles, the ICST is a configurable clock fed + from a 24 MHz clock on the motherboard (usually the main crystal) used for + generating e.g. video clocks. It is located on the core module and there is + only one of these. This clock node must be a subnode of the core module. + + Hardware variant RDW OD VDW + + Integrator/AP 22 1 Bit 8 0, rest variable + integratorap-cm + + Integrator/AP 46 3 Bit 8 0, rest variable + integratorap-sys + + Integrator/AP 22 or 1 17 or (33 or 25 MHz) + integratorap-pci 14 1 14 + + Integrator/CP 22 variable Bit 8 0, rest variable + integratorcp-cm-core + + Integrator/CP 22 variable Bit 8 0, rest variable + integratorcp-cm-mem + + The ICST oscillator must be provided inside a system controller node. + +properties: + "#clock-cells": + const: 0 + + compatible: + enum: + - arm,syscon-icst525 + - arm,syscon-icst307 + - arm,syscon-icst525-integratorap-cm + - arm,syscon-icst525-integratorap-sys + - arm,syscon-icst525-integratorap-pci + - arm,syscon-icst525-integratorcp-cm-core + - arm,syscon-icst525-integratorcp-cm-mem + - arm,integrator-cm-auxosc + - arm,versatile-cm-auxosc + - arm,impd-vco1 + - arm,impd-vco2 + + clocks: + description: Parent clock for the ICST VCO + maxItems: 1 + + clock-output-names: + maxItems: 1 + + lock-offset: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: Offset to the unlocking register for the oscillator + + vco-offset: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: Offset to the VCO register for the oscillator + +required: + - "#clock-cells" + - compatible + - clocks + +examples: + - | + vco1: clock@00 { + compatible = "arm,impd1-vco1"; + #clock-cells = <0>; + lock-offset = <0x08>; + vco-offset = <0x00>; + clocks = <&sysclk>; + clock-output-names = "IM-PD1-VCO1"; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/arm-integrator.txt b/Documentation/devicetree/bindings/clock/arm-integrator.txt deleted file mode 100644 index 11f5f95f571b..000000000000 --- a/Documentation/devicetree/bindings/clock/arm-integrator.txt +++ /dev/null @@ -1,34 +0,0 @@ -Clock bindings for ARM Integrator and Versatile Core Module clocks - -Auxiliary Oscillator Clock - -This is a configurable clock fed from a 24 MHz chrystal, -used for generating e.g. video clocks. It is located on the -core module and there is only one of these. - -This clock node *must* be a subnode of the core module, since -it obtains the base address for it's address range from its -parent node. - - -Required properties: -- compatible: must be "arm,integrator-cm-auxosc" or "arm,versatile-cm-auxosc" -- #clock-cells: must be <0> - -Optional properties: -- clocks: parent clock(s) - -Example: - -core-module@10000000 { - xtal24mhz: xtal24mhz@24M { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - }; - auxosc: cm_aux_osc@25M { - #clock-cells = <0>; - compatible = "arm,integrator-cm-auxosc"; - clocks = <&xtal24mhz>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt deleted file mode 100644 index 4cd81742038f..000000000000 --- a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt +++ /dev/null @@ -1,70 +0,0 @@ -ARM System Controller ICST clocks - -The ICS525 and ICS307 oscillators are produced by Integrated Devices -Technology (IDT). ARM integrated these oscillators deeply into their -reference designs by adding special control registers that manage such -oscillators to their system controllers. - -The various ARM system controllers contain logic to serialize and initialize -an ICST clock request after a write to the 32 bit register at an offset -into the system controller. Furthermore, to even be able to alter one of -these frequencies, the system controller must first be unlocked by -writing a special token to another offset in the system controller. - -Some ARM hardware contain special versions of the serial interface that only -connects the low 8 bits of the VDW (missing one bit), hardwires RDW to -different values and sometimes also hardwire the output divider. They -therefore have special compatible strings as per this table (the OD value is -the value on the pins, not the resulting output divider): - -Hardware variant: RDW OD VDW - -Integrator/AP 22 1 Bit 8 0, rest variable -integratorap-cm - -Integrator/AP 46 3 Bit 8 0, rest variable -integratorap-sys - -Integrator/AP 22 or 1 17 or (33 or 25 MHz) -integratorap-pci 14 1 14 - -Integrator/CP 22 variable Bit 8 0, rest variable -integratorcp-cm-core - -Integrator/CP 22 variable Bit 8 0, rest variable -integratorcp-cm-mem - -The ICST oscillator must be provided inside a system controller node. - -Required properties: -- compatible: must be one of - "arm,syscon-icst525" - "arm,syscon-icst307" - "arm,syscon-icst525-integratorap-cm" - "arm,syscon-icst525-integratorap-sys" - "arm,syscon-icst525-integratorap-pci" - "arm,syscon-icst525-integratorcp-cm-core" - "arm,syscon-icst525-integratorcp-cm-mem" -- lock-offset: the offset address into the system controller where the - unlocking register is located -- vco-offset: the offset address into the system controller where the - ICST control register is located (even 32 bit address) -- #clock-cells: must be <0> -- clocks: parent clock, since the ICST needs a parent clock to derive its - frequency from, this attribute is compulsory. - -Example: - -syscon: syscon@10000000 { - compatible = "syscon"; - reg = <0x10000000 0x1000>; - - oscclk0: osc0@c { - compatible = "arm,syscon-icst307"; - #clock-cells = <0>; - lock-offset = <0x20>; - vco-offset = <0x0c>; - clocks = <&xtal24mhz>; - }; - (...) -}; From eb9d6428a7dbd82255b9eabf4ffab54c230b06bc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Feb 2020 11:33:25 +0100 Subject: [PATCH 423/809] clk: versatile: Export icst_clk_setup() Export this clock setup method so we can register the IM-PD1 clocks with common code in the next step. Signed-off-by: Linus Walleij Link: https://lkml.kernel.org/r/20200219103326.81120-2-linus.walleij@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-icst.c | 25 +++++++------------------ drivers/clk/versatile/clk-icst.h | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index fe686f77787f..692be2fd9261 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -33,18 +33,6 @@ #define INTEGRATOR_AP_PCI_25_33_MHZ BIT(8) -/** - * enum icst_control_type - the type of ICST control register - */ -enum icst_control_type { - ICST_VERSATILE, /* The standard type, all control bits available */ - ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ - ICST_INTEGRATOR_AP_SYS, /* Only 8 bits of VDW available */ - ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ - ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ - ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ -}; - /** * struct clk_icst - ICST VCO clock wrapper * @hw: corresponding clock hardware entry @@ -344,12 +332,12 @@ static const struct clk_ops icst_ops = { .set_rate = icst_set_rate, }; -static struct clk *icst_clk_setup(struct device *dev, - const struct clk_icst_desc *desc, - const char *name, - const char *parent_name, - struct regmap *map, - enum icst_control_type ctype) +struct clk *icst_clk_setup(struct device *dev, + const struct clk_icst_desc *desc, + const char *name, + const char *parent_name, + struct regmap *map, + enum icst_control_type ctype) { struct clk *clk; struct clk_icst *icst; @@ -386,6 +374,7 @@ static struct clk *icst_clk_setup(struct device *dev, return clk; } +EXPORT_SYMBOL_GPL(icst_clk_setup); struct clk *icst_clk_register(struct device *dev, const struct clk_icst_desc *desc, diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index e36ca1a20e90..1206f008c11a 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -1,4 +1,18 @@ /* SPDX-License-Identifier: GPL-2.0 */ +struct regmap; + +/** + * enum icst_control_type - the type of ICST control register + */ +enum icst_control_type { + ICST_VERSATILE, /* The standard type, all control bits available */ + ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_SYS, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ + ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ + ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ +}; + /** * struct clk_icst_desc - descriptor for the ICST VCO * @params: ICST parameters @@ -17,3 +31,10 @@ struct clk *icst_clk_register(struct device *dev, const char *name, const char *parent_name, void __iomem *base); + +struct clk *icst_clk_setup(struct device *dev, + const struct clk_icst_desc *desc, + const char *name, + const char *parent_name, + struct regmap *map, + enum icst_control_type ctype); From 84655b762a276f4ad033288954f698e136704178 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Feb 2020 11:33:26 +0100 Subject: [PATCH 424/809] clk: versatile: Add device tree probing for IM-PD1 clocks As we want to move these clocks over to probe from the device tree we add a device tree probing path. The old platform data path will be deleted once we have the device tree overall code in place. Signed-off-by: Linus Walleij Link: https://lkml.kernel.org/r/20200219103326.81120-3-linus.walleij@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-icst.h | 1 + drivers/clk/versatile/clk-impd1.c | 79 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index 1206f008c11a..1a119ef11066 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -11,6 +11,7 @@ enum icst_control_type { ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ + ICST_INTEGRATOR_IM_PD1, /* Like the Versatile, all control bits */ }; /** diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 1991f15a5db9..b05da8516d4c 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -7,7 +7,11 @@ #include #include #include +#include #include +#include +#include +#include #include "icst.h" #include "clk-icst.h" @@ -175,3 +179,78 @@ void integrator_impd1_clk_exit(unsigned int id) kfree(imc->pclkname); } EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit); + +static int integrator_impd1_clk_spawn(struct device *dev, + struct device_node *parent, + struct device_node *np) +{ + struct regmap *map; + struct clk *clk = ERR_PTR(-EINVAL); + const char *name = np->name; + const char *parent_name; + const struct clk_icst_desc *desc; + int ret; + + map = syscon_node_to_regmap(parent); + if (IS_ERR(map)) { + pr_err("no regmap for syscon IM-PD1 ICST clock parent\n"); + return PTR_ERR(map); + } + + if (of_device_is_compatible(np, "arm,impd1-vco1")) { + desc = &impd1_icst1_desc; + } else if (of_device_is_compatible(np, "arm,impd1-vco2")) { + desc = &impd1_icst2_desc; + } else { + dev_err(dev, "not a clock node %s\n", name); + return -ENODEV; + } + + parent_name = of_clk_get_parent_name(np, 0); + clk = icst_clk_setup(NULL, desc, name, parent_name, map, + ICST_INTEGRATOR_IM_PD1); + if (!IS_ERR(clk)) { + of_clk_add_provider(np, of_clk_src_simple_get, clk); + ret = 0; + } else { + dev_err(dev, "error setting up IM-PD1 ICST clock\n"); + ret = PTR_ERR(clk); + } + + return ret; +} + +static int integrator_impd1_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + int ret = 0; + + for_each_available_child_of_node(np, child) { + ret = integrator_impd1_clk_spawn(dev, np, child); + if (ret) + break; + } + + return ret; +} + +static const struct of_device_id impd1_syscon_match[] = { + { .compatible = "arm,im-pd1-syscon", }, + {} +}; +MODULE_DEVICE_TABLE(of, impd1_syscon_match); + +static struct platform_driver impd1_clk_driver = { + .driver = { + .name = "impd1-clk", + .of_match_table = impd1_syscon_match, + }, + .probe = integrator_impd1_clk_probe, +}; +builtin_platform_driver(impd1_clk_driver); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("Arm IM-PD1 module clock driver"); +MODULE_LICENSE("GPL v2"); From 02ff48e4d7f7f253008f3aeadd41c8a2fc640587 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 14 Feb 2020 15:59:33 +0100 Subject: [PATCH 425/809] clk: at91: add at91rm9200 pmc driver Add a driver for the PMC clocks of the at91rm9200. Signed-off-by: Alexandre Belloni Link: https://lkml.kernel.org/r/20200214145934.53648-1-alexandre.belloni@bootlin.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/at91rm9200.c | 199 ++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 drivers/clk/at91/at91rm9200.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 7ab244f346c4..8b90357f2a93 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o +obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c new file mode 100644 index 000000000000..c44a431b6c97 --- /dev/null +++ b/drivers/clk/at91/at91rm9200.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +struct sck { + char *n; + char *p; + u8 id; +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct clk_master_characteristics rm9200_mck_characteristics = { + .output = { .min = 0, .max = 80000000 }, + .divisors = { 1, 2, 3, 4 }, +}; + +static u8 rm9200_pll_out[] = { 0, 2 }; + +static const struct clk_range rm9200_pll_outputs[] = { + { .min = 80000000, .max = 160000000 }, + { .min = 150000000, .max = 180000000 }, +}; + +static const struct clk_pll_characteristics rm9200_pll_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(rm9200_pll_outputs), + .output = rm9200_pll_outputs, + .out = rm9200_pll_out, +}; + +static const struct sck at91rm9200_systemck[] = { + { .n = "udpck", .p = "usbck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 4 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "pck3", .p = "prog3", .id = 11 }, +}; + +static const struct pck at91rm9200_periphck[] = { + { .n = "pioA_clk", .id = 2 }, + { .n = "pioB_clk", .id = 3 }, + { .n = "pioC_clk", .id = 4 }, + { .n = "pioD_clk", .id = 5 }, + { .n = "usart0_clk", .id = 6 }, + { .n = "usart1_clk", .id = 7 }, + { .n = "usart2_clk", .id = 8 }, + { .n = "usart3_clk", .id = 9 }, + { .n = "mci0_clk", .id = 10 }, + { .n = "udc_clk", .id = 11 }, + { .n = "twi0_clk", .id = 12 }, + { .n = "spi0_clk", .id = 13 }, + { .n = "ssc0_clk", .id = 14 }, + { .n = "ssc1_clk", .id = 15 }, + { .n = "ssc2_clk", .id = 16 }, + { .n = "tc0_clk", .id = 17 }, + { .n = "tc1_clk", .id = 18 }, + { .n = "tc2_clk", .id = 19 }, + { .n = "tc3_clk", .id = 20 }, + { .n = "tc4_clk", .id = 21 }, + { .n = "tc5_clk", .id = 22 }, + { .n = "ohci_clk", .id = 23 }, + { .n = "macb0_clk", .id = 24 }, +}; + +static void __init at91rm9200_pmc_setup(struct device_node *np) +{ + const char *slowxtal_name, *mainxtal_name; + struct pmc_data *at91rm9200_pmc; + u32 usb_div[] = { 1, 2, 0, 0 }; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_xtal"); + if (i < 0) + return; + + slowxtal_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = device_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91rm9200_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91rm9200_systemck), + nck(at91rm9200_periphck), 0); + if (!at91rm9200_pmc) + return; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc"); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, + &rm9200_pll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1, + &at91rm9200_pll_layout, + &rm9200_pll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slowxtal_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "pllbck"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91rm9200_master_layout, + &rm9200_mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->chws[PMC_MCK] = hw; + + hw = at91rm9200_clk_register_usb(regmap, "usbck", "pllbck", usb_div); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slowxtal_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "pllbck"; + for (i = 0; i < 4; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 4, i, + &at91rm9200_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91rm9200_systemck); i++) { + hw = at91_clk_register_system(regmap, at91rm9200_systemck[i].n, + at91rm9200_systemck[i].p, + at91rm9200_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->shws[at91rm9200_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) { + hw = at91_clk_register_peripheral(regmap, + at91rm9200_periphck[i].n, + "masterck", + at91rm9200_periphck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->phws[at91rm9200_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91rm9200_pmc); + + return; + +err_free: + pmc_data_free(at91rm9200_pmc); +} +/* + * While the TCB can be used as the clocksource, the system timer is most likely + * to be used instead. However, the pinctrl driver doesn't support probe + * deferring properly. Once this is fixed, this can be switched to a platform + * driver. + */ +CLK_OF_DECLARE_DRIVER(at91rm9200_pmc, "atmel,at91rm9200-pmc", + at91rm9200_pmc_setup); From b3296386c512de4b68242cabac880bc9d24cfdf6 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:38 +0100 Subject: [PATCH 426/809] clk: mmp2: Remove a unused prototype There is no mmp_clk_register_pll2() routine. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-2-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h index 70bb73257647..5bcbced3f458 100644 --- a/drivers/clk/mmp/clk.h +++ b/drivers/clk/mmp/clk.h @@ -124,9 +124,6 @@ extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name, u32 val_disable, unsigned int gate_flags, spinlock_t *lock); - -extern struct clk *mmp_clk_register_pll2(const char *name, - const char *parent_name, unsigned long flags); extern struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name, void __iomem *base, unsigned int delay, unsigned int apbc_flags, spinlock_t *lock); From cb8dbfe831758fb2ba52d8c30db5249e48f57b8b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:39 +0100 Subject: [PATCH 427/809] clk: mmp2: Constify some strings All the parent clock names for the muxes are constant. Add const. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-3-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-mix.c | 2 +- drivers/clk/mmp/clk-of-mmp2.c | 13 +++++++------ drivers/clk/mmp/clk.h | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index d2cd36c54474..7a351ec65564 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -441,7 +441,7 @@ const struct clk_ops mmp_clk_mix_ops = { struct clk *mmp_clk_register_mix(struct device *dev, const char *name, - const char **parent_names, + const char * const *parent_names, u8 num_parents, unsigned long flags, struct mmp_clk_mix_config *config, diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 6e71591e63a0..ee086d971416 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -127,16 +127,16 @@ static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit) static DEFINE_SPINLOCK(uart0_lock); static DEFINE_SPINLOCK(uart1_lock); static DEFINE_SPINLOCK(uart2_lock); -static const char *uart_parent_names[] = {"uart_pll", "vctcxo"}; +static const char * const uart_parent_names[] = {"uart_pll", "vctcxo"}; static DEFINE_SPINLOCK(ssp0_lock); static DEFINE_SPINLOCK(ssp1_lock); static DEFINE_SPINLOCK(ssp2_lock); static DEFINE_SPINLOCK(ssp3_lock); -static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; +static const char * const ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; static DEFINE_SPINLOCK(timer_lock); -static const char *timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"}; +static const char * const timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"}; static DEFINE_SPINLOCK(reset_lock); @@ -190,7 +190,7 @@ static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) } static DEFINE_SPINLOCK(sdh_lock); -static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; +static const char * const sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; static struct mmp_clk_mix_config sdh_mix_config = { .reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32), }; @@ -201,11 +201,12 @@ static DEFINE_SPINLOCK(usbhsic1_lock); static DEFINE_SPINLOCK(disp0_lock); static DEFINE_SPINLOCK(disp1_lock); -static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; +static const char * const disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; static DEFINE_SPINLOCK(ccic0_lock); static DEFINE_SPINLOCK(ccic1_lock); -static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"}; +static const char * const ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"}; + static struct mmp_clk_mix_config ccic0_mix_config = { .reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32), }; diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h index 5bcbced3f458..37d1e1d7b664 100644 --- a/drivers/clk/mmp/clk.h +++ b/drivers/clk/mmp/clk.h @@ -97,7 +97,7 @@ struct mmp_clk_mix { extern const struct clk_ops mmp_clk_mix_ops; extern struct clk *mmp_clk_register_mix(struct device *dev, const char *name, - const char **parent_names, + const char * const *parent_names, u8 num_parents, unsigned long flags, struct mmp_clk_mix_config *config, @@ -193,7 +193,7 @@ void mmp_register_gate_clks(struct mmp_clk_unit *unit, struct mmp_param_mux_clk { unsigned int id; char *name; - const char **parent_name; + const char * const *parent_name; u8 num_parents; unsigned long flags; unsigned long offset; From 7de0b8b8b0508af5fed2f2a07e3abb6acac0c466 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:40 +0100 Subject: [PATCH 428/809] dt-bindings: clock: Convert marvell,mmp2-clock to json-schema Convert the fixed-factor-clock binding to DT schema format using json-schema. While at that, fix a couple of small errors: make the file base name match the compatible string, add an example and document the reg-names property. Signed-off-by: Lubomir Rintel Reviewed-by: Rob Herring Link: https://lkml.kernel.org/r/20200309194254.29009-4-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- .../bindings/clock/marvell,mmp2-clock.yaml | 62 +++++++++++++++++++ .../bindings/clock/marvell,mmp2.txt | 21 ------- 2 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml delete mode 100644 Documentation/devicetree/bindings/clock/marvell,mmp2.txt diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml new file mode 100644 index 000000000000..c5fc2ad0236d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/marvell,mmp2-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MMP2 Clock Controller + +maintainers: + - Lubomir Rintel + +description: | + The MMP2 clock subsystem generates and supplies clock to various + controllers within the MMP2 SoC. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in . + +properties: + compatible: + const: marvell,mmp2-clock # controller compatible with MMP2 SoC + + reg: + items: + - description: MPMU register region + - description: APMU register region + - description: APBC register region + + reg-names: + items: + - const: mpmu + - const: apmu + - const: apbc + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - reg-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@d4050000 { + compatible = "marvell,mmp2-clock"; + reg = <0xd4050000 0x1000>, + <0xd4282800 0x400>, + <0xd4015000 0x1000>; + reg-names = "mpmu", "apmu", "apbc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt deleted file mode 100644 index 23b52dc02266..000000000000 --- a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt +++ /dev/null @@ -1,21 +0,0 @@ -* Marvell MMP2 Clock Controller - -The MMP2 clock subsystem generates and supplies clock to various -controllers within the MMP2 SoC. - -Required Properties: - -- compatible: should be one of the following. - - "marvell,mmp2-clock" - controller compatible with MMP2 SoC. - -- reg: physical base address of the clock subsystem and length of memory mapped - region. There are 3 places in SOC has clock control logic: - "mpmu", "apmu", "apbc". So three reg spaces need to be defined. - -- #clock-cells: should be 1. -- #reset-cells: should be 1. - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifiers could be found in . From 5d34d0b32d6c13947b0aa890fc4c68f203491169 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:41 +0100 Subject: [PATCH 429/809] clk: mmp2: Add support for PLL clock sources The clk-of-mmp2 driver pretends that the clock outputs from the PLLs are constant, but in fact they are configurable. Add logic for obtaining the actual clock rates on MMP2 as well as MMP3. There is no documentation for either SoC, but the "systemsetting" drivers from Marvell GPL code dump provide some clue as far as MPMU registers on MMP2 [1] and MMP3 [2] go. [1] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp2_systemsetting.c [2] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp3_systemsetting.c A separate commit will adjust the clk-of-mmp2 driver. Tested on a MMP3-based Dell Wyse 3020 as well as MMP2-based OLPC XO-1.75 laptop. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-5-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/Makefile | 2 +- drivers/clk/mmp/clk-pll.c | 139 ++++++++++++++++++++++++++++++++++++++ drivers/clk/mmp/clk.c | 31 +++++++++ drivers/clk/mmp/clk.h | 24 +++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mmp/clk-pll.c diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index acc141adf087..14dc8a8a9d08 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -8,7 +8,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o -obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o +obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o diff --git a/drivers/clk/mmp/clk-pll.c b/drivers/clk/mmp/clk-pll.c new file mode 100644 index 000000000000..7077be293871 --- /dev/null +++ b/drivers/clk/mmp/clk-pll.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MMP PLL clock rate calculation + * + * Copyright (C) 2020 Lubomir Rintel + */ + +#include +#include +#include + +#include "clk.h" + +#define to_clk_mmp_pll(hw) container_of(hw, struct mmp_clk_pll, hw) + +struct mmp_clk_pll { + struct clk_hw hw; + unsigned long default_rate; + void __iomem *enable_reg; + u32 enable; + void __iomem *reg; + u8 shift; + + unsigned long input_rate; + void __iomem *postdiv_reg; + u8 postdiv_shift; +}; + +static int mmp_clk_pll_is_enabled(struct clk_hw *hw) +{ + struct mmp_clk_pll *pll = to_clk_mmp_pll(hw); + u32 val; + + val = readl_relaxed(pll->enable_reg); + if ((val & pll->enable) == pll->enable) + return 1; + + /* Some PLLs, if not software controlled, output default clock. */ + if (pll->default_rate > 0) + return 1; + + return 0; +} + +static unsigned long mmp_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mmp_clk_pll *pll = to_clk_mmp_pll(hw); + u32 fbdiv, refdiv, postdiv; + u64 rate; + u32 val; + + val = readl_relaxed(pll->enable_reg); + if ((val & pll->enable) != pll->enable) + return pll->default_rate; + + if (pll->reg) { + val = readl_relaxed(pll->reg); + fbdiv = (val >> pll->shift) & 0x1ff; + refdiv = (val >> (pll->shift + 9)) & 0x1f; + } else { + fbdiv = 2; + refdiv = 1; + } + + if (pll->postdiv_reg) { + /* MMP3 clock rate calculation */ + static const u8 postdivs[] = {2, 3, 4, 5, 6, 8, 10, 12, 16}; + + val = readl_relaxed(pll->postdiv_reg); + postdiv = (val >> pll->postdiv_shift) & 0x7; + + rate = pll->input_rate; + rate *= 2 * fbdiv; + do_div(rate, refdiv); + do_div(rate, postdivs[postdiv]); + } else { + /* MMP2 clock rate calculation */ + if (refdiv == 3) { + rate = 19200000; + } else if (refdiv == 4) { + rate = 26000000; + } else { + pr_err("bad refdiv: %d (0x%08x)\n", refdiv, val); + return 0; + } + + rate *= fbdiv + 2; + do_div(rate, refdiv + 2); + } + + return (unsigned long)rate; +} + +static const struct clk_ops mmp_clk_pll_ops = { + .is_enabled = mmp_clk_pll_is_enabled, + .recalc_rate = mmp_clk_pll_recalc_rate, +}; + +struct clk *mmp_clk_register_pll(char *name, + unsigned long default_rate, + void __iomem *enable_reg, u32 enable, + void __iomem *reg, u8 shift, + unsigned long input_rate, + void __iomem *postdiv_reg, u8 postdiv_shift) +{ + struct mmp_clk_pll *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &mmp_clk_pll_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + + pll->default_rate = default_rate; + pll->enable_reg = enable_reg; + pll->enable = enable; + pll->reg = reg; + pll->shift = shift; + + pll->input_rate = input_rate; + pll->postdiv_reg = postdiv_reg; + pll->postdiv_shift = postdiv_shift; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c index ca7d37e2c7be..317123641d1e 100644 --- a/drivers/clk/mmp/clk.c +++ b/drivers/clk/mmp/clk.c @@ -176,6 +176,37 @@ void mmp_register_div_clks(struct mmp_clk_unit *unit, } } +void mmp_register_pll_clks(struct mmp_clk_unit *unit, + struct mmp_param_pll_clk *clks, + void __iomem *base, int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + void __iomem *reg = NULL; + + if (clks[i].offset) + reg = base + clks[i].offset; + + clk = mmp_clk_register_pll(clks[i].name, + clks[i].default_rate, + base + clks[i].enable_offset, + clks[i].enable, + reg, clks[i].shift, + clks[i].input_rate, + base + clks[i].postdiv_offset, + clks[i].postdiv_shift); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id, struct clk *clk) { diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h index 37d1e1d7b664..971b4d6d992f 100644 --- a/drivers/clk/mmp/clk.h +++ b/drivers/clk/mmp/clk.h @@ -221,6 +221,30 @@ void mmp_register_div_clks(struct mmp_clk_unit *unit, struct mmp_param_div_clk *clks, void __iomem *base, int size); +struct mmp_param_pll_clk { + unsigned int id; + char *name; + unsigned long default_rate; + unsigned long enable_offset; + u32 enable; + unsigned long offset; + u8 shift; + /* MMP3 specific: */ + unsigned long input_rate; + unsigned long postdiv_offset; + unsigned long postdiv_shift; +}; +void mmp_register_pll_clks(struct mmp_clk_unit *unit, + struct mmp_param_pll_clk *clks, + void __iomem *base, int size); + +extern struct clk *mmp_clk_register_pll(char *name, + unsigned long default_rate, + void __iomem *enable_reg, u32 enable, + void __iomem *reg, u8 shift, + unsigned long input_rate, + void __iomem *postdiv_reg, u8 postdiv_shift); + #define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \ { \ .width_div = (w_d), \ From ea56ad60260ec767d9a93f71f7baabcb618eb92d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:42 +0100 Subject: [PATCH 430/809] clk: mmp2: Stop pretending PLL outputs are constant The hardcoded values for PLL1 and PLL2 are wrong. PLL1 is slightly off -- it defaults to 797.33 MHz, not 800 MHz. PLL2 is disabled by default, but also configurable. Tested on a MMP2-based OLPC XO-1.75 laptop, with PLL1=797.33 and various values of PLL2 set via set-pll2-520mhz, set-pll2-910mhz and set-pll2-988mhz Open Firmware words. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-6-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index ee086d971416..251d8d0e78ab 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Marvell * Chao Xie + * Copyright (C) 2020 Lubomir Rintel * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -55,7 +56,11 @@ #define APMU_CCIC1 0xf4 #define APMU_USBHSIC0 0xf8 #define APMU_USBHSIC1 0xfc + +#define MPMU_FCCR 0x8 +#define MPMU_POSR 0x10 #define MPMU_UART_PLL 0x14 +#define MPMU_PLL2_CR 0x34 struct mmp2_clk_unit { struct mmp_clk_unit unit; @@ -67,11 +72,14 @@ struct mmp2_clk_unit { static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { {MMP2_CLK_CLK32, "clk32", NULL, 0, 32768}, {MMP2_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000}, - {MMP2_CLK_PLL1, "pll1", NULL, 0, 800000000}, - {MMP2_CLK_PLL2, "pll2", NULL, 0, 960000000}, {MMP2_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000}, }; +static struct mmp_param_pll_clk pll_clks[] = { + {MMP2_CLK_PLL1, "pll1", 797330000, MPMU_FCCR, 0x4000, MPMU_POSR, 0}, + {MMP2_CLK_PLL2, "pll2", 0, MPMU_PLL2_CR, 0x0300, MPMU_PLL2_CR, 10}, +}; + static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { {MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, {MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, @@ -113,6 +121,10 @@ static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit) mmp_register_fixed_rate_clks(unit, fixed_rate_clks, ARRAY_SIZE(fixed_rate_clks)); + mmp_register_pll_clks(unit, pll_clks, + pxa_unit->mpmu_base, + ARRAY_SIZE(pll_clks)); + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, ARRAY_SIZE(fixed_factor_clks)); From b90e0eb304292230a5d4004e0cd8b0ceba941d99 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:43 +0100 Subject: [PATCH 431/809] dt-bindings: clock: Add MMP3 compatible string This binding describes the PMUs that are found on MMP3 as well. Add the compatible strings and adjust the description. Signed-off-by: Lubomir Rintel Reviewed-by: Rob Herring Link: https://lkml.kernel.org/r/20200309194254.29009-7-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/marvell,mmp2-clock.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml index c5fc2ad0236d..e2b6ac96bbcb 100644 --- a/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml +++ b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml @@ -4,14 +4,14 @@ $id: http://devicetree.org/schemas/clock/marvell,mmp2-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Marvell MMP2 Clock Controller +title: Marvell MMP2 and MMP3 Clock Controller maintainers: - Lubomir Rintel description: | - The MMP2 clock subsystem generates and supplies clock to various - controllers within the MMP2 SoC. + The clock subsystem on MMP2 or MMP3 generates and supplies clock to various + controllers within the SoC. Each clock is assigned an identifier and client nodes use this identifier to specify the clock which they consume. @@ -20,7 +20,9 @@ description: | properties: compatible: - const: marvell,mmp2-clock # controller compatible with MMP2 SoC + enum: + - marvell,mmp2-clock # controller compatible with MMP2 SoC + - marvell,mmp3-clock # controller compatible with MMP3 SoC reg: items: From 391bbbd2b28e9868e36080bd0fa44dcae81707a1 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:44 +0100 Subject: [PATCH 432/809] clk: mmp2: Check for MMP3 The MMP3's are similar enough to MMP2, but there are differencies, such are more clocks available on the newer model. We want to tell which platform are we on. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-8-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 251d8d0e78ab..7594a8280b93 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -62,8 +62,14 @@ #define MPMU_UART_PLL 0x14 #define MPMU_PLL2_CR 0x34 +enum mmp2_clk_model { + CLK_MODEL_MMP2, + CLK_MODEL_MMP3, +}; + struct mmp2_clk_unit { struct mmp_clk_unit unit; + enum mmp2_clk_model model; void __iomem *mpmu_base; void __iomem *apmu_base; void __iomem *apbc_base; @@ -326,6 +332,11 @@ static void __init mmp2_clk_init(struct device_node *np) if (!pxa_unit) return; + if (of_device_is_compatible(np, "marvell,mmp3-clock")) + pxa_unit->model = CLK_MODEL_MMP3; + else + pxa_unit->model = CLK_MODEL_MMP2; + pxa_unit->mpmu_base = of_iomap(np, 0); if (!pxa_unit->mpmu_base) { pr_err("failed to map mpmu registers\n"); @@ -365,3 +376,4 @@ free_memory: } CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init); +CLK_OF_DECLARE(mmp3_clk, "marvell,mmp3-clock", mmp2_clk_init); From 4d6da655d1871fadcb2b5de086e5a35883e22c95 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:45 +0100 Subject: [PATCH 433/809] dt-bindings: marvell,mmp2: Add clock ids for MMP3 PLLs MMP3 variant provides some more clocks. Add respective IDs. Signed-off-by: Lubomir Rintel Acked-by: Rob Herring Link: https://lkml.kernel.org/r/20200309194254.29009-9-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/marvell,mmp2.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index 4b1a7724f20d..22006392b411 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -26,6 +26,9 @@ #define MMP2_CLK_VCTCXO_4 25 #define MMP2_CLK_UART_PLL 26 #define MMP2_CLK_USB_PLL 27 +#define MMP3_CLK_PLL1_P 28 +#define MMP3_CLK_PLL2_P 29 +#define MMP3_CLK_PLL3 30 /* apb periphrals */ #define MMP2_CLK_TWSI0 60 From a70812b1881566001e001dfe966ea724d889c071 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:46 +0100 Subject: [PATCH 434/809] clk: mmp2: Add PLLs that are available on MMP3 There are more PLLs on MMP3 and are configured slightly differently. Tested on a MMP3-based Dell Wyse 3020 machine. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-10-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 7594a8280b93..310d77855f03 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -57,10 +57,16 @@ #define APMU_USBHSIC0 0xf8 #define APMU_USBHSIC1 0xfc -#define MPMU_FCCR 0x8 -#define MPMU_POSR 0x10 -#define MPMU_UART_PLL 0x14 -#define MPMU_PLL2_CR 0x34 +#define MPMU_FCCR 0x8 +#define MPMU_POSR 0x10 +#define MPMU_UART_PLL 0x14 +#define MPMU_PLL2_CR 0x34 +/* MMP3 specific below */ +#define MPMU_PLL3_CR 0x50 +#define MPMU_PLL3_CTRL1 0x58 +#define MPMU_PLL1_CTRL 0x5c +#define MPMU_PLL_DIFF_CTRL 0x68 +#define MPMU_PLL2_CTRL1 0x414 enum mmp2_clk_model { CLK_MODEL_MMP2, @@ -86,6 +92,14 @@ static struct mmp_param_pll_clk pll_clks[] = { {MMP2_CLK_PLL2, "pll2", 0, MPMU_PLL2_CR, 0x0300, MPMU_PLL2_CR, 10}, }; +static struct mmp_param_pll_clk mmp3_pll_clks[] = { + {MMP2_CLK_PLL2, "pll1", 797330000, MPMU_FCCR, 0x4000, MPMU_POSR, 0, 26000000, MPMU_PLL1_CTRL, 25}, + {MMP2_CLK_PLL2, "pll2", 0, MPMU_PLL2_CR, 0x0300, MPMU_PLL2_CR, 10, 26000000, MPMU_PLL2_CTRL1, 25}, + {MMP3_CLK_PLL1_P, "pll1_p", 0, MPMU_PLL_DIFF_CTRL, 0x0010, 0, 0, 797330000, MPMU_PLL_DIFF_CTRL, 0}, + {MMP3_CLK_PLL2_P, "pll2_p", 0, MPMU_PLL_DIFF_CTRL, 0x0100, MPMU_PLL2_CR, 10, 26000000, MPMU_PLL_DIFF_CTRL, 5}, + {MMP3_CLK_PLL3, "pll3", 0, MPMU_PLL3_CR, 0x0300, MPMU_PLL3_CR, 10, 26000000, MPMU_PLL3_CTRL1, 25}, +}; + static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { {MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, {MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, @@ -127,9 +141,15 @@ static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit) mmp_register_fixed_rate_clks(unit, fixed_rate_clks, ARRAY_SIZE(fixed_rate_clks)); - mmp_register_pll_clks(unit, pll_clks, - pxa_unit->mpmu_base, - ARRAY_SIZE(pll_clks)); + if (pxa_unit->model == CLK_MODEL_MMP3) { + mmp_register_pll_clks(unit, mmp3_pll_clks, + pxa_unit->mpmu_base, + ARRAY_SIZE(mmp3_pll_clks)); + } else { + mmp_register_pll_clks(unit, pll_clks, + pxa_unit->mpmu_base, + ARRAY_SIZE(pll_clks)); + } mmp_register_fixed_factor_clks(unit, fixed_factor_clks, ARRAY_SIZE(fixed_factor_clks)); From e3142226fe11d7a9de2887d80a631a6108ba60c5 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:48 +0100 Subject: [PATCH 435/809] dt-bindings: marvell,mmp2: Add clock ids for the GPU clocks MMP2 has a single GC860 core while MMP3 has a GC2000 and a GC300. On both platforms there's an AXI bus interface clock that's common for all GPUs and each GPU core has a separate clock. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-12-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/marvell,mmp2.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index 22006392b411..dd5067bd92f2 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -77,6 +77,11 @@ #define MMP2_CLK_DISP0_LCDC 120 #define MMP2_CLK_USBHSIC0 121 #define MMP2_CLK_USBHSIC1 122 +#define MMP2_CLK_GPU_BUS 123 +#define MMP3_CLK_GPU_BUS MMP2_CLK_GPU_BUS +#define MMP2_CLK_GPU_3D 124 +#define MMP3_CLK_GPU_3D MMP2_CLK_GPU_3D +#define MMP3_CLK_GPU_2D 125 #define MMP2_NR_CLKS 200 #endif From bfa851b60c8a41d2c419b3846f74928bc31d7ad9 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:49 +0100 Subject: [PATCH 436/809] clk: mmp2: add the GPU clocks MMP2 has a single GC860 core while MMP3 has a GC2000 and a GC300. On both platforms there's an AXI bus interface clock that's common for all GPUs and each GPU core has a separate clock. Meaning of the relevant APMU_GPU bits were gotten from James Cameron's message and [1], the OLPC OS kernel source [2] and Marvell's MMP3 tree. [1] http://lists.laptop.org/pipermail/devel/2019-April/039053.html [2] http://dev.laptop.org/git/olpc-kernel/commit/arch/arm/mach-mmp/mmp2.c?h=arm-3.0-wip&id=8ce9f6122 Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-13-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 310d77855f03..208c67df482a 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -56,6 +56,7 @@ #define APMU_CCIC1 0xf4 #define APMU_USBHSIC0 0xf8 #define APMU_USBHSIC1 0xfc +#define APMU_GPU 0xcc #define MPMU_FCCR 0x8 #define MPMU_POSR 0x10 @@ -245,6 +246,14 @@ static DEFINE_SPINLOCK(ccic0_lock); static DEFINE_SPINLOCK(ccic1_lock); static const char * const ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"}; +static DEFINE_SPINLOCK(gpu_lock); +static const char * const mmp2_gpu_gc_parent_names[] = {"pll1_2", "pll1_3", "pll2_2", "pll2_3", "pll2", "usb_pll"}; +static u32 mmp2_gpu_gc_parent_table[] = { 0x0000, 0x0040, 0x0080, 0x00c0, 0x1000, 0x1040 }; +static const char * const mmp2_gpu_bus_parent_names[] = {"pll1_4", "pll2", "pll2_2", "usb_pll"}; +static u32 mmp2_gpu_bus_parent_table[] = { 0x0000, 0x0020, 0x0030, 0x4020 }; +static const char * const mmp3_gpu_bus_parent_names[] = {"pll1_4", "pll1_6", "pll1_2", "pll2_2"}; +static const char * const mmp3_gpu_gc_parent_names[] = {"pll1", "pll2", "pll1_p", "pll2_p"}; + static struct mmp_clk_mix_config ccic0_mix_config = { .reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32), }; @@ -257,6 +266,15 @@ static struct mmp_param_mux_clk apmu_mux_clks[] = { {MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock}, }; +static struct mmp_param_mux_clk mmp3_apmu_mux_clks[] = { + {0, "gpu_bus_mux", mmp3_gpu_bus_parent_names, ARRAY_SIZE(mmp3_gpu_bus_parent_names), + CLK_SET_RATE_PARENT, APMU_GPU, 4, 2, 0, &gpu_lock}, + {0, "gpu_3d_mux", mmp3_gpu_gc_parent_names, ARRAY_SIZE(mmp3_gpu_gc_parent_names), + CLK_SET_RATE_PARENT, APMU_GPU, 6, 2, 0, &gpu_lock}, + {0, "gpu_2d_mux", mmp3_gpu_gc_parent_names, ARRAY_SIZE(mmp3_gpu_gc_parent_names), + CLK_SET_RATE_PARENT, APMU_GPU, 12, 2, 0, &gpu_lock}, +}; + static struct mmp_param_div_clk apmu_div_clks[] = { {0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock}, {0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock}, @@ -265,6 +283,11 @@ static struct mmp_param_div_clk apmu_div_clks[] = { {0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock}, }; +static struct mmp_param_div_clk mmp3_apmu_div_clks[] = { + {0, "gpu_3d_div", "gpu_3d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 24, 4, 0, &gpu_lock}, + {0, "gpu_2d_div", "gpu_2d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 28, 4, 0, &gpu_lock}, +}; + static struct mmp_param_gate_clk apmu_gate_clks[] = { {MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, {MMP2_CLK_USBHSIC0, "usbhsic0_clk", "usb_pll", 0, APMU_USBHSIC0, 0x1b, 0x1b, 0x0, 0, &usbhsic0_lock}, @@ -285,6 +308,16 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = { {MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock}, {MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock}, {MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock}, + {MMP2_CLK_GPU_BUS, "gpu_bus_clk", "gpu_bus_mux", CLK_SET_RATE_PARENT, APMU_GPU, 0xa, 0xa, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, +}; + +static struct mmp_param_gate_clk mmp2_apmu_gate_clks[] = { + {MMP2_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, +}; + +static struct mmp_param_gate_clk mmp3_apmu_gate_clks[] = { + {MMP3_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, + {MMP3_CLK_GPU_2D, "gpu_2d_clk", "gpu_2d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x1c0000, 0x1c0000, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, }; static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit) @@ -320,6 +353,34 @@ static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit) mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, ARRAY_SIZE(apmu_gate_clks)); + + if (pxa_unit->model == CLK_MODEL_MMP3) { + mmp_register_mux_clks(unit, mmp3_apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(mmp3_apmu_mux_clks)); + + mmp_register_div_clks(unit, mmp3_apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(mmp3_apmu_div_clks)); + + mmp_register_gate_clks(unit, mmp3_apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(mmp3_apmu_gate_clks)); + } else { + clk_register_mux_table(NULL, "gpu_3d_mux", mmp2_gpu_gc_parent_names, + ARRAY_SIZE(mmp2_gpu_gc_parent_names), + CLK_SET_RATE_PARENT, + pxa_unit->apmu_base + APMU_GPU, + 0, 0x10c0, 0, + mmp2_gpu_gc_parent_table, &gpu_lock); + + clk_register_mux_table(NULL, "gpu_bus_mux", mmp2_gpu_bus_parent_names, + ARRAY_SIZE(mmp2_gpu_bus_parent_names), + CLK_SET_RATE_PARENT, + pxa_unit->apmu_base + APMU_GPU, + 0, 0x4030, 0, + mmp2_gpu_bus_parent_table, &gpu_lock); + + mmp_register_gate_clks(unit, mmp2_apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(mmp2_apmu_gate_clks)); + } } static void mmp2_clk_reset_init(struct device_node *np, From 41a8632049ac09d22bf71039fd945774c75de6ec Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:50 +0100 Subject: [PATCH 437/809] dt-bindings: marvell,mmp2: Add clock ids for the thermal sensors There seems to be a single thermal sensor block on MMP2 and a couple more on MMP3. Add definitions for their respective clocks. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-14-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/marvell,mmp2.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index dd5067bd92f2..2793fdf30006 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -53,6 +53,10 @@ #define MMP2_CLK_SSP2 79 #define MMP2_CLK_SSP3 80 #define MMP2_CLK_TIMER 81 +#define MMP2_CLK_THERMAL0 82 +#define MMP3_CLK_THERMAL1 83 +#define MMP3_CLK_THERMAL2 84 +#define MMP3_CLK_THERMAL3 85 /* axi periphrals */ #define MMP2_CLK_SDH0 101 From 82d59c382c230fb26fe193c9e1b5239d8fcb2d77 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:51 +0100 Subject: [PATCH 438/809] clk: mmp2: Add clocks for the thermal sensors The register definitions gotten from OLPC Open Firmware. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-15-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 208c67df482a..0057a53905d8 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -54,6 +54,10 @@ #define APMU_DISP1 0x110 #define APMU_CCIC0 0x50 #define APMU_CCIC1 0xf4 +#define APBC_THERMAL0 0x90 +#define APBC_THERMAL1 0x98 +#define APBC_THERMAL2 0x9c +#define APBC_THERMAL3 0xa0 #define APMU_USBHSIC0 0xf8 #define APMU_USBHSIC1 0xfc #define APMU_GPU 0xcc @@ -215,6 +219,13 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = { {MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock}, {MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock}, {MMP2_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x7, 0x3, 0x0, 0, &timer_lock}, + {MMP2_CLK_THERMAL0, "thermal0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL0, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, +}; + +static struct mmp_param_gate_clk mmp3_apbc_gate_clks[] = { + {MMP3_CLK_THERMAL1, "thermal1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL1, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP3_CLK_THERMAL2, "thermal2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL2, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP3_CLK_THERMAL3, "thermal3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL3, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, }; static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) @@ -226,6 +237,11 @@ static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, ARRAY_SIZE(apbc_gate_clks)); + + if (pxa_unit->model == CLK_MODEL_MMP3) { + mmp_register_gate_clks(unit, mmp3_apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(mmp3_apbc_gate_clks)); + } } static DEFINE_SPINLOCK(sdh_lock); From c2ca122a0a3901596ae387d134e4c6d6f6216bf1 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:52 +0100 Subject: [PATCH 439/809] dt-bindings: marvell,mmp2: Add clock id for the fifth SD HCI on MMP3 There's one extra SDHCI on MMP3, used by the internal SD card on OLPC XO-4. Add a clock for it. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-16-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/marvell,mmp2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index 2793fdf30006..06bb7fe4c62f 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -86,6 +86,7 @@ #define MMP2_CLK_GPU_3D 124 #define MMP3_CLK_GPU_3D MMP2_CLK_GPU_3D #define MMP3_CLK_GPU_2D 125 +#define MMP3_CLK_SDH4 126 #define MMP2_NR_CLKS 200 #endif From 54198276badf2cd74f799ec61b0e0afcd958efdb Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:53 +0100 Subject: [PATCH 440/809] clk: mmp2: Add clock for fifth SD HCI on MMP3 There's one extra SDHCI on MMP3, used by the internal SD card on OLPC XO-4. Add a clock for it. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-17-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 0057a53905d8..8769860fab64 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -49,6 +49,7 @@ #define APMU_SDH1 0x58 #define APMU_SDH2 0xe8 #define APMU_SDH3 0xec +#define APMU_SDH4 0x15c #define APMU_USB 0x5c #define APMU_DISP0 0x4c #define APMU_DISP1 0x110 @@ -332,6 +333,7 @@ static struct mmp_param_gate_clk mmp2_apmu_gate_clks[] = { }; static struct mmp_param_gate_clk mmp3_apmu_gate_clks[] = { + {MMP3_CLK_SDH4, "sdh4_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH4, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP3_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, {MMP3_CLK_GPU_2D, "gpu_2d_clk", "gpu_2d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x1c0000, 0x1c0000, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock}, }; From de17be999cb07effacf6a1129602f63396f5af27 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Mar 2020 20:42:54 +0100 Subject: [PATCH 441/809] clk: mmp2: Fix bit masks for LCDC I/O and pixel clocks They were reversed because I read the datasheet upside down. Actually there is no datasheet, but I ended up understanding the comments in Open Firmware driver wrong. Signed-off-by: Lubomir Rintel Link: https://lkml.kernel.org/r/20200309194254.29009-18-lkundrak@v3.sk Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 8769860fab64..52dc8b43acd9 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -314,8 +314,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = { {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x09, 0x09, 0x0, 0, &disp0_lock}, - {MMP2_CLK_DISP0_LCDC, "disp0_lcdc_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x12, 0x12, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x12, 0x12, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0_LCDC, "disp0_lcdc_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x09, 0x09, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x09, 0x09, 0x0, 0, &disp1_lock}, {MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock}, From df11b323b16fce74d32571c2f80074df41df002d Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 7 Feb 2020 16:18:11 +1300 Subject: [PATCH 442/809] rtc: ds1307: handle oscillator failure flags for ds1388 variant The FLAG register is at a different location to the other supported RTCs so this requires an extra case in the existing switch statement. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20200207031812.14424-2-chris.packham@alliedtelesis.co.nz Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 1f7e8aefc1eb..31a38d468378 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -144,6 +144,8 @@ enum ds_type { # define M41TXX_BIT_CALIB_SIGN BIT(5) # define M41TXX_M_CALIBRATION GENMASK(4, 0) +#define DS1388_REG_FLAG 0x0b +# define DS1388_BIT_OSF BIT(7) /* negative offset step is -2.034ppm */ #define M41TXX_NEG_OFFSET_STEP_PPB 2034 /* positive offset step is +4.068ppm */ @@ -252,6 +254,13 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) if (tmp & DS1340_BIT_OSF) return -EINVAL; break; + case ds_1388: + ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp); + if (ret) + return ret; + if (tmp & DS1388_BIT_OSF) + return -EINVAL; + break; case mcp794xx: if (!(tmp & MCP794XX_BIT_ST)) return -EINVAL; From fdc9f0eace99b288d5ef5cc7489699bf7b2d9e36 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 16 Mar 2020 17:09:45 +0800 Subject: [PATCH 443/809] rtc: mxc: Use devm_add_action_or_reset() for calls to clk_disable_unprepare() Use devm_add_action_or_reset() for calls to clk_disable_unprepare(), which can simplify the error handling, and .remove callback can be dropped. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1584349785-27042-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mxc.c | 46 ++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 902d57dcd0d4..a8cfbde048f4 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -307,6 +307,14 @@ static const struct rtc_class_ops mxc_rtc_ops = { .alarm_irq_enable = mxc_rtc_alarm_irq_enable, }; +static void mxc_rtc_action(void *p) +{ + struct rtc_plat_data *pdata = p; + + clk_disable_unprepare(pdata->clk_ref); + clk_disable_unprepare(pdata->clk_ipg); +} + static int mxc_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; @@ -366,14 +374,20 @@ static int mxc_rtc_probe(struct platform_device *pdev) pdata->clk_ref = devm_clk_get(&pdev->dev, "ref"); if (IS_ERR(pdata->clk_ref)) { + clk_disable_unprepare(pdata->clk_ipg); dev_err(&pdev->dev, "unable to get ref clock!\n"); - ret = PTR_ERR(pdata->clk_ref); - goto exit_put_clk_ipg; + return PTR_ERR(pdata->clk_ref); } ret = clk_prepare_enable(pdata->clk_ref); + if (ret) { + clk_disable_unprepare(pdata->clk_ipg); + return ret; + } + + ret = devm_add_action_or_reset(&pdev->dev, mxc_rtc_action, pdata); if (ret) - goto exit_put_clk_ipg; + return ret; rate = clk_get_rate(pdata->clk_ref); @@ -385,16 +399,14 @@ static int mxc_rtc_probe(struct platform_device *pdev) reg = RTC_INPUT_CLK_38400HZ; else { dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate); - ret = -EINVAL; - goto exit_put_clk_ref; + return -EINVAL; } reg |= RTC_ENABLE_BIT; writew(reg, (pdata->ioaddr + RTC_RTCCTL)); if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { dev_err(&pdev->dev, "hardware module can't be enabled!\n"); - ret = -EIO; - goto exit_put_clk_ref; + return -EIO; } platform_set_drvdata(pdev, pdata); @@ -417,29 +429,10 @@ static int mxc_rtc_probe(struct platform_device *pdev) } ret = rtc_register_device(rtc); - if (ret) - goto exit_put_clk_ref; - - return 0; - -exit_put_clk_ref: - clk_disable_unprepare(pdata->clk_ref); -exit_put_clk_ipg: - clk_disable_unprepare(pdata->clk_ipg); return ret; } -static int mxc_rtc_remove(struct platform_device *pdev) -{ - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - - clk_disable_unprepare(pdata->clk_ref); - clk_disable_unprepare(pdata->clk_ipg); - - return 0; -} - static struct platform_driver mxc_rtc_driver = { .driver = { .name = "mxc_rtc", @@ -447,7 +440,6 @@ static struct platform_driver mxc_rtc_driver = { }, .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, - .remove = mxc_rtc_remove, }; module_platform_driver(mxc_rtc_driver) From 929a3270488956316214d70cd4e2ba3fa56ffe31 Mon Sep 17 00:00:00 2001 From: Peng Ma Date: Wed, 18 Mar 2020 10:53:54 +0800 Subject: [PATCH 444/809] rtc: fsl-ftm-alarm: enable acpi support This patch enables ACPI support in Rtc Flex timer driver. Signed-off-by: Peng Ma Link: https://lore.kernel.org/r/20200318025354.6447-1-peng.ma@nxp.com Link: https://lore.kernel.org/r/20200323072956.38263-1-peng.ma@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-fsl-ftm-alarm.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index 9e6e994cce99..0f4142b35f38 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -20,6 +20,7 @@ #include #include #include +#include #define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT) @@ -242,7 +243,6 @@ static const struct rtc_class_ops ftm_rtc_ops = { static int ftm_rtc_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; int irq; int ret; struct ftm_rtc *rtc; @@ -265,10 +265,10 @@ static int ftm_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc->base); } - irq = irq_of_parse_and_map(np, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "unable to get IRQ from DT, %d\n", irq); - return -EINVAL; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "can't get irq number\n"); + return irq; } ret = devm_request_irq(&pdev->dev, irq, ftm_rtc_alarm_interrupt, @@ -278,7 +278,9 @@ static int ftm_rtc_probe(struct platform_device *pdev) return ret; } - rtc->big_endian = of_property_read_bool(np, "big-endian"); + rtc->big_endian = + device_property_read_bool(&pdev->dev, "big-endian"); + rtc->alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV; rtc->rtc_dev->ops = &ftm_rtc_ops; @@ -305,11 +307,18 @@ static const struct of_device_id ftm_rtc_match[] = { { }, }; +static const struct acpi_device_id ftm_imx_acpi_ids[] = { + {"NXP0011",}, + { } +}; +MODULE_DEVICE_TABLE(acpi, ftm_imx_acpi_ids); + static struct platform_driver ftm_rtc_driver = { .probe = ftm_rtc_probe, .driver = { .name = "ftm-alarm", .of_match_table = ftm_rtc_match, + .acpi_match_table = ACPI_PTR(ftm_imx_acpi_ids), }, }; From c05a31f4d1de8f49f66f499e67da9c3d745c4f19 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 18 Mar 2020 15:26:49 +0000 Subject: [PATCH 445/809] rtc: max8907: add missing select REGMAP_IRQ I have hit the following build error: armv7a-hardfloat-linux-gnueabi-ld: drivers/rtc/rtc-max8907.o: in function `max8907_rtc_probe': rtc-max8907.c:(.text+0x400): undefined reference to `regmap_irq_get_virq' max8907 should select REGMAP_IRQ Fixes: 94c01ab6d7544 ("rtc: add MAX8907 RTC driver") Cc: stable Signed-off-by: Corentin Labbe Link: https://lore.kernel.org/r/1584545209-20433-1-git-send-email-clabbe@baylibre.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7d6cb60ee010..6c99156cbe57 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -327,6 +327,7 @@ config RTC_DRV_MAX6900 config RTC_DRV_MAX8907 tristate "Maxim MAX8907" depends on MFD_MAX8907 || COMPILE_TEST + select REGMAP_IRQ help If you say yes here you will get support for the RTC of Maxim MAX8907 PMIC. From 6e7af45102994dca6941720c2207f081f8f26adc Mon Sep 17 00:00:00 2001 From: Keyur Patel Date: Sat, 21 Mar 2020 14:08:37 -0400 Subject: [PATCH 446/809] rtc: bd70528: Avoid double error messaging when IRQ absent Since the commit 7723f4c ("driver core: platform: Add an error message to platform_get_irq*()") platform_get_irq() started issuing an error message. Thus, there is no need to have the same in the driver. Signed-off-by: Keyur Patel Link: https://lore.kernel.org/r/20200321180838.12729-1-iamkeyur96@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bd70528.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index bbbb1f07c91f..4492b770422c 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -542,10 +542,8 @@ static int bd70528_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, irq_name); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get irq\n"); + if (irq < 0) return irq; - } platform_set_drvdata(pdev, bd_rtc); From 4828a82e29eb77628526fd6b92d528c2f724cb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 21 Mar 2020 21:37:37 +0100 Subject: [PATCH 447/809] rtc: omap: drop unused dt-bindings header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitons in the dt-binding's gpio header only contains some constants to be used in device trees. It is not relevant for rtc-omap (as the gpio API hides the details) and in fact unused so it can just be dropped. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20200321203737.29850-1-uwe@kleine-koenig.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index d4ed20fb3194..c20fc7937dfa 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -9,7 +9,6 @@ * Copyright (C) 2014 Johan Hovold */ -#include #include #include #include From 34ce29774dadc24ac1a529c562c325db2b77c7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9F=A9=E7=A7=91=E6=89=8D?= Date: Sat, 21 Mar 2020 19:50:17 +0800 Subject: [PATCH 448/809] rtc: pm8xxx: clear alarm register when alarm is not enabled Clear alarm register when alarm is not enabled otherwise the consumer may still start alarm timer if it find the alarm register is not zero. Signed-off-by: hankecai Link: https://lore.kernel.org/r/APoAZgAaCEiRpKG6PlzreaqE.1.1584791417367.Hmail.hankecai@vivo.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index e3d9abb2134e..b45ee2cb2c04 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -295,6 +295,7 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; unsigned int ctrl_reg; + u8 value[NUM_8_BIT_RTC_REGS] = {0}; spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); @@ -313,6 +314,16 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) goto rtc_rw_fail; } + /* Clear Alarm register */ + if (!enable) { + rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, + sizeof(value)); + if (rc) { + dev_err(dev, "Clear RTC ALARM register failed\n"); + goto rtc_rw_fail; + } + } + rtc_rw_fail: spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); return rc; From 44a52022e7f15cbaab957df1c14f7a4f527ef7cf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 22 Mar 2020 19:45:41 -0700 Subject: [PATCH 449/809] ext2: fix empty body warnings when -Wextra is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When EXT2_ATTR_DEBUG is not defined, modify the 2 debug macros to use the no_printk() macro instead of . This fixes gcc warnings when -Wextra is used: ../fs/ext2/xattr.c:252:42: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] ../fs/ext2/xattr.c:258:42: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] ../fs/ext2/xattr.c:330:42: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] ../fs/ext2/xattr.c:872:45: warning: suggest braces around empty body in an ‘else’ statement [-Wempty-body] I have verified that the only object code change (with gcc 7.5.0) is the reversal of some instructions from 'cmp a,b' to 'cmp b,a'. Link: https://lore.kernel.org/r/e18a7395-61fb-2093-18e8-ed4f8cf56248@infradead.org Signed-off-by: Randy Dunlap Cc: Jan Kara Cc: linux-ext4@vger.kernel.org Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 6d9731b03715..943cc469f42f 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -84,8 +85,8 @@ printk("\n"); \ } while (0) #else -# define ea_idebug(f...) -# define ea_bdebug(f...) +# define ea_idebug(inode, f...) no_printk(f) +# define ea_bdebug(bh, f...) no_printk(f) #endif static int ext2_xattr_set2(struct inode *, struct buffer_head *, From 31932757c6121b394cd4f158b6b8f1cca8ffe871 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 8 Mar 2020 21:34:49 +0100 Subject: [PATCH 450/809] s390/mm: optimize page table upgrade routine There is a maximum of two new tables allocated on page table upgrade. Because we know that a loop the current implementation is based on could be unrolled with some improvements: * upgrade from 3 to 5 levels happens in one go - without an unnecessary re-take of page_table_lock in-between; * page tables initialization moved out of the atomic code; Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/mm/pgalloc.c | 90 ++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index 3dd253f81a77..d3be3fe2c55d 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -77,43 +77,65 @@ static void __crst_table_upgrade(void *arg) int crst_table_upgrade(struct mm_struct *mm, unsigned long end) { - unsigned long *table, *pgd; - int rc, notify; + unsigned long *pgd = NULL, *p4d = NULL, *__pgd; + unsigned long asce_limit = mm->context.asce_limit; /* upgrade should only happen from 3 to 4, 3 to 5, or 4 to 5 levels */ - VM_BUG_ON(mm->context.asce_limit < _REGION2_SIZE); - rc = 0; - notify = 0; - while (mm->context.asce_limit < end) { - table = crst_table_alloc(mm); - if (!table) { - rc = -ENOMEM; - break; - } - spin_lock_bh(&mm->page_table_lock); - pgd = (unsigned long *) mm->pgd; - if (mm->context.asce_limit == _REGION2_SIZE) { - crst_table_init(table, _REGION2_ENTRY_EMPTY); - p4d_populate(mm, (p4d_t *) table, (pud_t *) pgd); - mm->pgd = (pgd_t *) table; - mm->context.asce_limit = _REGION1_SIZE; - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_REGION2; - mm_inc_nr_puds(mm); - } else { - crst_table_init(table, _REGION1_ENTRY_EMPTY); - pgd_populate(mm, (pgd_t *) table, (p4d_t *) pgd); - mm->pgd = (pgd_t *) table; - mm->context.asce_limit = -PAGE_SIZE; - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_REGION1; - } - notify = 1; - spin_unlock_bh(&mm->page_table_lock); + VM_BUG_ON(asce_limit < _REGION2_SIZE); + + if (end <= asce_limit) + return 0; + + if (asce_limit == _REGION2_SIZE) { + p4d = crst_table_alloc(mm); + if (unlikely(!p4d)) + goto err_p4d; + crst_table_init(p4d, _REGION2_ENTRY_EMPTY); } - if (notify) - on_each_cpu(__crst_table_upgrade, mm, 0); - return rc; + if (end > _REGION1_SIZE) { + pgd = crst_table_alloc(mm); + if (unlikely(!pgd)) + goto err_pgd; + crst_table_init(pgd, _REGION1_ENTRY_EMPTY); + } + + spin_lock_bh(&mm->page_table_lock); + + /* + * This routine gets called with mmap_sem lock held and there is + * no reason to optimize for the case of otherwise. However, if + * that would ever change, the below check will let us know. + */ + VM_BUG_ON(asce_limit != mm->context.asce_limit); + + if (p4d) { + __pgd = (unsigned long *) mm->pgd; + p4d_populate(mm, (p4d_t *) p4d, (pud_t *) __pgd); + mm->pgd = (pgd_t *) p4d; + mm->context.asce_limit = _REGION1_SIZE; + mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | _ASCE_TYPE_REGION2; + mm_inc_nr_puds(mm); + } + if (pgd) { + __pgd = (unsigned long *) mm->pgd; + pgd_populate(mm, (pgd_t *) pgd, (p4d_t *) __pgd); + mm->pgd = (pgd_t *) pgd; + mm->context.asce_limit = -PAGE_SIZE; + mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | _ASCE_TYPE_REGION1; + } + + spin_unlock_bh(&mm->page_table_lock); + + on_each_cpu(__crst_table_upgrade, mm, 0); + + return 0; + +err_pgd: + crst_table_free(mm, p4d); +err_p4d: + return -ENOMEM; } void crst_table_downgrade(struct mm_struct *mm) From 42d211a1ae3b77008d4190b7dc79ad29b48bbcd2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 11 Mar 2020 14:18:05 +0100 Subject: [PATCH 451/809] s390/cpuinfo: show processor physical address Show CPU physical address as reported by STAP instruction Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/smp.h | 1 + arch/s390/kernel/processor.c | 1 + arch/s390/kernel/smp.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index b157a81fb977..231a51e870fe 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -34,6 +34,7 @@ extern int smp_vcpu_scheduled(int cpu); extern void smp_yield_cpu(int cpu); extern void smp_cpu_set_polarization(int cpu, int val); extern int smp_cpu_get_polarization(int cpu); +extern int smp_cpu_get_cpu_address(int cpu); extern void smp_fill_possible_mask(void); extern void smp_detect_cpus(void); diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 2c13ca562b48..b98654d0ce41 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -159,6 +159,7 @@ static void show_cpu_topology(struct seq_file *m, unsigned long n) seq_printf(m, "book id : %d\n", topology_book_id(n)); seq_printf(m, "drawer id : %d\n", topology_drawer_id(n)); seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n)); + seq_printf(m, "address : %d\n", smp_cpu_get_cpu_address(n)); #endif /* CONFIG_SCHED_TOPOLOGY */ } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index f87d4e14269c..edc1bf39c542 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -703,6 +703,11 @@ int smp_cpu_get_polarization(int cpu) return pcpu_devices[cpu].polarization; } +int smp_cpu_get_cpu_address(int cpu) +{ + return pcpu_devices[cpu].address; +} + static void __ref smp_get_core_info(struct sclp_core_info *info, int early) { static int use_sigp_detection; From cd8e702f0db75f28d0fbdc574a8fcda4aca0b09b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 12 Mar 2020 11:35:05 +0100 Subject: [PATCH 452/809] s390/numa: remove redundant cpus_with_topology variable Variable cpus_with_topology is a leftover that became unneeded once the fake NUMA support has been removed. Signed-off-by: Alexander Gordeev Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/topology.h | 1 - arch/s390/kernel/topology.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index bd3417185e30..4648303e6958 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -24,7 +24,6 @@ struct cpu_topology_s390 { }; extern struct cpu_topology_s390 cpu_topology[NR_CPUS]; -extern cpumask_t cpus_with_topology; #define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) #define topology_thread_id(cpu) (cpu_topology[cpu].thread_id) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index c189f5d996ff..ec1bffe6ce75 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -62,8 +62,6 @@ static struct mask_info drawer_info; struct cpu_topology_s390 cpu_topology[NR_CPUS]; EXPORT_SYMBOL_GPL(cpu_topology); -cpumask_t cpus_with_topology; - static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) { cpumask_t mask; @@ -137,7 +135,6 @@ static void add_cpus_to_mask(struct topology_core *tl_core, cpumask_set_cpu(lcpu + i, &drawer->mask); cpumask_set_cpu(lcpu + i, &book->mask); cpumask_set_cpu(lcpu + i, &socket->mask); - cpumask_set_cpu(lcpu + i, &cpus_with_topology); smp_cpu_set_polarization(lcpu + i, tl_core->pp); } } @@ -262,8 +259,6 @@ static void update_cpu_masks(void) topo->socket_id = id; topo->book_id = id; topo->drawer_id = id; - if (cpu_present(cpu)) - cpumask_set_cpu(cpu, &cpus_with_topology); } } } @@ -287,7 +282,6 @@ static int __arch_update_cpu_topology(void) int rc = 0; mutex_lock(&smp_cpu_state_mutex); - cpumask_clear(&cpus_with_topology); if (MACHINE_HAS_TOPOLOGY) { rc = 1; store_topology(info); From 52aeda7accb6d2e511a1b89142cbbf6fd2c12565 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 12 Mar 2020 11:32:23 +0100 Subject: [PATCH 453/809] s390/topology: remove offline CPUs from CPU topology masks The CPU topology masks on s390 contain also bits of CPUs which are offline. Currently this is already a problem, since common code scheduler expects e.g. cpu_smt_mask() to reflect reality. This update changes the described behaviour and s390 starts to behave like all other architectures. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/topology.h | 2 ++ arch/s390/kernel/smp.c | 6 ++++-- arch/s390/kernel/topology.c | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 4648303e6958..56b14616fb6b 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -43,6 +43,7 @@ int topology_cpu_init(struct cpu *); int topology_set_cpu_management(int fc); void topology_schedule_update(void); void store_topology(struct sysinfo_15_1_x *info); +void update_cpu_masks(void); void topology_expect_change(void); const struct cpumask *cpu_coregroup_mask(int cpu); @@ -52,6 +53,7 @@ static inline void topology_init_early(void) { } static inline void topology_schedule_update(void) { } static inline int topology_cpu_init(struct cpu *cpu) { return 0; } static inline int topology_cpu_dedicated(int cpu_nr) { return 0; } +static inline void update_cpu_masks(void) { } static inline void topology_expect_change(void) { } #endif /* CONFIG_SCHED_TOPOLOGY */ diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index edc1bf39c542..7eaabbab2213 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -858,12 +858,13 @@ static void smp_init_secondary(void) init_cpu_timer(); vtime_init(); pfault_init(); - notify_cpu_starting(smp_processor_id()); + notify_cpu_starting(cpu); if (topology_cpu_dedicated(cpu)) set_cpu_flag(CIF_DEDICATED_CPU); else clear_cpu_flag(CIF_DEDICATED_CPU); - set_cpu_online(smp_processor_id(), true); + set_cpu_online(cpu, true); + update_cpu_masks(); inc_irq_stat(CPU_RST); local_irq_enable(); cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); @@ -935,6 +936,7 @@ int __cpu_disable(void) /* Handle possible pending IPIs */ smp_handle_ext_call(); set_cpu_online(smp_processor_id(), false); + update_cpu_masks(); /* Disable pseudo page faults on this cpu. */ pfault_fini(); /* Disable interrupt sources via control register. */ diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index ec1bffe6ce75..09711d55f123 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -88,6 +88,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_copy(&mask, cpumask_of(cpu)); break; } + cpumask_and(&mask, &mask, cpu_online_mask); return mask; } @@ -103,6 +104,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) for (i = 0; i <= smp_cpu_mtid; i++) if (cpu_present(cpu + i)) cpumask_set_cpu(cpu + i, &mask); + cpumask_and(&mask, &mask, cpu_online_mask); return mask; } @@ -241,7 +243,7 @@ int topology_set_cpu_management(int fc) return rc; } -static void update_cpu_masks(void) +void update_cpu_masks(void) { struct cpu_topology_s390 *topo; int cpu, id; From eb3e064b8dd12d0bc907dbbfc227bca9da252e6f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2020 10:09:15 +0100 Subject: [PATCH 454/809] s390/zcrypt: Use scnprintf() for avoiding potential buffer overflow Since snprintf() returns the would-be-output size instead of the actual output size, the succeeding calls may go beyond the given buffer limit. Fix it by replacing with scnprintf(). Message-Id: <20200311090915.21059-1-tiwai@suse.de> Signed-off-by: Takashi Iwai Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_cex4.c | 40 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 9a9d02e19774..6fc1ea77fbe9 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -128,16 +128,18 @@ static ssize_t cca_mkvps_show(struct device *dev, n = snprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2') - n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: %s 0x%016llx\n", - cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp); + n += scnprintf(buf + n, PAGE_SIZE - n, + "AES CUR: %s 0x%016llx\n", + cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp); else - n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2') - n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: %s 0x%016llx\n", - cao_state[ci.old_mk_state - '1'], ci.old_mkvp); + n += scnprintf(buf + n, PAGE_SIZE - n, + "AES OLD: %s 0x%016llx\n", + cao_state[ci.old_mk_state - '1'], ci.old_mkvp); else - n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); return n; } @@ -251,11 +253,11 @@ static ssize_t ep11_card_op_modes_show(struct device *dev, if (ci.op_mode & (1 << ep11_op_modes[i].mode_bit)) { if (n > 0) buf[n++] = ' '; - n += snprintf(buf + n, PAGE_SIZE - n, - "%s", ep11_op_modes[i].mode_txt); + n += scnprintf(buf + n, PAGE_SIZE - n, + "%s", ep11_op_modes[i].mode_txt); } } - n += snprintf(buf + n, PAGE_SIZE - n, "\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); return n; } @@ -305,21 +307,21 @@ static ssize_t ep11_mkvps_show(struct device *dev, cwk_state[di.cur_wk_state - '0']); bin2hex(buf + n, di.cur_wkvp, sizeof(di.cur_wkvp)); n += 2 * sizeof(di.cur_wkvp); - n += snprintf(buf + n, PAGE_SIZE - n, "\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); } else n = snprintf(buf, PAGE_SIZE, "WK CUR: - -\n"); if (di.new_wk_state == '0') { - n += snprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s -\n", - nwk_state[di.new_wk_state - '0']); + n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s -\n", + nwk_state[di.new_wk_state - '0']); } else if (di.new_wk_state >= '1' && di.new_wk_state <= '2') { - n += snprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s 0x", - nwk_state[di.new_wk_state - '0']); + n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s 0x", + nwk_state[di.new_wk_state - '0']); bin2hex(buf + n, di.new_wkvp, sizeof(di.new_wkvp)); n += 2 * sizeof(di.new_wkvp); - n += snprintf(buf + n, PAGE_SIZE - n, "\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); } else - n += snprintf(buf + n, PAGE_SIZE - n, "WK NEW: - -\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: - -\n"); return n; } @@ -346,11 +348,11 @@ static ssize_t ep11_queue_op_modes_show(struct device *dev, if (di.op_mode & (1 << ep11_op_modes[i].mode_bit)) { if (n > 0) buf[n++] = ' '; - n += snprintf(buf + n, PAGE_SIZE - n, - "%s", ep11_op_modes[i].mode_txt); + n += scnprintf(buf + n, PAGE_SIZE - n, + "%s", ep11_op_modes[i].mode_txt); } } - n += snprintf(buf + n, PAGE_SIZE - n, "\n"); + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); return n; } From 40501c70e3f09e8018bf08457502a3a7b2d5a406 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 12 Mar 2020 11:19:55 +0100 Subject: [PATCH 455/809] s390/zcrypt: replace snprintf/sprintf with scnprintf snprintf() may not always return the correct size of used bytes but instead the length the resulting string would be if it would fit into the buffer. So scnprintf() is the function to use when the real length of the resulting string is needed. Replace all occurrences of snprintf() with scnprintf() where the return code is further processed. Also find and fix some occurrences where sprintf() was used. Suggested-by: Takashi Iwai Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.c | 72 +++++++++++++++--------------- drivers/s390/crypto/ap_card.c | 17 +++---- drivers/s390/crypto/ap_queue.c | 18 ++++---- drivers/s390/crypto/zcrypt_card.c | 6 +-- drivers/s390/crypto/zcrypt_cex4.c | 34 +++++++------- drivers/s390/crypto/zcrypt_queue.c | 4 +- 6 files changed, 76 insertions(+), 75 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5256e3ce84e5..171b0a08e0f9 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1021,7 +1021,7 @@ EXPORT_SYMBOL(ap_parse_mask_str); static ssize_t ap_domain_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); + return scnprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); } static ssize_t ap_domain_store(struct bus_type *bus, @@ -1047,14 +1047,14 @@ static BUS_ATTR_RW(ap_domain); static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { if (!ap_configuration) /* QCI not supported */ - return snprintf(buf, PAGE_SIZE, "not supported\n"); + return scnprintf(buf, PAGE_SIZE, "not supported\n"); - return snprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_configuration->adm[0], ap_configuration->adm[1], - ap_configuration->adm[2], ap_configuration->adm[3], - ap_configuration->adm[4], ap_configuration->adm[5], - ap_configuration->adm[6], ap_configuration->adm[7]); + return scnprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->adm[0], ap_configuration->adm[1], + ap_configuration->adm[2], ap_configuration->adm[3], + ap_configuration->adm[4], ap_configuration->adm[5], + ap_configuration->adm[6], ap_configuration->adm[7]); } static BUS_ATTR_RO(ap_control_domain_mask); @@ -1062,14 +1062,14 @@ static BUS_ATTR_RO(ap_control_domain_mask); static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) { if (!ap_configuration) /* QCI not supported */ - return snprintf(buf, PAGE_SIZE, "not supported\n"); + return scnprintf(buf, PAGE_SIZE, "not supported\n"); - return snprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_configuration->aqm[0], ap_configuration->aqm[1], - ap_configuration->aqm[2], ap_configuration->aqm[3], - ap_configuration->aqm[4], ap_configuration->aqm[5], - ap_configuration->aqm[6], ap_configuration->aqm[7]); + return scnprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->aqm[0], ap_configuration->aqm[1], + ap_configuration->aqm[2], ap_configuration->aqm[3], + ap_configuration->aqm[4], ap_configuration->aqm[5], + ap_configuration->aqm[6], ap_configuration->aqm[7]); } static BUS_ATTR_RO(ap_usage_domain_mask); @@ -1077,29 +1077,29 @@ static BUS_ATTR_RO(ap_usage_domain_mask); static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf) { if (!ap_configuration) /* QCI not supported */ - return snprintf(buf, PAGE_SIZE, "not supported\n"); + return scnprintf(buf, PAGE_SIZE, "not supported\n"); - return snprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_configuration->apm[0], ap_configuration->apm[1], - ap_configuration->apm[2], ap_configuration->apm[3], - ap_configuration->apm[4], ap_configuration->apm[5], - ap_configuration->apm[6], ap_configuration->apm[7]); + return scnprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->apm[0], ap_configuration->apm[1], + ap_configuration->apm[2], ap_configuration->apm[3], + ap_configuration->apm[4], ap_configuration->apm[5], + ap_configuration->apm[6], ap_configuration->apm[7]); } static BUS_ATTR_RO(ap_adapter_mask); static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", - ap_using_interrupts() ? 1 : 0); + return scnprintf(buf, PAGE_SIZE, "%d\n", + ap_using_interrupts() ? 1 : 0); } static BUS_ATTR_RO(ap_interrupts); static ssize_t config_time_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); + return scnprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); } static ssize_t config_time_store(struct bus_type *bus, @@ -1118,7 +1118,7 @@ static BUS_ATTR_RW(config_time); static ssize_t poll_thread_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); + return scnprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); } static ssize_t poll_thread_store(struct bus_type *bus, @@ -1141,7 +1141,7 @@ static BUS_ATTR_RW(poll_thread); static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); + return scnprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); } static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, @@ -1176,7 +1176,7 @@ static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) max_domain_id = ap_max_domain_id ? : -1; else max_domain_id = 15; - return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); + return scnprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); } static BUS_ATTR_RO(ap_max_domain_id); @@ -1187,10 +1187,10 @@ static ssize_t apmask_show(struct bus_type *bus, char *buf) if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - rc = snprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_perms.apm[0], ap_perms.apm[1], - ap_perms.apm[2], ap_perms.apm[3]); + rc = scnprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.apm[0], ap_perms.apm[1], + ap_perms.apm[2], ap_perms.apm[3]); mutex_unlock(&ap_perms_mutex); return rc; @@ -1218,10 +1218,10 @@ static ssize_t aqmask_show(struct bus_type *bus, char *buf) if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - rc = snprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_perms.aqm[0], ap_perms.aqm[1], - ap_perms.aqm[2], ap_perms.aqm[3]); + rc = scnprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.aqm[0], ap_perms.aqm[1], + ap_perms.aqm[2], ap_perms.aqm[3]); mutex_unlock(&ap_perms_mutex); return rc; diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index e85bfca1ed16..0a39dfdb6a1d 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -23,7 +23,7 @@ static ssize_t hwtype_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); + return scnprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); } static DEVICE_ATTR_RO(hwtype); @@ -33,7 +33,7 @@ static ssize_t raw_hwtype_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); + return scnprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); } static DEVICE_ATTR_RO(raw_hwtype); @@ -43,7 +43,7 @@ static ssize_t depth_show(struct device *dev, struct device_attribute *attr, { struct ap_card *ac = to_ap_card(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); + return scnprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); } static DEVICE_ATTR_RO(depth); @@ -53,7 +53,7 @@ static ssize_t ap_functions_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); + return scnprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); } static DEVICE_ATTR_RO(ap_functions); @@ -69,7 +69,7 @@ static ssize_t request_count_show(struct device *dev, spin_lock_bh(&ap_list_lock); req_cnt = atomic64_read(&ac->total_request_count); spin_unlock_bh(&ap_list_lock); - return snprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); + return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); } static ssize_t request_count_store(struct device *dev, @@ -102,7 +102,7 @@ static ssize_t requestq_count_show(struct device *dev, for_each_ap_queue(aq, ac) reqq_cnt += aq->requestq_count; spin_unlock_bh(&ap_list_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); + return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } static DEVICE_ATTR_RO(requestq_count); @@ -119,7 +119,7 @@ static ssize_t pendingq_count_show(struct device *dev, for_each_ap_queue(aq, ac) penq_cnt += aq->pendingq_count; spin_unlock_bh(&ap_list_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); + return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } static DEVICE_ATTR_RO(pendingq_count); @@ -127,7 +127,8 @@ static DEVICE_ATTR_RO(pendingq_count); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); + return scnprintf(buf, PAGE_SIZE, "ap:t%02X\n", + to_ap_dev(dev)->device_type); } static DEVICE_ATTR_RO(modalias); diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index a317ab484932..39c0b246c69a 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -484,7 +484,7 @@ static ssize_t request_count_show(struct device *dev, spin_lock_bh(&aq->lock); req_cnt = aq->total_request_count; spin_unlock_bh(&aq->lock); - return snprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); + return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); } static ssize_t request_count_store(struct device *dev, @@ -511,7 +511,7 @@ static ssize_t requestq_count_show(struct device *dev, spin_lock_bh(&aq->lock); reqq_cnt = aq->requestq_count; spin_unlock_bh(&aq->lock); - return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); + return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } static DEVICE_ATTR_RO(requestq_count); @@ -525,7 +525,7 @@ static ssize_t pendingq_count_show(struct device *dev, spin_lock_bh(&aq->lock); penq_cnt = aq->pendingq_count; spin_unlock_bh(&aq->lock); - return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); + return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } static DEVICE_ATTR_RO(pendingq_count); @@ -540,14 +540,14 @@ static ssize_t reset_show(struct device *dev, switch (aq->state) { case AP_STATE_RESET_START: case AP_STATE_RESET_WAIT: - rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); + rc = scnprintf(buf, PAGE_SIZE, "Reset in progress.\n"); break; case AP_STATE_WORKING: case AP_STATE_QUEUE_FULL: - rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); + rc = scnprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); break; default: - rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); + rc = scnprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); } spin_unlock_bh(&aq->lock); return rc; @@ -581,11 +581,11 @@ static ssize_t interrupt_show(struct device *dev, spin_lock_bh(&aq->lock); if (aq->state == AP_STATE_SETIRQ_WAIT) - rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); + rc = scnprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); else if (aq->interrupt == AP_INTR_ENABLED) - rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); + rc = scnprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); else - rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); + rc = scnprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); spin_unlock_bh(&aq->lock); return rc; } diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index d4f35a183c15..c53cab4b0c9e 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -41,7 +41,7 @@ static ssize_t type_show(struct device *dev, { struct zcrypt_card *zc = to_ap_card(dev)->private; - return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); + return scnprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); } static DEVICE_ATTR_RO(type); @@ -52,7 +52,7 @@ static ssize_t online_show(struct device *dev, { struct zcrypt_card *zc = to_ap_card(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", zc->online); + return scnprintf(buf, PAGE_SIZE, "%d\n", zc->online); } static ssize_t online_store(struct device *dev, @@ -86,7 +86,7 @@ static ssize_t load_show(struct device *dev, { struct zcrypt_card *zc = to_ap_card(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); + return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); } static DEVICE_ATTR_RO(load); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 6fc1ea77fbe9..8cfb1e2e9e1b 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -87,7 +87,7 @@ static ssize_t cca_serialnr_show(struct device *dev, if (ap_domain_index >= 0) cca_get_info(ac->id, ap_domain_index, &ci, zc->online); - return snprintf(buf, PAGE_SIZE, "%s\n", ci.serial); + return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial); } static struct device_attribute dev_attr_cca_serialnr = @@ -122,10 +122,10 @@ static ssize_t cca_mkvps_show(struct device *dev, &ci, zq->online); if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3') - n = snprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", - new_state[ci.new_mk_state - '1'], ci.new_mkvp); + n = scnprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", + new_state[ci.new_mk_state - '1'], ci.new_mkvp); else - n = snprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); + n = scnprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2') n += scnprintf(buf + n, PAGE_SIZE - n, @@ -172,9 +172,9 @@ static ssize_t ep11_api_ordinalnr_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.API_ord_nr > 0) - return snprintf(buf, PAGE_SIZE, "%u\n", ci.API_ord_nr); + return scnprintf(buf, PAGE_SIZE, "%u\n", ci.API_ord_nr); else - return snprintf(buf, PAGE_SIZE, "\n"); + return scnprintf(buf, PAGE_SIZE, "\n"); } static struct device_attribute dev_attr_ep11_api_ordinalnr = @@ -193,11 +193,11 @@ static ssize_t ep11_fw_version_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.FW_version > 0) - return snprintf(buf, PAGE_SIZE, "%d.%d\n", - (int)(ci.FW_version >> 8), - (int)(ci.FW_version & 0xFF)); + return scnprintf(buf, PAGE_SIZE, "%d.%d\n", + (int)(ci.FW_version >> 8), + (int)(ci.FW_version & 0xFF)); else - return snprintf(buf, PAGE_SIZE, "\n"); + return scnprintf(buf, PAGE_SIZE, "\n"); } static struct device_attribute dev_attr_ep11_fw_version = @@ -216,9 +216,9 @@ static ssize_t ep11_serialnr_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.serial[0]) - return snprintf(buf, PAGE_SIZE, "%16.16s\n", ci.serial); + return scnprintf(buf, PAGE_SIZE, "%16.16s\n", ci.serial); else - return snprintf(buf, PAGE_SIZE, "\n"); + return scnprintf(buf, PAGE_SIZE, "\n"); } static struct device_attribute dev_attr_ep11_serialnr = @@ -300,16 +300,16 @@ static ssize_t ep11_mkvps_show(struct device *dev, &di); if (di.cur_wk_state == '0') { - n = snprintf(buf, PAGE_SIZE, "WK CUR: %s -\n", - cwk_state[di.cur_wk_state - '0']); + n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s -\n", + cwk_state[di.cur_wk_state - '0']); } else if (di.cur_wk_state == '1') { - n = snprintf(buf, PAGE_SIZE, "WK CUR: %s 0x", - cwk_state[di.cur_wk_state - '0']); + n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s 0x", + cwk_state[di.cur_wk_state - '0']); bin2hex(buf + n, di.cur_wkvp, sizeof(di.cur_wkvp)); n += 2 * sizeof(di.cur_wkvp); n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); } else - n = snprintf(buf, PAGE_SIZE, "WK CUR: - -\n"); + n = scnprintf(buf, PAGE_SIZE, "WK CUR: - -\n"); if (di.new_wk_state == '0') { n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s -\n", diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 522c4bc69a08..b7d9fa567880 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -42,7 +42,7 @@ static ssize_t online_show(struct device *dev, { struct zcrypt_queue *zq = to_ap_queue(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); + return scnprintf(buf, PAGE_SIZE, "%d\n", zq->online); } static ssize_t online_store(struct device *dev, @@ -78,7 +78,7 @@ static ssize_t load_show(struct device *dev, { struct zcrypt_queue *zq = to_ap_queue(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); + return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); } static DEVICE_ATTR_RO(load); From 1a2ae03b1938b050c3bbd79e79d5075e0307fe20 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Thu, 20 Feb 2020 16:22:30 +0100 Subject: [PATCH 456/809] s390/ipl: add support to control memory clearing for FCP and CCW re-IPL Re-IPL for both CCW and FCP is currently done by using diag 308 with the "Load Clear" subcode, which means that all memory will be cleared. This can increase re-IPL duration considerably on very large machines. For CCW devices, there is also a "Load Normal" subcode that was only used for dump kernels so far. For FCP devices, a similar "Load Normal" subcode was introduced with z14. The "Load Normal" diag 308 subcode allows to re-IPL without clearing memory. This patch adds a new "clear" sysfs attribute to /sys/firmware/reipl for both the ccw and fcp subdirectories, which can be set to either "0" or "1" to disable or enable re-IPL with memory clearing. The default value is "0", which disables memory clearing. Signed-off-by: Gerald Schaefer Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/ipl.h | 1 + arch/s390/kernel/ipl.c | 73 +++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 084e71b7272a..b63bd66404b8 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h @@ -119,6 +119,7 @@ enum diag308_subcode { DIAG308_LOAD_NORMAL_DUMP = 4, DIAG308_SET = 5, DIAG308_STORE = 6, + DIAG308_LOAD_NORMAL = 7, }; enum diag308_rc { diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 6837affc19e8..4a71061974fd 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -144,6 +144,9 @@ static struct ipl_parameter_block *dump_block_ccw; static struct sclp_ipl_info sclp_ipl_info; +static bool reipl_fcp_clear; +static bool reipl_ccw_clear; + static inline int __diag308(unsigned long subcode, void *addr) { register unsigned long _addr asm("0") = (unsigned long) addr; @@ -691,6 +694,21 @@ static struct kobj_attribute sys_reipl_fcp_loadparm_attr = __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show, reipl_fcp_loadparm_store); +static ssize_t reipl_fcp_clear_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return sprintf(page, "%u\n", reipl_fcp_clear); +} + +static ssize_t reipl_fcp_clear_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + if (strtobool(buf, &reipl_fcp_clear) < 0) + return -EINVAL; + return len; +} + static struct attribute *reipl_fcp_attrs[] = { &sys_reipl_fcp_device_attr.attr, &sys_reipl_fcp_wwpn_attr.attr, @@ -706,6 +724,9 @@ static struct attribute_group reipl_fcp_attr_group = { .bin_attrs = reipl_fcp_bin_attrs, }; +static struct kobj_attribute sys_reipl_fcp_clear_attr = + __ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store); + /* CCW reipl device attributes */ DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw); @@ -741,16 +762,36 @@ static struct kobj_attribute sys_reipl_ccw_loadparm_attr = __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show, reipl_ccw_loadparm_store); +static ssize_t reipl_ccw_clear_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return sprintf(page, "%u\n", reipl_ccw_clear); +} + +static ssize_t reipl_ccw_clear_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + if (strtobool(buf, &reipl_ccw_clear) < 0) + return -EINVAL; + return len; +} + +static struct kobj_attribute sys_reipl_ccw_clear_attr = + __ATTR(clear, 0644, reipl_ccw_clear_show, reipl_ccw_clear_store); + static struct attribute *reipl_ccw_attrs_vm[] = { &sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_loadparm_attr.attr, &sys_reipl_ccw_vmparm_attr.attr, + &sys_reipl_ccw_clear_attr.attr, NULL, }; static struct attribute *reipl_ccw_attrs_lpar[] = { &sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_loadparm_attr.attr, + &sys_reipl_ccw_clear_attr.attr, NULL, }; @@ -892,11 +933,17 @@ static void __reipl_run(void *unused) switch (reipl_type) { case IPL_TYPE_CCW: diag308(DIAG308_SET, reipl_block_ccw); - diag308(DIAG308_LOAD_CLEAR, NULL); + if (reipl_ccw_clear) + diag308(DIAG308_LOAD_CLEAR, NULL); + else + diag308(DIAG308_LOAD_NORMAL_DUMP, NULL); break; case IPL_TYPE_FCP: diag308(DIAG308_SET, reipl_block_fcp); - diag308(DIAG308_LOAD_CLEAR, NULL); + if (reipl_fcp_clear) + diag308(DIAG308_LOAD_CLEAR, NULL); + else + diag308(DIAG308_LOAD_NORMAL, NULL); break; case IPL_TYPE_NSS: diag308(DIAG308_SET, reipl_block_nss); @@ -1008,11 +1055,16 @@ static int __init reipl_fcp_init(void) } rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); - if (rc) { - kset_unregister(reipl_fcp_kset); - free_page((unsigned long) reipl_block_fcp); - return rc; - } + if (rc) + goto out1; + + if (test_facility(141)) { + rc = sysfs_create_file(&reipl_fcp_kset->kobj, + &sys_reipl_fcp_clear_attr.attr); + if (rc) + goto out2; + } else + reipl_fcp_clear = true; if (ipl_info.type == IPL_TYPE_FCP) { memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block)); @@ -1032,6 +1084,13 @@ static int __init reipl_fcp_init(void) } reipl_capabilities |= IPL_TYPE_FCP; return 0; + +out2: + sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); +out1: + kset_unregister(reipl_fcp_kset); + free_page((unsigned long) reipl_block_fcp); + return rc; } static int __init reipl_type_init(void) From 959684978d5a8443cfb0ed59a9d1fc59d2a80d09 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 13 Mar 2020 16:52:44 +0100 Subject: [PATCH 457/809] s390/cpuinfo: show number of online cores Show number of cores that run at least one SMT thread Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/topology.h | 3 +++ arch/s390/kernel/processor.c | 1 + arch/s390/kernel/topology.c | 20 ++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 56b14616fb6b..fbb507504a3b 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -17,6 +17,7 @@ struct cpu_topology_s390 { unsigned short book_id; unsigned short drawer_id; unsigned short dedicated : 1; + int booted_cores; cpumask_t thread_mask; cpumask_t core_mask; cpumask_t book_mask; @@ -35,6 +36,7 @@ extern struct cpu_topology_s390 cpu_topology[NR_CPUS]; #define topology_drawer_id(cpu) (cpu_topology[cpu].drawer_id) #define topology_drawer_cpumask(cpu) (&cpu_topology[cpu].drawer_mask) #define topology_cpu_dedicated(cpu) (cpu_topology[cpu].dedicated) +#define topology_booted_cores(cpu) (cpu_topology[cpu].booted_cores) #define mc_capable() 1 @@ -53,6 +55,7 @@ static inline void topology_init_early(void) { } static inline void topology_schedule_update(void) { } static inline int topology_cpu_init(struct cpu *cpu) { return 0; } static inline int topology_cpu_dedicated(int cpu_nr) { return 0; } +static inline int topology_booted_cores(int cpu_nr) { return 1; } static inline void update_cpu_masks(void) { } static inline void topology_expect_change(void) { } diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index b98654d0ce41..41172093160e 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -160,6 +160,7 @@ static void show_cpu_topology(struct seq_file *m, unsigned long n) seq_printf(m, "drawer id : %d\n", topology_drawer_id(n)); seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n)); seq_printf(m, "address : %d\n", smp_cpu_get_cpu_address(n)); + seq_printf(m, "cpu cores : %d\n", topology_booted_cores(n)); #endif /* CONFIG_SCHED_TOPOLOGY */ } diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 09711d55f123..d03edebce754 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -245,8 +245,8 @@ int topology_set_cpu_management(int fc) void update_cpu_masks(void) { - struct cpu_topology_s390 *topo; - int cpu, id; + struct cpu_topology_s390 *topo, *topo_package, *topo_sibling; + int cpu, sibling, pkg_first, smt_first, id; for_each_possible_cpu(cpu) { topo = &cpu_topology[cpu]; @@ -254,6 +254,7 @@ void update_cpu_masks(void) topo->core_mask = cpu_group_map(&socket_info, cpu); topo->book_mask = cpu_group_map(&book_info, cpu); topo->drawer_mask = cpu_group_map(&drawer_info, cpu); + topo->booted_cores = 0; if (topology_mode != TOPOLOGY_MODE_HW) { id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu; topo->thread_id = cpu; @@ -263,6 +264,21 @@ void update_cpu_masks(void) topo->drawer_id = id; } } + for_each_online_cpu(cpu) { + topo = &cpu_topology[cpu]; + pkg_first = cpumask_first(&topo->core_mask); + topo_package = &cpu_topology[pkg_first]; + if (cpu == pkg_first) { + for_each_cpu(sibling, &topo->core_mask) { + topo_sibling = &cpu_topology[sibling]; + smt_first = cpumask_first(&topo_sibling->thread_mask); + if (sibling == smt_first) + topo_package->booted_cores++; + } + } else { + topo->booted_cores = topo_package->booted_cores; + } + } } void store_topology(struct sysinfo_15_1_x *info) From 2db52dc353146e684d0b3ec4060f00ebefc5c4d2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 13 Mar 2020 16:55:10 +0100 Subject: [PATCH 458/809] s390/cpuinfo: show number of online CPUs within a package Show number of online CPUs within a package (which is the socket in case of s390). For what it worth, present that value as "siblings" field - just like x86 does. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/processor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 41172093160e..39bf777e140e 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -160,6 +160,7 @@ static void show_cpu_topology(struct seq_file *m, unsigned long n) seq_printf(m, "drawer id : %d\n", topology_drawer_id(n)); seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n)); seq_printf(m, "address : %d\n", smp_cpu_get_cpu_address(n)); + seq_printf(m, "siblings : %d\n", cpumask_weight(topology_core_cpumask(n))); seq_printf(m, "cpu cores : %d\n", topology_booted_cores(n)); #endif /* CONFIG_SCHED_TOPOLOGY */ } From 872f27103874a73783aeff2aac2b41a489f67d7c Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 16 Mar 2020 12:39:55 +0100 Subject: [PATCH 459/809] s390/cpuinfo: fix wrong output when CPU0 is offline /proc/cpuinfo should not print information about CPU 0 when it is offline. Fixes: 281eaa8cb67c ("s390/cpuinfo: simplify locking and skip offline cpus early") Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens [heiko.carstens@de.ibm.com: shortened commit message] Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/processor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 39bf777e140e..f36acc8d2631 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -188,8 +188,9 @@ static void show_cpu_mhz(struct seq_file *m, unsigned long n) static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long n = (unsigned long) v - 1; + unsigned long first = cpumask_first(cpu_online_mask); - if (!n) + if (n == first) show_cpu_summary(m, v); if (!machine_has_cpu_mhz) return 0; @@ -204,6 +205,8 @@ static inline void *c_update(loff_t *pos) { if (*pos) *pos = cpumask_next(*pos - 1, cpu_online_mask); + else + *pos = cpumask_first(cpu_online_mask); return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL; } From 1b648dfd544bd9d486926e221743b9bd143d7eca Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 16 Mar 2020 10:25:44 +0100 Subject: [PATCH 460/809] s390/cpuinfo: do not skip info for CPUs without MHz feature In the past there were no per-CPU information in /proc/cpuinfo other than CPU frequency. Hence, for machines without CPU MHz feature there were nothing to show. Now CPU topology and IDs still could be shown, so do not skip this information from the output. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens [heiko.carstens@de.ibm.com: moved comparison] Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/processor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index f36acc8d2631..c92d04f876cb 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -178,6 +178,8 @@ static void show_cpu_mhz(struct seq_file *m, unsigned long n) { struct cpu_info *c = per_cpu_ptr(&cpu_info, n); + if (!machine_has_cpu_mhz) + return; seq_printf(m, "cpu MHz dynamic : %d\n", c->cpu_mhz_dynamic); seq_printf(m, "cpu MHz static : %d\n", c->cpu_mhz_static); } @@ -192,8 +194,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (n == first) show_cpu_summary(m, v); - if (!machine_has_cpu_mhz) - return 0; seq_printf(m, "\ncpu number : %ld\n", n); show_cpu_topology(m, n); show_cpu_ids(m, n); From 394216275c7d503d966317da9a01ad6626a6091d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 18 Mar 2020 20:55:24 +0100 Subject: [PATCH 461/809] s390: remove broken hibernate / power management support Hibernation is known to be broken for many years on s390. Given that there aren't any real use cases, remove the code instead of spending time to fix and maintain it. Without hibernate support it doesn't make too much sense to keep power management support; therefore remove it completely. Acked-by: Christian Borntraeger Acked-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 10 -- arch/s390/kernel/Makefile | 1 - arch/s390/kernel/machine_kexec.c | 31 ---- arch/s390/kernel/suspend.c | 240 --------------------------- arch/s390/kernel/swsusp.S | 276 ------------------------------- arch/s390/mm/cmm.c | 46 +----- arch/s390/mm/pageattr.c | 16 -- arch/s390/pci/pci.c | 43 ----- 8 files changed, 3 insertions(+), 660 deletions(-) delete mode 100644 arch/s390/kernel/suspend.c delete mode 100644 arch/s390/kernel/swsusp.S diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 334f3f2199e8..0e2ad7b2e073 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -102,7 +102,6 @@ config S390 select ARCH_INLINE_WRITE_UNLOCK_IRQ select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE select ARCH_KEEP_MEMBLOCK - select ARCH_SAVE_PAGE_KEYS if HIBERNATION select ARCH_STACKWALK select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING @@ -810,15 +809,6 @@ config SECCOMP If unsure, say Y. -menu "Power Management" - -config ARCH_HIBERNATION_POSSIBLE - def_bool y - -source "kernel/power/Kconfig" - -endmenu - config CCW def_bool y diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 2b1203cf7be6..10f80071f945 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -54,7 +54,6 @@ CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o -obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index cb8b1cc285c9..3a854cb5a4c6 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -38,36 +37,6 @@ extern const unsigned long long relocate_kernel_len; #ifdef CONFIG_CRASH_DUMP -/* - * PM notifier callback for kdump - */ -static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, - void *ptr) -{ - switch (action) { - case PM_SUSPEND_PREPARE: - case PM_HIBERNATION_PREPARE: - if (kexec_crash_image) - arch_kexec_unprotect_crashkres(); - break; - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: - if (kexec_crash_image) - arch_kexec_protect_crashkres(); - break; - default: - return NOTIFY_DONE; - } - return NOTIFY_OK; -} - -static int __init machine_kdump_pm_init(void) -{ - pm_notifier(machine_kdump_pm_cb, 0); - return 0; -} -arch_initcall(machine_kdump_pm_init); - /* * Reset the system, copy boot CPU registers to absolute zero, * and jump to the kdump image diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c deleted file mode 100644 index 75b7b307946e..000000000000 --- a/arch/s390/kernel/suspend.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Suspend support specific for s390. - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "entry.h" - -/* - * The restore of the saved pages in an hibernation image will set - * the change and referenced bits in the storage key for each page. - * Overindication of the referenced bits after an hibernation cycle - * does not cause any harm but the overindication of the change bits - * would cause trouble. - * Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each - * page to the most significant byte of the associated page frame - * number in the hibernation image. - */ - -/* - * Key storage is allocated as a linked list of pages. - * The size of the keys array is (PAGE_SIZE - sizeof(long)) - */ -struct page_key_data { - struct page_key_data *next; - unsigned char data[]; -}; - -#define PAGE_KEY_DATA_SIZE (PAGE_SIZE - sizeof(struct page_key_data *)) - -static struct page_key_data *page_key_data; -static struct page_key_data *page_key_rp, *page_key_wp; -static unsigned long page_key_rx, page_key_wx; -unsigned long suspend_zero_pages; - -/* - * For each page in the hibernation image one additional byte is - * stored in the most significant byte of the page frame number. - * On suspend no additional memory is required but on resume the - * keys need to be memorized until the page data has been restored. - * Only then can the storage keys be set to their old state. - */ -unsigned long page_key_additional_pages(unsigned long pages) -{ - return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE); -} - -/* - * Free page_key_data list of arrays. - */ -void page_key_free(void) -{ - struct page_key_data *pkd; - - while (page_key_data) { - pkd = page_key_data; - page_key_data = pkd->next; - free_page((unsigned long) pkd); - } -} - -/* - * Allocate page_key_data list of arrays with enough room to store - * one byte for each page in the hibernation image. - */ -int page_key_alloc(unsigned long pages) -{ - struct page_key_data *pk; - unsigned long size; - - size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE); - while (size--) { - pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL); - if (!pk) { - page_key_free(); - return -ENOMEM; - } - pk->next = page_key_data; - page_key_data = pk; - } - page_key_rp = page_key_wp = page_key_data; - page_key_rx = page_key_wx = 0; - return 0; -} - -/* - * Save the storage key into the upper 8 bits of the page frame number. - */ -void page_key_read(unsigned long *pfn) -{ - struct page *page; - unsigned long addr; - unsigned char key; - - page = pfn_to_page(*pfn); - addr = (unsigned long) page_address(page); - key = (unsigned char) page_get_storage_key(addr) & 0x7f; - if (arch_test_page_nodat(page)) - key |= 0x80; - *(unsigned char *) pfn = key; -} - -/* - * Extract the storage key from the upper 8 bits of the page frame number - * and store it in the page_key_data list of arrays. - */ -void page_key_memorize(unsigned long *pfn) -{ - page_key_wp->data[page_key_wx] = *(unsigned char *) pfn; - *(unsigned char *) pfn = 0; - if (++page_key_wx < PAGE_KEY_DATA_SIZE) - return; - page_key_wp = page_key_wp->next; - page_key_wx = 0; -} - -/* - * Get the next key from the page_key_data list of arrays and set the - * storage key of the page referred by @address. If @address refers to - * a "safe" page the swsusp_arch_resume code will transfer the storage - * key from the buffer page to the original page. - */ -void page_key_write(void *address) -{ - struct page *page; - unsigned char key; - - key = page_key_rp->data[page_key_rx]; - page_set_storage_key((unsigned long) address, key & 0x7f, 0); - page = virt_to_page(address); - if (key & 0x80) - arch_set_page_nodat(page, 0); - else - arch_set_page_dat(page, 0); - if (++page_key_rx >= PAGE_KEY_DATA_SIZE) - return; - page_key_rp = page_key_rp->next; - page_key_rx = 0; -} - -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); - unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end)); - unsigned long end_rodata_pfn = PFN_DOWN(__pa(__end_rodata)) - 1; - unsigned long stext_pfn = PFN_DOWN(__pa(_stext)); - - /* Always save lowcore pages (LC protection might be enabled). */ - if (pfn <= LC_PAGES) - return 0; - if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) - return 1; - /* Skip memory holes and read-only pages (DCSS, ...). */ - if (pfn >= stext_pfn && pfn <= end_rodata_pfn) - return 0; - if (tprot(PFN_PHYS(pfn))) - return 1; - return 0; -} - -/* - * PM notifier callback for suspend - */ -static int suspend_pm_cb(struct notifier_block *nb, unsigned long action, - void *ptr) -{ - switch (action) { - case PM_SUSPEND_PREPARE: - case PM_HIBERNATION_PREPARE: - suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER); - if (!suspend_zero_pages) - return NOTIFY_BAD; - break; - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: - free_pages(suspend_zero_pages, LC_ORDER); - break; - default: - return NOTIFY_DONE; - } - return NOTIFY_OK; -} - -static int __init suspend_pm_init(void) -{ - pm_notifier(suspend_pm_cb, 0); - return 0; -} -arch_initcall(suspend_pm_init); - -void save_processor_state(void) -{ - /* swsusp_arch_suspend() actually saves all cpu register contents. - * Machine checks must be disabled since swsusp_arch_suspend() stores - * register contents to their lowcore save areas. That's the same - * place where register contents on machine checks would be saved. - * To avoid register corruption disable machine checks. - * We must also disable machine checks in the new psw mask for - * program checks, since swsusp_arch_suspend() may generate program - * checks. Disabling machine checks for all other new psw masks is - * just paranoia. - */ - local_mcck_disable(); - /* Disable lowcore protection */ - __ctl_clear_bit(0,28); - S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK; -} - -void restore_processor_state(void) -{ - S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK; - /* Enable lowcore protection */ - __ctl_set_bit(0,28); - local_mcck_enable(); -} - -/* Called at the end of swsusp_arch_resume */ -void s390_early_resume(void) -{ - lgr_info_log(); - channel_subsystem_reinit(); - zpci_rescan(); -} diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S deleted file mode 100644 index a7baf0b5f818..000000000000 --- a/arch/s390/kernel/swsusp.S +++ /dev/null @@ -1,276 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * S390 64-bit swsusp implementation - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - * Michael Holzheu - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Save register context in absolute 0 lowcore and call swsusp_save() to - * create in-memory kernel image. The context is saved in the designated - * "store status" memory locations (see POP). - * We return from this function twice. The first time during the suspend to - * disk process. The second time via the swsusp_arch_resume() function - * (see below) in the resume process. - * This function runs with disabled interrupts. - */ - GEN_BR_THUNK %r14 - - .section .text -ENTRY(swsusp_arch_suspend) - lg %r1,__LC_NODAT_STACK - stmg %r6,%r15,__SF_GPRS(%r1) - aghi %r1,-STACK_FRAME_OVERHEAD - stg %r15,__SF_BACKCHAIN(%r1) - lgr %r15,%r1 - - /* Store FPU registers */ - brasl %r14,save_fpu_regs - - /* Deactivate DAT */ - stnsm __SF_EMPTY(%r15),0xfb - - /* Store prefix register on stack */ - stpx __SF_EMPTY(%r15) - - /* Save prefix register contents for lowcore copy */ - llgf %r10,__SF_EMPTY(%r15) - - /* Get pointer to save area */ - lghi %r1,0x1000 - - /* Save CPU address */ - stap __LC_EXT_CPU_ADDR(%r0) - - /* Store registers */ - mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ - stam %a0,%a15,0x340(%r1) /* store access registers */ - stctg %c0,%c15,0x380(%r1) /* store control registers */ - stmg %r0,%r15,0x280(%r1) /* store general registers */ - - stpt 0x328(%r1) /* store timer */ - stck __SF_EMPTY(%r15) /* store clock */ - stckc 0x330(%r1) /* store clock comparator */ - - /* Update cputime accounting before going to sleep */ - lg %r0,__LC_LAST_UPDATE_TIMER - slg %r0,0x328(%r1) - alg %r0,__LC_SYSTEM_TIMER - stg %r0,__LC_SYSTEM_TIMER - mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) - lg %r0,__LC_LAST_UPDATE_CLOCK - slg %r0,__SF_EMPTY(%r15) - alg %r0,__LC_STEAL_TIMER - stg %r0,__LC_STEAL_TIMER - mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) - - /* Activate DAT */ - stosm __SF_EMPTY(%r15),0x04 - - /* Set prefix page to zero */ - xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) - spx __SF_EMPTY(%r15) - - /* Save absolute zero pages */ - larl %r2,suspend_zero_pages - lg %r2,0(%r2) - lghi %r4,0 - lghi %r3,2*PAGE_SIZE - lghi %r5,2*PAGE_SIZE -1: mvcle %r2,%r4,0 - jo 1b - - /* Copy lowcore to absolute zero lowcore */ - lghi %r2,0 - lgr %r4,%r10 - lghi %r3,2*PAGE_SIZE - lghi %r5,2*PAGE_SIZE -1: mvcle %r2,%r4,0 - jo 1b - - /* Save image */ - brasl %r14,swsusp_save - - /* Restore prefix register and return */ - lghi %r1,0x1000 - spx 0x318(%r1) - lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) - lghi %r2,0 - BR_EX %r14 -ENDPROC(swsusp_arch_suspend) - -/* - * Restore saved memory image to correct place and restore register context. - * Then we return to the function that called swsusp_arch_suspend(). - * swsusp_arch_resume() runs with disabled interrupts. - */ -ENTRY(swsusp_arch_resume) - stmg %r6,%r15,__SF_GPRS(%r15) - lgr %r1,%r15 - aghi %r15,-STACK_FRAME_OVERHEAD - stg %r1,__SF_BACKCHAIN(%r15) - - /* Make all free pages stable */ - lghi %r2,1 - brasl %r14,arch_set_page_states - - /* Set prefix page to zero */ - xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) - spx __SF_EMPTY(%r15) - - /* Deactivate DAT */ - stnsm __SF_EMPTY(%r15),0xfb - - /* Restore saved image */ - larl %r1,restore_pblist - lg %r1,0(%r1) - ltgr %r1,%r1 - jz 2f -0: - lg %r2,8(%r1) - lg %r4,0(%r1) - iske %r0,%r4 - lghi %r3,PAGE_SIZE - lghi %r5,PAGE_SIZE -1: - mvcle %r2,%r4,0 - jo 1b - lg %r2,8(%r1) - sske %r0,%r2 - lg %r1,16(%r1) - ltgr %r1,%r1 - jnz 0b -2: - ptlb /* flush tlb */ - - /* Reset System */ - larl %r1,.Lnew_pgm_check_psw - epsw %r2,%r3 - stm %r2,%r3,0(%r1) - mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) - larl %r1,__swsusp_reset_dma - lg %r1,0(%r1) - BASR_EX %r14,%r1 - larl %r1,smp_cpu_mt_shift - icm %r1,15,0(%r1) - jz smt_done - llgfr %r1,%r1 -smt_loop: - sigp %r1,%r0,SIGP_SET_MULTI_THREADING - brc 8,smt_done /* accepted */ - brc 2,smt_loop /* busy, try again */ -smt_done: - larl %r1,.Lnew_pgm_check_psw - lpswe 0(%r1) -pgm_check_entry: - - /* Switch to original suspend CPU */ - larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ - stap 0(%r1) - llgh %r2,0(%r1) - llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ - cgr %r1,%r2 - je restore_registers /* r1 = r2 -> nothing to do */ - larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ - mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) -3: - sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */ - brc 8,4f /* accepted */ - brc 2,3b /* busy, try again */ - - /* Suspend CPU not available -> panic */ - larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD - larl %r2,.Lpanic_string - brasl %r14,sclp_early_printk_force - larl %r3,.Ldisabled_wait_31 - lpsw 0(%r3) -4: - /* Switch to suspend CPU */ - sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */ - brc 2,4b /* busy, try again */ -5: - sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */ - brc 2,5b /* busy, try again */ -6: j 6b - -restart_suspend: - larl %r1,.Lresume_cpu - llgh %r2,0(%r1) -7: - sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */ - brc 8,7b /* accepted, status 0, still running */ - brc 2,7b /* busy, try again */ - tmll %r9,0x40 /* Test if resume CPU is stopped */ - jz 7b - -restore_registers: - /* Restore registers */ - lghi %r13,0x1000 /* %r1 = pointer to save area */ - - /* Ignore time spent in suspended state. */ - llgf %r1,0x318(%r13) - stck __LC_LAST_UPDATE_CLOCK(%r1) - spt 0x328(%r13) /* reprogram timer */ - //sckc 0x330(%r13) /* set clock comparator */ - - lctlg %c0,%c15,0x380(%r13) /* load control registers */ - lam %a0,%a15,0x340(%r13) /* load access registers */ - - /* Load old stack */ - lg %r15,0x2f8(%r13) - - /* Save prefix register */ - mvc __SF_EMPTY(4,%r15),0x318(%r13) - - /* Restore absolute zero pages */ - lghi %r2,0 - larl %r4,suspend_zero_pages - lg %r4,0(%r4) - lghi %r3,2*PAGE_SIZE - lghi %r5,2*PAGE_SIZE -1: mvcle %r2,%r4,0 - jo 1b - - /* Restore prefix register */ - spx __SF_EMPTY(%r15) - - /* Activate DAT */ - stosm __SF_EMPTY(%r15),0x04 - - /* Make all free pages unstable */ - lghi %r2,0 - brasl %r14,arch_set_page_states - - /* Call arch specific early resume code */ - brasl %r14,s390_early_resume - - /* Return 0 */ - lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) - lghi %r2,0 - BR_EX %r14 -ENDPROC(swsusp_arch_resume) - - .section .data..nosave,"aw",@progbits - .align 8 -.Ldisabled_wait_31: - .long 0x000a0000,0x00000000 -.Lpanic_string: - .asciz "Resume not possible because suspend CPU is no longer available\n" - .align 8 -.Lrestart_suspend_psw: - .quad 0x0000000180000000,restart_suspend -.Lnew_pgm_check_psw: - .quad 0,pgm_check_entry -.Lresume_cpu: - .byte 0,0 diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index a51c892f14f3..ae989b740376 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -49,7 +48,6 @@ static volatile long cmm_pages_target; static volatile long cmm_timed_pages_target; static long cmm_timeout_pages; static long cmm_timeout_seconds; -static int cmm_suspended; static struct cmm_page_array *cmm_page_list; static struct cmm_page_array *cmm_timed_page_list; @@ -151,9 +149,9 @@ static int cmm_thread(void *dummy) while (1) { rc = wait_event_interruptible(cmm_thread_wait, - (!cmm_suspended && (cmm_pages != cmm_pages_target || - cmm_timed_pages != cmm_timed_pages_target)) || - kthread_should_stop()); + cmm_pages != cmm_pages_target || + cmm_timed_pages != cmm_timed_pages_target || + kthread_should_stop()); if (kthread_should_stop() || rc == -ERESTARTSYS) { cmm_pages_target = cmm_pages; cmm_timed_pages_target = cmm_timed_pages; @@ -390,38 +388,6 @@ static void cmm_smsg_target(const char *from, char *msg) static struct ctl_table_header *cmm_sysctl_header; -static int cmm_suspend(void) -{ - cmm_suspended = 1; - cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); - cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); - return 0; -} - -static int cmm_resume(void) -{ - cmm_suspended = 0; - cmm_kick_thread(); - return 0; -} - -static int cmm_power_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - switch (event) { - case PM_POST_HIBERNATION: - return cmm_resume(); - case PM_HIBERNATION_PREPARE: - return cmm_suspend(); - default: - return NOTIFY_DONE; - } -} - -static struct notifier_block cmm_power_notifier = { - .notifier_call = cmm_power_event, -}; - static int __init cmm_init(void) { int rc = -ENOMEM; @@ -446,16 +412,11 @@ static int __init cmm_init(void) rc = register_oom_notifier(&cmm_oom_nb); if (rc < 0) goto out_oom_notify; - rc = register_pm_notifier(&cmm_power_notifier); - if (rc) - goto out_pm; cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); if (!IS_ERR(cmm_thread_ptr)) return 0; rc = PTR_ERR(cmm_thread_ptr); - unregister_pm_notifier(&cmm_power_notifier); -out_pm: unregister_oom_notifier(&cmm_oom_nb); out_oom_notify: #ifdef CONFIG_CMM_IUCV @@ -475,7 +436,6 @@ static void __exit cmm_exit(void) #ifdef CONFIG_CMM_IUCV smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); #endif - unregister_pm_notifier(&cmm_power_notifier); unregister_oom_notifier(&cmm_oom_nb); kthread_stop(cmm_thread_ptr); del_timer_sync(&cmm_timer); diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index f8c6faab41f4..e22c06d5f206 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -367,20 +367,4 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) } } -#ifdef CONFIG_HIBERNATION -bool kernel_page_present(struct page *page) -{ - unsigned long addr; - int cc; - - addr = page_to_phys(page); - asm volatile( - " lra %1,0(%1)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (cc), "+a" (addr) : : "cc"); - return cc == 0; -} -#endif /* CONFIG_HIBERNATION */ - #endif /* CONFIG_DEBUG_PAGEALLOC */ diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index bc61ea18e88d..d4eaba24e300 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -607,49 +607,6 @@ void pcibios_disable_device(struct pci_dev *pdev) zpci_debug_exit_device(zdev); } -#ifdef CONFIG_HIBERNATE_CALLBACKS -static int zpci_restore(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct zpci_dev *zdev = to_zpci(pdev); - int ret = 0; - - if (zdev->state != ZPCI_FN_STATE_ONLINE) - goto out; - - ret = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES); - if (ret) - goto out; - - zpci_map_resources(pdev); - zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, - (u64) zdev->dma_table); - -out: - return ret; -} - -static int zpci_freeze(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct zpci_dev *zdev = to_zpci(pdev); - - if (zdev->state != ZPCI_FN_STATE_ONLINE) - return 0; - - zpci_unregister_ioat(zdev, 0); - zpci_unmap_resources(pdev); - return clp_disable_fh(zdev); -} - -struct dev_pm_ops pcibios_pm_ops = { - .thaw_noirq = zpci_restore, - .freeze_noirq = zpci_freeze, - .restore_noirq = zpci_restore, - .poweroff_noirq = zpci_freeze, -}; -#endif /* CONFIG_HIBERNATE_CALLBACKS */ - static int zpci_alloc_domain(struct zpci_dev *zdev) { if (zpci_unique_uid) { From 086b2d78375cffe58f5341359bebec0650793811 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 18 Mar 2020 20:55:20 +0100 Subject: [PATCH 462/809] PM: remove s390 specific callbacks ARCH_SAVE_PAGE_KEYS has been introduced in order to be able to save and restore s390 specific storage keys into a hibernation image. With hibernation support removed from s390 there is no point in keeping the callbacks. Acked-by: Christian Borntraeger Acked-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- include/linux/suspend.h | 34 ---------------------------------- kernel/power/Kconfig | 3 --- kernel/power/snapshot.c | 18 ------------------ 3 files changed, 55 deletions(-) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 2b2055b035ee..4fcc6fd0cbd6 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -566,38 +566,4 @@ static inline void queue_up_suspend_work(void) {} #endif /* !CONFIG_PM_AUTOSLEEP */ -#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS -/* - * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture - * to save/restore additional information to/from the array of page - * frame numbers in the hibernation image. For s390 this is used to - * save and restore the storage key for each page that is included - * in the hibernation image. - */ -unsigned long page_key_additional_pages(unsigned long pages); -int page_key_alloc(unsigned long pages); -void page_key_free(void); -void page_key_read(unsigned long *pfn); -void page_key_memorize(unsigned long *pfn); -void page_key_write(void *address); - -#else /* !CONFIG_ARCH_SAVE_PAGE_KEYS */ - -static inline unsigned long page_key_additional_pages(unsigned long pages) -{ - return 0; -} - -static inline int page_key_alloc(unsigned long pages) -{ - return 0; -} - -static inline void page_key_free(void) {} -static inline void page_key_read(unsigned long *pfn) {} -static inline void page_key_memorize(unsigned long *pfn) {} -static inline void page_key_write(void *address) {} - -#endif /* !CONFIG_ARCH_SAVE_PAGE_KEYS */ - #endif /* _LINUX_SUSPEND_H */ diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 7cbfbeacd68a..c208566c844b 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -80,9 +80,6 @@ config HIBERNATION For more information take a look at . -config ARCH_SAVE_PAGE_KEYS - bool - config PM_STD_PARTITION string "Default resume partition" depends on HIBERNATION diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index ddade80ad276..e99d13b0b8fc 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1744,9 +1744,6 @@ int hibernate_preallocate_memory(void) count += highmem; count -= totalreserve_pages; - /* Add number of pages required for page keys (s390 only). */ - size += page_key_additional_pages(saveable); - /* Compute the maximum number of saveable pages to leave in memory. */ max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE); @@ -2075,8 +2072,6 @@ static inline void pack_pfns(unsigned long *buf, struct memory_bitmap *bm) buf[j] = memory_bm_next_pfn(bm); if (unlikely(buf[j] == BM_END_OF_MAP)) break; - /* Save page key for data page (s390 only). */ - page_key_read(buf + j); } } @@ -2226,9 +2221,6 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) if (unlikely(buf[j] == BM_END_OF_MAP)) break; - /* Extract and buffer page key for data page (s390 only). */ - page_key_memorize(buf + j); - if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j])) memory_bm_set_bit(bm, buf[j]); else @@ -2623,11 +2615,6 @@ int snapshot_write_next(struct snapshot_handle *handle) if (error) return error; - /* Allocate buffer for page keys. */ - error = page_key_alloc(nr_copy_pages); - if (error) - return error; - hibernate_restore_protection_begin(); } else if (handle->cur <= nr_meta_pages + 1) { error = unpack_orig_pfns(buffer, ©_bm); @@ -2649,8 +2636,6 @@ int snapshot_write_next(struct snapshot_handle *handle) } } else { copy_last_highmem_page(); - /* Restore page key for data page (s390 only). */ - page_key_write(handle->buffer); hibernate_restore_protect_page(handle->buffer); handle->buffer = get_buffer(&orig_bm, &ca); if (IS_ERR(handle->buffer)) @@ -2673,9 +2658,6 @@ int snapshot_write_next(struct snapshot_handle *handle) void snapshot_write_finalize(struct snapshot_handle *handle) { copy_last_highmem_page(); - /* Restore page key for data page (s390 only). */ - page_key_write(handle->buffer); - page_key_free(); hibernate_restore_protect_page(handle->buffer); /* Do that only if we have loaded the image entirely */ if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) { From 9289224040cb120605ffa35263ea27a30105019e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 16 Mar 2020 09:20:38 +0100 Subject: [PATCH 463/809] s390/qdio: pass ISC as parameter to chsc_sadc() When issuing a SADC for a QDIO device, don't hardcode the ISC but use whatever is specified in qdio's handler for Adapter Interrupts. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/chsc.c | 5 +++-- drivers/s390/cio/chsc.h | 3 ++- drivers/s390/cio/qdio_thinint.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 6392a1b95b02..1ca73c2e5a8f 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -180,11 +180,12 @@ EXPORT_SYMBOL_GPL(chsc_ssqd); * @scssc: request and response block for SADC * @summary_indicator_addr: summary indicator address * @subchannel_indicator_addr: subchannel indicator address + * @isc: Interruption Subclass for this subchannel * * Returns 0 on success. */ int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, - u64 summary_indicator_addr, u64 subchannel_indicator_addr) + u64 summary_indicator_addr, u64 subchannel_indicator_addr, u8 isc) { memset(scssc, 0, sizeof(*scssc)); scssc->request.length = 0x0fe0; @@ -196,7 +197,7 @@ int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, scssc->ks = PAGE_DEFAULT_KEY >> 4; scssc->kc = PAGE_DEFAULT_KEY >> 4; - scssc->isc = QDIO_AIRQ_ISC; + scssc->isc = isc; scssc->schid = schid; /* enable the time delay disablement facility */ diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index e57d68e325a3..34de6d77442c 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -163,7 +163,8 @@ void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd); int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, - u64 summary_indicator_addr, u64 subchannel_indicator_addr); + u64 summary_indicator_addr, u64 subchannel_indicator_addr, + u8 isc); int chsc_sgib(u32 origin); int chsc_error_from_response(int response); diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 7c4e4ec08a12..999b998ea0c9 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -211,7 +211,7 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) } rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr, - subchannel_indicator_addr); + subchannel_indicator_addr, tiqdio_airq.isc); if (rc) { DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, scssc->response.code); From 969ae01bab2fe938b4c8324836038b5ac1c78fac Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Tue, 17 Mar 2020 12:59:37 +0100 Subject: [PATCH 464/809] s390/pci: Fix zpci_alloc_domain() over allocation Until now zpci_alloc_domain() only prevented more than CONFIG_PCI_NR_FUNCTIONS from being added when using automatic domain allocation. When explicit UIDs were defined UIDs above CONFIG_PCI_NR_FUNCTIONS were not counted at all. When more PCI functions are added this could lead to various errors including under sized IRQ vectors and similar issues. Fix this by explicitly tracking the number of allocated domains. Signed-off-by: Niklas Schnelle Reviewed-by: Pierre Morel Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pci.h | 1 + arch/s390/pci/pci.c | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 73b69a777152..93527655e752 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -26,6 +26,7 @@ int pci_proc_domain(struct pci_bus *); #define ZPCI_NR_DMA_SPACES 1 #define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS +#define ZPCI_DOMAIN_BITMAP_SIZE (1 << 16) /* PCI Function Controls */ #define ZPCI_FC_FN_ENABLED 0x80 diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index d4eaba24e300..2b90a90aa81d 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -40,8 +40,9 @@ static LIST_HEAD(zpci_list); static DEFINE_SPINLOCK(zpci_list_lock); -static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); +static DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE); static DEFINE_SPINLOCK(zpci_domain_lock); +static unsigned int zpci_num_domains_allocated; #define ZPCI_IOMAP_ENTRIES \ min(((unsigned long) ZPCI_NR_DEVICES * PCI_STD_NUM_BARS / 2), \ @@ -609,12 +610,16 @@ void pcibios_disable_device(struct pci_dev *pdev) static int zpci_alloc_domain(struct zpci_dev *zdev) { + spin_lock(&zpci_domain_lock); + if (zpci_num_domains_allocated > (ZPCI_NR_DEVICES - 1)) { + spin_unlock(&zpci_domain_lock); + pr_err("Adding PCI function %08x failed because the configured limit of %d is reached\n", + zdev->fid, ZPCI_NR_DEVICES); + return -ENOSPC; + } + if (zpci_unique_uid) { zdev->domain = (u16) zdev->uid; - if (zdev->domain >= ZPCI_NR_DEVICES) - return 0; - - spin_lock(&zpci_domain_lock); if (test_bit(zdev->domain, zpci_domain)) { spin_unlock(&zpci_domain_lock); pr_err("Adding PCI function %08x failed because domain %04x is already assigned\n", @@ -622,30 +627,27 @@ static int zpci_alloc_domain(struct zpci_dev *zdev) return -EEXIST; } set_bit(zdev->domain, zpci_domain); + zpci_num_domains_allocated++; spin_unlock(&zpci_domain_lock); return 0; } - - spin_lock(&zpci_domain_lock); + /* + * We can always auto allocate domains below ZPCI_NR_DEVICES. + * There is either a free domain or we have reached the maximum in + * which case we would have bailed earlier. + */ zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES); - if (zdev->domain == ZPCI_NR_DEVICES) { - spin_unlock(&zpci_domain_lock); - pr_err("Adding PCI function %08x failed because the configured limit of %d is reached\n", - zdev->fid, ZPCI_NR_DEVICES); - return -ENOSPC; - } set_bit(zdev->domain, zpci_domain); + zpci_num_domains_allocated++; spin_unlock(&zpci_domain_lock); return 0; } static void zpci_free_domain(struct zpci_dev *zdev) { - if (zdev->domain >= ZPCI_NR_DEVICES) - return; - spin_lock(&zpci_domain_lock); clear_bit(zdev->domain, zpci_domain); + zpci_num_domains_allocated--; spin_unlock(&zpci_domain_lock); } From 7a11c67a1ff9b0231eaaaa6a28294776d55b569a Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Wed, 18 Mar 2020 13:53:16 +0100 Subject: [PATCH 465/809] s390/pci: Improve handling of unset UID When UID checking is enabled a UID value of 0 is invalid and can not be set by the user. On z/VM it is however used to indicate an unset UID. Until now, this lead to the behavior that one PCI function could be attached with UID 0 after which z/VM would prohibit further attachment. Now if the user then turns off UID checking in z/VM the user could seemingly attach additional PCI functions that would however not show up in Linux as that would not be informed of the change in UID checking mode. This is unexpected and confusing and lead to bug reports against Linux. Instead now, if we encounter an unset UID value of 0 treat it as indicating that UID checking was turned off, switch to automatic domain allocation, and warn the user of the possible misconfiguration. Signed-off-by: Niklas Schnelle Reviewed-by: Peter Oberparleiter Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pci.h | 3 +++ arch/s390/pci/pci.c | 8 ++++++++ arch/s390/pci/pci_clp.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 93527655e752..7485ee561fec 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -189,6 +189,9 @@ int clp_enable_fh(struct zpci_dev *, u8); int clp_disable_fh(struct zpci_dev *); int clp_get_state(u32 fid, enum zpci_state *state); +/* UID */ +void update_uid_checking(bool new); + /* IOMMU Interface */ int zpci_init_iommu(struct zpci_dev *zdev); void zpci_destroy_iommu(struct zpci_dev *zdev); diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 2b90a90aa81d..cf7485bdd7cf 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -620,6 +620,13 @@ static int zpci_alloc_domain(struct zpci_dev *zdev) if (zpci_unique_uid) { zdev->domain = (u16) zdev->uid; + if (zdev->domain == 0) { + pr_warn("UID checking is active but no UID is set for PCI function %08x, so automatic domain allocation is used instead\n", + zdev->fid); + update_uid_checking(false); + goto auto_allocate; + } + if (test_bit(zdev->domain, zpci_domain)) { spin_unlock(&zpci_domain_lock); pr_err("Adding PCI function %08x failed because domain %04x is already assigned\n", @@ -631,6 +638,7 @@ static int zpci_alloc_domain(struct zpci_dev *zdev) spin_unlock(&zpci_domain_lock); return 0; } +auto_allocate: /* * We can always auto allocate domains below ZPCI_NR_DEVICES. * There is either a free domain or we have reached the maximum in diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 0d3d8f170ea4..ea794ae755ae 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -24,7 +24,7 @@ bool zpci_unique_uid; -static void update_uid_checking(bool new) +void update_uid_checking(bool new) { if (zpci_unique_uid != new) zpci_dbg(1, "uid checking:%d\n", new); From 3cc7c927102d8ce836735c1005a7d102a148579c Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 19 Mar 2020 16:01:04 +0100 Subject: [PATCH 466/809] s390/ap: Remove ap device suspend and resume callbacks With the removal of the s390 hibernate support the suspend and resume callbacks for the ap devices are not needed any more. This patch removes the callbacks and the ap bus' registration struct for the power management. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 171b0a08e0f9..0246bb35790f 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -587,24 +587,6 @@ static int ap_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } -static int ap_dev_suspend(struct device *dev) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - - if (ap_dev->drv && ap_dev->drv->suspend) - ap_dev->drv->suspend(ap_dev); - return 0; -} - -static int ap_dev_resume(struct device *dev) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - - if (ap_dev->drv && ap_dev->drv->resume) - ap_dev->drv->resume(ap_dev); - return 0; -} - static void ap_bus_suspend(void) { AP_DBF(DBF_DEBUG, "%s running\n", __func__); @@ -694,13 +676,10 @@ static struct notifier_block ap_power_notifier = { .notifier_call = ap_power_event, }; -static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, ap_dev_resume); - static struct bus_type ap_bus_type = { .name = "ap", .match = &ap_bus_match, .uevent = &ap_uevent, - .pm = &ap_bus_pm_ops, }; static int __ap_revise_reserved(struct device *dev, void *dummy) From d4953f7ef1a2e87ef732823af35361404d13fea8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 14 Mar 2020 10:03:56 -0700 Subject: [PATCH 467/809] perf parse-events: Fix 3 use after frees found with clang ASAN Reproducible with a clang asan build and then running perf test in particular 'Parse event definition strings'. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: clang-built-linux@googlegroups.com Link: http://lore.kernel.org/lkml/20200314170356.62914-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + tools/perf/util/parse-events.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 816d930d774e..15ccd193483f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1287,6 +1287,7 @@ void perf_evsel__exit(struct evsel *evsel) perf_thread_map__put(evsel->core.threads); zfree(&evsel->group_name); zfree(&evsel->name); + zfree(&evsel->pmu_name); perf_evsel__object.fini(evsel); } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a7dc0b096974..10107747b361 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1449,7 +1449,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, evsel = __add_event(list, &parse_state->idx, &attr, NULL, pmu, NULL, auto_merge_stats, NULL); if (evsel) { - evsel->pmu_name = name; + evsel->pmu_name = name ? strdup(name) : NULL; evsel->use_uncore_alias = use_uncore_alias; return 0; } else { @@ -1497,7 +1497,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, evsel->snapshot = info.snapshot; evsel->metric_expr = info.metric_expr; evsel->metric_name = info.metric_name; - evsel->pmu_name = name; + evsel->pmu_name = name ? strdup(name) : NULL; evsel->use_uncore_alias = use_uncore_alias; evsel->percore = config_term_percore(&evsel->config_terms); } @@ -1547,7 +1547,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, if (!parse_events_add_pmu(parse_state, list, pmu->name, head, true, true)) { - pr_debug("%s -> %s/%s/\n", config, + pr_debug("%s -> %s/%s/\n", str, pmu->name, alias->str); ok++; } From 7eec00a74720d35b6d89505350e5b08ecef376c0 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 6 Mar 2020 09:57:58 +0800 Subject: [PATCH 468/809] perf symbols: Consolidate symbol fixup issue After copying Arm64's perf archive with object files and perf.data file to x86 laptop, the x86's perf kernel symbol resolution fails. It outputs 'unknown' for all symbols parsing. This issue is root caused by the function elf__needs_adjust_symbols(), x86 perf tool uses one weak version, Arm64 (and powerpc) has rewritten their own version. elf__needs_adjust_symbols() decides if need to parse symbols with the relative offset address; but x86 building uses the weak function which misses to check for the elf type 'ET_DYN', so that it cannot parse symbols in Arm DSOs due to the wrong result from elf__needs_adjust_symbols(). The DSO parsing should not depend on any specific architecture perf building; e.g. x86 perf tool can parse Arm and Arm64 DSOs, vice versa. And confirmed by Naveen N. Rao that powerpc64 kernels are not being built as ET_DYN anymore and change to ET_EXEC. This patch removes the arch specific functions for Arm64 and powerpc and changes elf__needs_adjust_symbols() as a common function. In the common elf__needs_adjust_symbols(), it checks an extra condition 'ET_DYN' for elf header type. With this fixing, the Arm64 DSO can be parsed properly with x86's perf tool. Before: # perf script main 3258 1 branches: 0 [unknown] ([unknown]) => ffff800010c4665c [unknown] ([kernel.kallsyms]) main 3258 1 branches: ffff800010c46670 [unknown] ([kernel.kallsyms]) => ffff800010c4eaec [unknown] ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eaec [unknown] ([kernel.kallsyms]) => ffff800010c4eb00 [unknown] ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eb08 [unknown] ([kernel.kallsyms]) => ffff800010c4e780 [unknown] ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4e7a0 [unknown] ([kernel.kallsyms]) => ffff800010c4eeac [unknown] ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eebc [unknown] ([kernel.kallsyms]) => ffff800010c4ed80 [unknown] ([kernel.kallsyms]) After: # perf script main 3258 1 branches: 0 [unknown] ([unknown]) => ffff800010c4665c coresight_timeout+0x54 ([kernel.kallsyms]) main 3258 1 branches: ffff800010c46670 coresight_timeout+0x68 ([kernel.kallsyms]) => ffff800010c4eaec etm4_enable_hw+0x3cc ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eaec etm4_enable_hw+0x3cc ([kernel.kallsyms]) => ffff800010c4eb00 etm4_enable_hw+0x3e0 ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eb08 etm4_enable_hw+0x3e8 ([kernel.kallsyms]) => ffff800010c4e780 etm4_enable_hw+0x60 ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4e7a0 etm4_enable_hw+0x80 ([kernel.kallsyms]) => ffff800010c4eeac etm4_enable+0x2d4 ([kernel.kallsyms]) main 3258 1 branches: ffff800010c4eebc etm4_enable+0x2e4 ([kernel.kallsyms]) => ffff800010c4ed80 etm4_enable+0x1a8 ([kernel.kallsyms]) v3: Changed to check for ET_DYN across all architectures. v2: Fixed Arm64 and powerpc native building. Reported-by: Mike Leach Signed-off-by: Leo Yan Reviewed-by: Naveen N. Rao Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Allison Randal Cc: Enrico Weigelt Cc: Greg Kroah-Hartman Cc: Hendrik Brueckner Cc: John Garry Cc: Kate Stewart Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Thomas Richter Link: http://lore.kernel.org/lkml/20200306015759.10084-1-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/Build | 1 - tools/perf/arch/arm64/util/sym-handling.c | 19 ------------------- tools/perf/arch/powerpc/util/Build | 1 - tools/perf/arch/powerpc/util/sym-handling.c | 10 ---------- tools/perf/util/symbol-elf.c | 10 ++++++++-- 5 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 tools/perf/arch/arm64/util/sym-handling.c diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index 0a7782c61209..789956f76d85 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,6 +1,5 @@ perf-y += header.o perf-y += perf_regs.o -perf-y += sym-handling.o perf-$(CONFIG_DWARF) += dwarf-regs.o perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm64/util/sym-handling.c b/tools/perf/arch/arm64/util/sym-handling.c deleted file mode 100644 index 8dfa3e5229f1..000000000000 --- a/tools/perf/arch/arm64/util/sym-handling.c +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Copyright (C) 2015 Naveen N. Rao, IBM Corporation - */ - -#include "symbol.h" // for the elf__needs_adjust_symbols() prototype -#include - -#ifdef HAVE_LIBELF_SUPPORT -#include - -bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) -{ - return ehdr.e_type == ET_EXEC || - ehdr.e_type == ET_REL || - ehdr.e_type == ET_DYN; -} -#endif diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index 7cf0b8803097..e5c9504f8586 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -1,5 +1,4 @@ perf-y += header.o -perf-y += sym-handling.o perf-y += kvm-stat.o perf-y += perf_regs.o perf-y += mem-events.o diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index abb7a12d8f93..0856b32f9e08 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -10,16 +10,6 @@ #include "probe-event.h" #include "probe-file.h" -#ifdef HAVE_LIBELF_SUPPORT -bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) -{ - return ehdr.e_type == ET_EXEC || - ehdr.e_type == ET_REL || - ehdr.e_type == ET_DYN; -} - -#endif - int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb __maybe_unused) { diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 1965aefccb02..be5b493f8284 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -704,9 +704,15 @@ void symsrc__destroy(struct symsrc *ss) close(ss->fd); } -bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr) +bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) { - return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL; + /* + * Usually vmlinux is an ELF file with type ET_EXEC for most + * architectures; except Arm64 kernel is linked with option + * '-share', so need to check type ET_DYN. + */ + return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL || + ehdr.e_type == ET_DYN; } int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, From 443bc639e518c6c4e8fc2e0456cccf3a04f6e77f Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 27 Feb 2020 12:39:37 +0800 Subject: [PATCH 469/809] perf report: Print al_addr when symbol is not found For branch mode, if the symbol is not found, it prints the address. For example, 0x0000555eee0365a0 in below output. Overhead Command Source Shared Object Source Symbol Target Symbol 17.55% div libc-2.27.so [.] __random [.] __random 6.11% div div [.] 0x0000555eee0365a0 [.] rand 6.10% div libc-2.27.so [.] rand [.] 0x0000555eee036769 5.80% div libc-2.27.so [.] __random_r [.] __random 5.72% div libc-2.27.so [.] __random [.] __random_r 5.62% div libc-2.27.so [.] __random_r [.] __random_r 5.38% div libc-2.27.so [.] __random [.] rand 4.56% div libc-2.27.so [.] __random [.] __random 4.49% div div [.] 0x0000555eee036779 [.] 0x0000555eee0365ff 4.25% div div [.] 0x0000555eee0365fa [.] 0x0000555eee036760 But it's not very easy to understand what the instructions are in the binary. So this patch uses the al_addr instead. With this patch, the output is Overhead Command Source Shared Object Source Symbol Target Symbol 17.55% div libc-2.27.so [.] __random [.] __random 6.11% div div [.] 0x00000000000005a0 [.] rand 6.10% div libc-2.27.so [.] rand [.] 0x0000000000000769 5.80% div libc-2.27.so [.] __random_r [.] __random 5.72% div libc-2.27.so [.] __random [.] __random_r 5.62% div libc-2.27.so [.] __random_r [.] __random_r 5.38% div libc-2.27.so [.] __random [.] rand 4.56% div libc-2.27.so [.] __random [.] __random 4.49% div div [.] 0x0000000000000779 [.] 0x00000000000005ff 4.25% div div [.] 0x00000000000005fa [.] 0x0000000000000760 Now we can use objdump to dump the object starting from 0x5a0. For example, objdump -d --start-address 0x5a0 div 00000000000005a0 : 5a0: ff 25 2a 0a 20 00 jmpq *0x200a2a(%rip) # 200fd0 <__cxa_finalize@plt+0x200a20> 5a6: 68 02 00 00 00 pushq $0x2 5ab: e9 c0 ff ff ff jmpq 570 ... Committer testing: [root@seventh ~]# perf record -a -b sleep 1 [root@seventh ~]# perf report --header-only | grep cpudesc # cpudesc : Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz [root@seventh ~]# perf evlist -v cycles: size: 120, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|CPU|PERIOD|BRANCH_STACK, read_format: ID, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, precise_ip: 3, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1, ksymbol: 1, bpf_event: 1, branch_sample_type: ANY [root@seventh ~]# Before: [root@seventh ~]# perf report --stdio --dso libsystemd-shared-241.so | head -20 # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 2K of event 'cycles' # Event count (approx.): 2240 # # Overhead Command Source Shared Object Source Symbol Target Symbol Basic Block Cycles # ........ ............... ........................ ...................... ...................... .................. # 0.13% systemd-journal libc-2.29.so [.] cfree@GLIBC_2.2.5 [.] _int_free 1 0.09% systemd libsystemd-shared-241.so [.] 0x00007fe406465c82 [.] 0x00007fe406465d80 1 0.09% systemd libsystemd-shared-241.so [.] 0x00007fe406465ded [.] 0x00007fe406465c30 1 0.09% systemd libsystemd-shared-241.so [.] 0x00007fe406465e4e [.] 0x00007fe406465de0 1 0.09% systemd-journal systemd-journald [.] free@plt [.] cfree@GLIBC_2.2.5 1 0.09% systemd-journal libc-2.29.so [.] _int_free [.] _int_free 18 0.09% systemd-journal libc-2.29.so [.] _int_free [.] _int_free 2 0.04% systemd libsystemd-shared-241.so [.] bus_resolve@plt [.] bus_resolve 204 0.04% systemd libsystemd-shared-241.so [.] getpid_cached@plt [.] getpid_cached 7 [root@seventh ~]# After: [root@seventh ~]# perf report --stdio --dso libsystemd-shared-241.so | head -20 # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 2K of event 'cycles' # Event count (approx.): 2240 # # Overhead Command Source Shared Object Source Symbol Target Symbol Basic Block Cycles # ........ ............... ........................ ...................... ...................... .................. # 0.13% systemd-journal libc-2.29.so [.] cfree@GLIBC_2.2.5 [.] _int_free 1 0.09% systemd libsystemd-shared-241.so [.] 0x00000000000f7c82 [.] 0x00000000000f7d80 1 0.09% systemd libsystemd-shared-241.so [.] 0x00000000000f7ded [.] 0x00000000000f7c30 1 0.09% systemd libsystemd-shared-241.so [.] 0x00000000000f7e4e [.] 0x00000000000f7de0 1 0.09% systemd-journal systemd-journald [.] free@plt [.] cfree@GLIBC_2.2.5 1 0.09% systemd-journal libc-2.29.so [.] _int_free [.] _int_free 18 0.09% systemd-journal libc-2.29.so [.] _int_free [.] _int_free 2 0.04% systemd libsystemd-shared-241.so [.] bus_resolve@plt [.] bus_resolve 204 0.04% systemd libsystemd-shared-241.so [.] getpid_cached@plt [.] getpid_cached 7 [root@seventh ~]# Lets use -v to get full paths and then try objdump on the unresolved address: [root@seventh ~]# perf report -v --stdio --dso libsystemd-shared-241.so |& grep libsystemd-shared-241.so | tail -1 0.04% systemd-journal /usr/lib/systemd/libsystemd-shared-241.so 0x80c1a B [.] 0x0000000000080c1a 0x80a95 B [.] 0x0000000000080a95 61 [root@seventh ~]# [root@seventh ~]# objdump -d --start-address 0x00000000000f7d80 /usr/lib/systemd/libsystemd-shared-241.so | head -20 /usr/lib/systemd/libsystemd-shared-241.so: file format elf64-x86-64 Disassembly of section .text: 00000000000f7d80 : f7d80: 41 39 11 cmp %edx,(%r9) f7d83: 0f 84 ff fe ff ff je f7c88 f7d89: 4c 8d 05 97 09 0c 00 lea 0xc0997(%rip),%r8 # 1b8727 f7d90: b9 49 00 00 00 mov $0x49,%ecx f7d95: 48 8d 15 c9 f5 0b 00 lea 0xbf5c9(%rip),%rdx # 1b7365 f7d9c: 31 ff xor %edi,%edi f7d9e: 48 8d 35 9b ff 0b 00 lea 0xbff9b(%rip),%rsi # 1b7d40 f7da5: e8 a6 d6 f4 ff callq 45450 f7daa: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) f7db0: 41 56 push %r14 f7db2: 41 55 push %r13 f7db4: 41 54 push %r12 f7db6: 55 push %rbp [root@seventh ~]# If we tried the the reported address before this patch: [root@seventh ~]# objdump -d --start-address 0x00007fe406465d80 /usr/lib/systemd/libsystemd-shared-241.so | head -20 /usr/lib/systemd/libsystemd-shared-241.so: file format elf64-x86-64 [root@seventh ~]# Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Tested-by: Ravi Bangoria Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200227043939.4403-2-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index ab0cfd790ad0..e860595576c2 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -869,7 +869,8 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf, if (he->branch_info) { struct addr_map_symbol *from = &he->branch_info->from; - return _hist_entry__sym_snprintf(&from->ms, from->addr, he->level, bf, size, width); + return _hist_entry__sym_snprintf(&from->ms, from->al_addr, + he->level, bf, size, width); } return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); @@ -881,7 +882,8 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf, if (he->branch_info) { struct addr_map_symbol *to = &he->branch_info->to; - return _hist_entry__sym_snprintf(&to->ms, to->addr, he->level, bf, size, width); + return _hist_entry__sym_snprintf(&to->ms, to->al_addr, + he->level, bf, size, width); } return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); From 6473ea760ca1707ade74de5b57e74189d14f8e10 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:09 +0200 Subject: [PATCH 470/809] fsnotify: tidy up FS_ and FAN_ constants Order by value, so the free value ranges are easier to find. Link: https://lore.kernel.org/r/20200319151022.31456-2-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify_backend.h | 11 +++++------ include/uapi/linux/fanotify.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 1915bdba2fad..db3cabb4600e 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -49,16 +49,15 @@ #define FS_OPEN_EXEC_PERM 0x00040000 /* open/exec event in a permission hook */ #define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ -#define FS_ISDIR 0x40000000 /* event occurred against dir */ -#define FS_IN_ONESHOT 0x80000000 /* only send event once */ - -#define FS_DN_RENAME 0x10000000 /* file renamed */ -#define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ - /* This inode cares about things that happen to its children. Always set for * dnotify and inotify. */ #define FS_EVENT_ON_CHILD 0x08000000 +#define FS_DN_RENAME 0x10000000 /* file renamed */ +#define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ +#define FS_ISDIR 0x40000000 /* event occurred against dir */ +#define FS_IN_ONESHOT 0x80000000 /* only send event once */ + #define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO) /* diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index b9effa6f8503..2a1844edda47 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -25,9 +25,9 @@ #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ #define FAN_OPEN_EXEC_PERM 0x00040000 /* File open/exec in perm check */ -#define FAN_ONDIR 0x40000000 /* event occurred against dir */ +#define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */ -#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ +#define FAN_ONDIR 0x40000000 /* Event occurred against dir */ /* helper events */ #define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ From eae36a2b8324c9dd0a66b2ae32abd4a456e49c39 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:10 +0200 Subject: [PATCH 471/809] fsnotify: factor helpers fsnotify_dentry() and fsnotify_file() Most of the code in fsnotify hooks is boiler plate of one or the other. Link: https://lore.kernel.org/r/20200319151022.31456-3-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify.h | 99 +++++++++++++++------------------------- 1 file changed, 37 insertions(+), 62 deletions(-) diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index a2d5d175d3c1..f54936aa0365 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -41,16 +41,36 @@ static inline int fsnotify_parent(const struct path *path, } /* - * Simple wrapper to consolidate calls fsnotify_parent()/fsnotify() when - * an event is on a path. + * Simple wrappers to consolidate calls fsnotify_parent()/fsnotify() when + * an event is on a file/dentry. */ -static inline int fsnotify_path(struct inode *inode, const struct path *path, - __u32 mask) +static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) { - int ret = fsnotify_parent(path, NULL, mask); + struct inode *inode = d_inode(dentry); + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + + fsnotify_parent(NULL, dentry, mask); + fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); +} + +static inline int fsnotify_file(struct file *file, __u32 mask) +{ + const struct path *path = &file->f_path; + struct inode *inode = file_inode(file); + int ret; + + if (file->f_mode & FMODE_NONOTIFY) + return 0; + + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + + ret = fsnotify_parent(path, NULL, mask); if (ret) return ret; + return fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } @@ -58,19 +78,16 @@ static inline int fsnotify_path(struct inode *inode, const struct path *path, static inline int fsnotify_perm(struct file *file, int mask) { int ret; - const struct path *path = &file->f_path; - struct inode *inode = file_inode(file); __u32 fsnotify_mask = 0; - if (file->f_mode & FMODE_NONOTIFY) - return 0; if (!(mask & (MAY_READ | MAY_OPEN))) return 0; + if (mask & MAY_OPEN) { fsnotify_mask = FS_OPEN_PERM; if (file->f_flags & __FMODE_EXEC) { - ret = fsnotify_path(inode, path, FS_OPEN_EXEC_PERM); + ret = fsnotify_file(file, FS_OPEN_EXEC_PERM); if (ret) return ret; @@ -79,10 +96,7 @@ static inline int fsnotify_perm(struct file *file, int mask) fsnotify_mask = FS_ACCESS_PERM; } - if (S_ISDIR(inode->i_mode)) - fsnotify_mask |= FS_ISDIR; - - return fsnotify_path(inode, path, fsnotify_mask); + return fsnotify_file(file, fsnotify_mask); } /* @@ -229,15 +243,7 @@ static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) */ static inline void fsnotify_access(struct file *file) { - const struct path *path = &file->f_path; - struct inode *inode = file_inode(file); - __u32 mask = FS_ACCESS; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) - fsnotify_path(inode, path, mask); + fsnotify_file(file, FS_ACCESS); } /* @@ -245,15 +251,7 @@ static inline void fsnotify_access(struct file *file) */ static inline void fsnotify_modify(struct file *file) { - const struct path *path = &file->f_path; - struct inode *inode = file_inode(file); - __u32 mask = FS_MODIFY; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) - fsnotify_path(inode, path, mask); + fsnotify_file(file, FS_MODIFY); } /* @@ -261,16 +259,12 @@ static inline void fsnotify_modify(struct file *file) */ static inline void fsnotify_open(struct file *file) { - const struct path *path = &file->f_path; - struct inode *inode = file_inode(file); __u32 mask = FS_OPEN; - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; if (file->f_flags & __FMODE_EXEC) mask |= FS_OPEN_EXEC; - fsnotify_path(inode, path, mask); + fsnotify_file(file, mask); } /* @@ -278,16 +272,10 @@ static inline void fsnotify_open(struct file *file) */ static inline void fsnotify_close(struct file *file) { - const struct path *path = &file->f_path; - struct inode *inode = file_inode(file); - fmode_t mode = file->f_mode; - __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; + __u32 mask = (file->f_mode & FMODE_WRITE) ? FS_CLOSE_WRITE : + FS_CLOSE_NOWRITE; - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) - fsnotify_path(inode, path, mask); + fsnotify_file(file, mask); } /* @@ -295,14 +283,7 @@ static inline void fsnotify_close(struct file *file) */ static inline void fsnotify_xattr(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; - __u32 mask = FS_ATTRIB; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - fsnotify_parent(NULL, dentry, mask); - fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); + fsnotify_dentry(dentry, FS_ATTRIB); } /* @@ -311,7 +292,6 @@ static inline void fsnotify_xattr(struct dentry *dentry) */ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) { - struct inode *inode = dentry->d_inode; __u32 mask = 0; if (ia_valid & ATTR_UID) @@ -332,13 +312,8 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) if (ia_valid & ATTR_MODE) mask |= FS_ATTRIB; - if (mask) { - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - fsnotify_parent(NULL, dentry, mask); - fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); - } + if (mask) + fsnotify_dentry(dentry, mask); } #endif /* _LINUX_FS_NOTIFY_H */ From a1aae0570a2b806937120921db2c5d3100ca55fc Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:11 +0200 Subject: [PATCH 472/809] fsnotify: funnel all dirent events through fsnotify_name() Factor out fsnotify_name() from fsnotify_dirent(), so it can also serve link and rename events and use this helper to report all directory entry change events. Both helpers return void because no caller checks their return value. Link: https://lore.kernel.org/r/20200319151022.31456-4-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify.h | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index f54936aa0365..751da17e003d 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -18,16 +18,24 @@ #include /* - * Notify this @dir inode about a change in the directory entry @dentry. + * Notify this @dir inode about a change in a child directory entry. + * The directory entry may have turned positive or negative or its inode may + * have changed (i.e. renamed over). * * Unlike fsnotify_parent(), the event will be reported regardless of the * FS_EVENT_ON_CHILD mask on the parent inode. */ -static inline int fsnotify_dirent(struct inode *dir, struct dentry *dentry, - __u32 mask) +static inline void fsnotify_name(struct inode *dir, __u32 mask, + struct inode *child, + const struct qstr *name, u32 cookie) { - return fsnotify(dir, mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, - &dentry->d_name, 0); + fsnotify(dir, mask, child, FSNOTIFY_EVENT_INODE, name, cookie); +} + +static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, + __u32 mask) +{ + fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0); } /* Notify this dentry's parent about a child's events. */ @@ -136,10 +144,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, mask |= FS_ISDIR; } - fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name, - fs_cookie); - fsnotify(new_dir, new_dir_mask, source, FSNOTIFY_EVENT_INODE, new_name, - fs_cookie); + fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie); + fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie); if (target) fsnotify_link_count(target); @@ -194,12 +200,13 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) * Note: We have to pass also the linked inode ptr as some filesystems leave * new_dentry->d_inode NULL and instantiate inode pointer later */ -static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) +static inline void fsnotify_link(struct inode *dir, struct inode *inode, + struct dentry *new_dentry) { fsnotify_link_count(inode); audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); - fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0); + fsnotify_name(dir, FS_CREATE, inode, &new_dentry->d_name, 0); } /* From aa93bdc5500cc93ba31afeda1a61610d117947ad Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:12 +0200 Subject: [PATCH 473/809] fsnotify: use helpers to access data by data_type Create helpers to access path and inode from different data types. Link: https://lore.kernel.org/r/20200319151022.31456-5-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 18 +++++++-------- fs/notify/fsnotify.c | 5 ++-- fs/notify/inotify/inotify_fsnotify.c | 8 +++---- include/linux/fsnotify_backend.h | 34 ++++++++++++++++++++++++---- kernel/audit_fsnotify.c | 13 ++--------- kernel/audit_watch.c | 16 ++----------- 6 files changed, 48 insertions(+), 46 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 5778d1347b35..19ec7a4f4d50 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -151,7 +151,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, { __u32 marks_mask = 0, marks_ignored_mask = 0; __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS; - const struct path *path = data; + const struct path *path = fsnotify_data_path(data, data_type); struct fsnotify_mark *mark; int type; @@ -160,7 +160,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, if (!FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { /* Do we have path to open a file descriptor? */ - if (data_type != FSNOTIFY_EVENT_PATH) + if (!path) return 0; /* Path type events are only relevant for files and dirs */ if (!d_is_reg(path->dentry) && !d_can_lookup(path->dentry)) @@ -269,11 +269,8 @@ static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask, { if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) return to_tell; - else if (data_type == FSNOTIFY_EVENT_INODE) - return (struct inode *)data; - else if (data_type == FSNOTIFY_EVENT_PATH) - return d_inode(((struct path *)data)->dentry); - return NULL; + + return (struct inode *)fsnotify_data_inode(data, data_type); } struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, @@ -284,6 +281,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, struct fanotify_event *event = NULL; gfp_t gfp = GFP_KERNEL_ACCOUNT; struct inode *id = fanotify_fid_inode(inode, mask, data, data_type); + const struct path *path = fsnotify_data_path(data, data_type); /* * For queues with unlimited length lost events are not expected and @@ -324,10 +322,10 @@ init: __maybe_unused if (id && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { /* Report the event without a file identifier on encode error */ event->fh_type = fanotify_encode_fid(event, id, gfp, fsid); - } else if (data_type == FSNOTIFY_EVENT_PATH) { + } else if (path) { event->fh_type = FILEID_ROOT; - event->path = *((struct path *)data); - path_get(&event->path); + event->path = *path; + path_get(path); } else { event->fh_type = FILEID_INVALID; event->path.mnt = NULL; diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 46f225580009..a5d6467f89a0 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -318,6 +318,7 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, const struct qstr *file_name, u32 cookie) { + const struct path *path = fsnotify_data_path(data, data_is); struct fsnotify_iter_info iter_info = {}; struct super_block *sb = to_tell->i_sb; struct mount *mnt = NULL; @@ -325,8 +326,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, int ret = 0; __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); - if (data_is == FSNOTIFY_EVENT_PATH) { - mnt = real_mount(((const struct path *)data)->mnt); + if (path) { + mnt = real_mount(path->mnt); mnt_or_sb_mask |= mnt->mnt_fsnotify_mask; } /* An event "on child" is not intended for a mount/sb mark */ diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index d510223d302c..6bb98522bbfd 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -61,6 +61,7 @@ int inotify_handle_event(struct fsnotify_group *group, const struct qstr *file_name, u32 cookie, struct fsnotify_iter_info *iter_info) { + const struct path *path = fsnotify_data_path(data, data_type); struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); struct inotify_inode_mark *i_mark; struct inotify_event_info *event; @@ -73,12 +74,9 @@ int inotify_handle_event(struct fsnotify_group *group, return 0; if ((inode_mark->mask & FS_EXCL_UNLINK) && - (data_type == FSNOTIFY_EVENT_PATH)) { - const struct path *path = data; + path && d_unlinked(path->dentry)) + return 0; - if (d_unlinked(path->dentry)) - return 0; - } if (file_name) { len = file_name->len; alloc_len += len + 1; diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index db3cabb4600e..5cc838db422a 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -212,10 +212,36 @@ struct fsnotify_group { }; }; -/* when calling fsnotify tell it if the data is a path or inode */ -#define FSNOTIFY_EVENT_NONE 0 -#define FSNOTIFY_EVENT_PATH 1 -#define FSNOTIFY_EVENT_INODE 2 +/* When calling fsnotify tell it if the data is a path or inode */ +enum fsnotify_data_type { + FSNOTIFY_EVENT_NONE, + FSNOTIFY_EVENT_PATH, + FSNOTIFY_EVENT_INODE, +}; + +static inline const struct inode *fsnotify_data_inode(const void *data, + int data_type) +{ + switch (data_type) { + case FSNOTIFY_EVENT_INODE: + return data; + case FSNOTIFY_EVENT_PATH: + return d_inode(((const struct path *)data)->dentry); + default: + return NULL; + } +} + +static inline const struct path *fsnotify_data_path(const void *data, + int data_type) +{ + switch (data_type) { + case FSNOTIFY_EVENT_PATH: + return data; + default: + return NULL; + } +} enum fsnotify_obj_type { FSNOTIFY_OBJ_TYPE_INODE, diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c index f0d243318452..3596448bfdab 100644 --- a/kernel/audit_fsnotify.c +++ b/kernel/audit_fsnotify.c @@ -160,23 +160,14 @@ static int audit_mark_handle_event(struct fsnotify_group *group, { struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); struct audit_fsnotify_mark *audit_mark; - const struct inode *inode = NULL; + const struct inode *inode = fsnotify_data_inode(data, data_type); audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark); BUG_ON(group != audit_fsnotify_group); - switch (data_type) { - case (FSNOTIFY_EVENT_PATH): - inode = ((const struct path *)data)->dentry->d_inode; - break; - case (FSNOTIFY_EVENT_INODE): - inode = (const struct inode *)data; - break; - default: - BUG(); + if (WARN_ON(!inode)) return 0; - } if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) { if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL)) diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 4508d5e0cf69..dcfbb44c6720 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -473,25 +473,13 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_iter_info *iter_info) { struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); - const struct inode *inode; + const struct inode *inode = fsnotify_data_inode(data, data_type); struct audit_parent *parent; parent = container_of(inode_mark, struct audit_parent, mark); BUG_ON(group != audit_watch_group); - - switch (data_type) { - case (FSNOTIFY_EVENT_PATH): - inode = d_backing_inode(((const struct path *)data)->dentry); - break; - case (FSNOTIFY_EVENT_INODE): - inode = (const struct inode *)data; - break; - default: - BUG(); - inode = NULL; - break; - } + WARN_ON(!inode); if (mask & (FS_CREATE|FS_MOVED_TO) && inode) audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0); From 017de65fe58f2b0ca428b5830609520ded5898b9 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:13 +0200 Subject: [PATCH 474/809] fsnotify: simplify arguments passing to fsnotify_parent() Instead of passing both dentry and path and having to figure out which one to use, pass data/data_type to simplify the code. Link: https://lore.kernel.org/r/20200319151022.31456-6-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fsnotify.c | 15 ++++----------- include/linux/fsnotify.h | 14 ++------------ include/linux/fsnotify_backend.h | 14 ++++++++------ 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index a5d6467f89a0..193530f57963 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -143,15 +143,13 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) } /* Notify this dentry's parent about a child's events. */ -int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask) +int fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, + int data_type) { struct dentry *parent; struct inode *p_inode; int ret = 0; - if (!dentry) - dentry = path->dentry; - if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) return 0; @@ -168,12 +166,7 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask mask |= FS_EVENT_ON_CHILD; take_dentry_name_snapshot(&name, dentry); - if (path) - ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, - &name.name, 0); - else - ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, - &name.name, 0); + ret = fsnotify(p_inode, mask, data, data_type, &name.name, 0); release_dentry_name_snapshot(&name); } @@ -181,7 +174,7 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask return ret; } -EXPORT_SYMBOL_GPL(__fsnotify_parent); +EXPORT_SYMBOL_GPL(fsnotify_parent); static int send_to_group(struct inode *to_tell, __u32 mask, const void *data, diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 751da17e003d..860018f3e545 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -38,16 +38,6 @@ static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0); } -/* Notify this dentry's parent about a child's events. */ -static inline int fsnotify_parent(const struct path *path, - struct dentry *dentry, __u32 mask) -{ - if (!dentry) - dentry = path->dentry; - - return __fsnotify_parent(path, dentry, mask); -} - /* * Simple wrappers to consolidate calls fsnotify_parent()/fsnotify() when * an event is on a file/dentry. @@ -59,7 +49,7 @@ static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) if (S_ISDIR(inode->i_mode)) mask |= FS_ISDIR; - fsnotify_parent(NULL, dentry, mask); + fsnotify_parent(dentry, mask, inode, FSNOTIFY_EVENT_INODE); fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); } @@ -75,7 +65,7 @@ static inline int fsnotify_file(struct file *file, __u32 mask) if (S_ISDIR(inode->i_mode)) mask |= FS_ISDIR; - ret = fsnotify_parent(path, NULL, mask); + ret = fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); if (ret) return ret; diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 5cc838db422a..337c87cf34d6 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -376,9 +376,10 @@ struct fsnotify_mark { /* called from the vfs helpers */ /* main fsnotify call to send events */ -extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, - const struct qstr *name, u32 cookie); -extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask); +extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, + int data_type, const struct qstr *name, u32 cookie); +extern int fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, + int data_type); extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void fsnotify_sb_delete(struct super_block *sb); @@ -533,13 +534,14 @@ static inline void fsnotify_init_event(struct fsnotify_event *event, #else -static inline int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, - const struct qstr *name, u32 cookie) +static inline int fsnotify(struct inode *to_tell, __u32 mask, const void *data, + int data_type, const struct qstr *name, u32 cookie) { return 0; } -static inline int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask) +static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, + const void *data, int data_type) { return 0; } From f9b2a4d6a5f18e0aaf715206a056565c56889d9f Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Wed, 6 Nov 2019 11:46:25 -0800 Subject: [PATCH 475/809] rtc: class: support hctosys from modular RTC drivers Due to distribution constraints it may not be possible to statically compile the required RTC driver into the kernel. Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled or not) by checking at the end of RTC device registration whether the time should be synced. Signed-off-by: Steve Muckle Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 3 -- drivers/rtc/Makefile | 1 - drivers/rtc/class.c | 61 ++++++++++++++++++++++++++++++++++++++ drivers/rtc/hctosys.c | 69 ------------------------------------------- 4 files changed, 61 insertions(+), 73 deletions(-) delete mode 100644 drivers/rtc/hctosys.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6c99156cbe57..417fc6ec9338 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -41,9 +41,6 @@ config RTC_HCTOSYS_DEVICE device should record time in UTC, since the kernel won't do timezone correction. - The driver for this RTC device must be loaded before late_initcall - functions run, so it must usually be statically linked. - This clock should be battery-backed, so that it reads the correct time when the system boots from a power-off state. Otherwise, your system will need an external clock source (like an NTP server). diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6c3e93aa36dc..8642d6f7560d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -6,7 +6,6 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += lib.o -obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 9458e6d6686a..8793b2b8cf9d 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -34,6 +34,62 @@ static void rtc_device_release(struct device *dev) #ifdef CONFIG_RTC_HCTOSYS_DEVICE /* Result of the last RTC to system clock attempt. */ int rtc_hctosys_ret = -ENODEV; + +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary + * whether it stores the most close value or the value with partial + * seconds truncated. However, it is important that we use it to store + * the truncated value. This is because otherwise it is necessary, + * in an rtc sync function, to read both xtime.tv_sec and + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read + * of >32bits is not possible. So storing the most close value would + * slow down the sync API. So here we have the truncated value and + * the best guess is to add 0.5s. + */ + +static int rtc_hctosys(void) +{ + int err = -ENODEV; + struct rtc_time tm; + struct timespec64 tv64 = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; + struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + + if (!rtc) { + pr_info("unable to open rtc device (%s)\n", + CONFIG_RTC_HCTOSYS_DEVICE); + goto err_open; + } + + err = rtc_read_time(rtc, &tm); + if (err) { + dev_err(rtc->dev.parent, + "hctosys: unable to read the hardware clock\n"); + goto err_read; + } + + tv64.tv_sec = rtc_tm_to_time64(&tm); + +#if BITS_PER_LONG == 32 + if (tv64.tv_sec > INT_MAX) { + err = -ERANGE; + goto err_read; + } +#endif + + err = do_settimeofday64(&tv64); + + dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n", + &tm, (long long)tv64.tv_sec); + +err_read: + rtc_class_close(rtc); + +err_open: + rtc_hctosys_ret = err; + + return err; +} #endif #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) @@ -375,6 +431,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) dev_info(rtc->dev.parent, "registered as %s\n", dev_name(&rtc->dev)); +#ifdef CONFIG_RTC_HCTOSYS_DEVICE + if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE)) + rtc_hctosys(); +#endif + return 0; } EXPORT_SYMBOL_GPL(__rtc_register_device); diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c deleted file mode 100644 index a74d0d890600..000000000000 --- a/drivers/rtc/hctosys.c +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * RTC subsystem, initialize system time on startup - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include - -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary - * whether it stores the most close value or the value with partial - * seconds truncated. However, it is important that we use it to store - * the truncated value. This is because otherwise it is necessary, - * in an rtc sync function, to read both xtime.tv_sec and - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read - * of >32bits is not possible. So storing the most close value would - * slow down the sync API. So here we have the truncated value and - * the best guess is to add 0.5s. - */ - -static int __init rtc_hctosys(void) -{ - int err = -ENODEV; - struct rtc_time tm; - struct timespec64 tv64 = { - .tv_nsec = NSEC_PER_SEC >> 1, - }; - struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - - if (!rtc) { - pr_info("unable to open rtc device (%s)\n", - CONFIG_RTC_HCTOSYS_DEVICE); - goto err_open; - } - - err = rtc_read_time(rtc, &tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: unable to read the hardware clock\n"); - goto err_read; - } - - tv64.tv_sec = rtc_tm_to_time64(&tm); - -#if BITS_PER_LONG == 32 - if (tv64.tv_sec > INT_MAX) { - err = -ERANGE; - goto err_read; - } -#endif - - err = do_settimeofday64(&tv64); - - dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n", - &tm, (long long)tv64.tv_sec); - -err_read: - rtc_class_close(rtc); - -err_open: - rtc_hctosys_ret = err; - - return err; -} - -late_initcall(rtc_hctosys); From 5840748520be19ea97ffdb80e5aa313c6ef60575 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 11 Mar 2020 19:23:16 +0100 Subject: [PATCH 476/809] rtc: jz4740: Add support for JZ4760 SoC The WENR feature (set a magic value to enable RTC registers read-write) first appeared on the JZ4760; the JZ4780 came much later. Since it would be dangerous to specify a newer SoC's compatible string as the fallback of an older SoC's compatible string, we add support for the "ingenic,jz4760-rtc" compatible string in the driver. This will permit to support the JZ4770 by having: compatible = "ingenic,jz4770-rtc", "ingenic,jz4760-rtc"; Instead of doing: compatible = "ingenic,jz4770-rtc", "ingenic,jz4780-rtc"; Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20200311182318.22154-1-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 18023e472cbc..d764cd525c9a 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -46,6 +46,7 @@ enum jz4740_rtc_type { ID_JZ4740, + ID_JZ4760, ID_JZ4780, }; @@ -106,7 +107,7 @@ static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, { int ret = 0; - if (rtc->type >= ID_JZ4780) + if (rtc->type >= ID_JZ4760) ret = jz4780_rtc_enable_write(rtc); if (ret == 0) ret = jz4740_rtc_wait_write_ready(rtc); @@ -298,6 +299,7 @@ static void jz4740_rtc_power_off(void) static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, + { .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 }, { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, {}, }; From 91b298f5dc95e632bd17e325fc32caad19d3f27d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 11 Mar 2020 19:23:17 +0100 Subject: [PATCH 477/809] rtc: jz4740: Rename vendor-specific DT properties These properties are never set anywhere within any of the upstream devicetree files, so I assume I'm not breaking the ABI with this change. Rename vendor-specific DT properties to have the 'ingenic,' prefix, which they should have had from the start. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20200311182318.22154-2-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index d764cd525c9a..e4c719085c31 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -374,13 +374,14 @@ static int jz4740_rtc_probe(struct platform_device *pdev) if (!pm_power_off) { /* Default: 60ms */ rtc->reset_pin_assert_time = 60; - of_property_read_u32(np, "reset-pin-assert-time-ms", + of_property_read_u32(np, + "ingenic,reset-pin-assert-time-ms", &rtc->reset_pin_assert_time); /* Default: 100ms */ rtc->min_wakeup_pin_assert_time = 100; of_property_read_u32(np, - "min-wakeup-pin-assert-time-ms", + "ingenic,min-wakeup-pin-assert-time-ms", &rtc->min_wakeup_pin_assert_time); dev_for_power_off = &pdev->dev; From f1cd223389f04bfb26bfe30b5ac2558733fee34f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 11 Mar 2020 19:23:18 +0100 Subject: [PATCH 478/809] dt-bindings: rtc: Convert and update jz4740-rtc doc to YAML Convert the jz4740-rtc doc to YAML, and update it to reflect the new changes in the driver: - More compatible strings are specified, with fallbacks if needed, - The vendor-specific properties are now properly prefixed with the 'ingenic,' prefix. Signed-off-by: Paul Cercueil Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200311182318.22154-3-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- .../bindings/rtc/ingenic,jz4740-rtc.txt | 37 --------- .../devicetree/bindings/rtc/ingenic,rtc.yaml | 83 +++++++++++++++++++ 2 files changed, 83 insertions(+), 37 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt create mode 100644 Documentation/devicetree/bindings/rtc/ingenic,rtc.yaml diff --git a/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt b/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt deleted file mode 100644 index 41c7ae18fd7b..000000000000 --- a/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt +++ /dev/null @@ -1,37 +0,0 @@ -JZ4740 and similar SoCs real-time clock driver - -Required properties: - -- compatible: One of: - - "ingenic,jz4740-rtc" - for use with the JZ4740 SoC - - "ingenic,jz4780-rtc" - for use with the JZ4780 SoC -- reg: Address range of rtc register set -- interrupts: IRQ number for the alarm interrupt -- clocks: phandle to the "rtc" clock -- clock-names: must be "rtc" - -Optional properties: -- system-power-controller: To use this component as the - system power controller -- reset-pin-assert-time-ms: Reset pin low-level assertion - time after wakeup (default 60ms; range 0-125ms if RTC clock - at 32 kHz) -- min-wakeup-pin-assert-time-ms: Minimum wakeup pin assertion - time (default 100ms; range 0-2s if RTC clock at 32 kHz) - -Example: - -rtc@10003000 { - compatible = "ingenic,jz4740-rtc"; - reg = <0x10003000 0x40>; - - interrupt-parent = <&intc>; - interrupts = <32>; - - clocks = <&rtc_clock>; - clock-names = "rtc"; - - system-power-controller; - reset-pin-assert-time-ms = <60>; - min-wakeup-pin-assert-time-ms = <100>; -}; diff --git a/Documentation/devicetree/bindings/rtc/ingenic,rtc.yaml b/Documentation/devicetree/bindings/rtc/ingenic,rtc.yaml new file mode 100644 index 000000000000..4206bf8a2469 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/ingenic,rtc.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/ingenic,rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ingenic SoCs Real-Time Clock DT bindings + +maintainers: + - Paul Cercueil + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + oneOf: + - enum: + - ingenic,jz4740-rtc + - ingenic,jz4760-rtc + - items: + - const: ingenic,jz4725b-rtc + - const: ingenic,jz4740-rtc + - items: + - enum: + - ingenic,jz4770-rtc + - ingenic,jz4780-rtc + - const: ingenic,jz4760-rtc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: rtc + + system-power-controller: + description: | + Indicates that the RTC is responsible for powering OFF + the system. + type: boolean + + ingenic,reset-pin-assert-time-ms: + minimum: 0 + maximum: 125 + default: 60 + description: | + Reset pin low-level assertion time after wakeup + (assuming RTC clock at 32 kHz) + + ingenic,min-wakeup-pin-assert-time-ms: + minimum: 0 + maximum: 2000 + default: 100 + description: | + Minimum wakeup pin assertion time + (assuming RTC clock at 32 kHz) + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +examples: + - | + #include + rtc_dev: rtc@10003000 { + compatible = "ingenic,jz4740-rtc"; + reg = <0x10003000 0x40>; + + interrupt-parent = <&intc>; + interrupts = <15>; + + clocks = <&cgu JZ4740_CLK_RTC>; + clock-names = "rtc"; + }; From dfc2d2594e4a79204a3967585245f00644b8f838 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:15 +0200 Subject: [PATCH 479/809] fsnotify: replace inode pointer with an object id The event inode field is used only for comparison in queue merges and cannot be dereferenced after handle_event(), because it does not hold a refcount on the inode. Replace it with an abstract id to do the same thing. Link: https://lore.kernel.org/r/20200319151022.31456-8-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 4 ++-- fs/notify/inotify/inotify_fsnotify.c | 4 ++-- fs/notify/inotify/inotify_user.c | 2 +- include/linux/fsnotify_backend.h | 7 +++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 19ec7a4f4d50..6a202aaf941f 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -26,7 +26,7 @@ static bool should_merge(struct fsnotify_event *old_fsn, old = FANOTIFY_E(old_fsn); new = FANOTIFY_E(new_fsn); - if (old_fsn->inode != new_fsn->inode || old->pid != new->pid || + if (old_fsn->objectid != new_fsn->objectid || old->pid != new->pid || old->fh_type != new->fh_type || old->fh_len != new->fh_len) return false; @@ -312,7 +312,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, if (!event) goto out; init: __maybe_unused - fsnotify_init_event(&event->fse, inode); + fsnotify_init_event(&event->fse, (unsigned long)inode); event->mask = mask; if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) event->pid = get_pid(task_pid(current)); diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 6bb98522bbfd..2ebc89047153 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -39,7 +39,7 @@ static bool event_compare(struct fsnotify_event *old_fsn, if (old->mask & FS_IN_IGNORED) return false; if ((old->mask == new->mask) && - (old_fsn->inode == new_fsn->inode) && + (old_fsn->objectid == new_fsn->objectid) && (old->name_len == new->name_len) && (!old->name_len || !strcmp(old->name, new->name))) return true; @@ -116,7 +116,7 @@ int inotify_handle_event(struct fsnotify_group *group, mask &= ~IN_ISDIR; fsn_event = &event->fse; - fsnotify_init_event(fsn_event, inode); + fsnotify_init_event(fsn_event, (unsigned long)inode); event->mask = mask; event->wd = i_mark->wd; event->sync_cookie = cookie; diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 107537a543fd..81ffc8629fc4 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -635,7 +635,7 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) return ERR_PTR(-ENOMEM); } group->overflow_event = &oevent->fse; - fsnotify_init_event(group->overflow_event, NULL); + fsnotify_init_event(group->overflow_event, 0); oevent->mask = FS_Q_OVERFLOW; oevent->wd = -1; oevent->sync_cookie = 0; diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 337c87cf34d6..c72cbea20ef7 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -132,8 +132,7 @@ struct fsnotify_ops { */ struct fsnotify_event { struct list_head list; - /* inode may ONLY be dereferenced during handle_event(). */ - struct inode *inode; /* either the inode the event happened to or its parent */ + unsigned long objectid; /* identifier for queue merges */ }; /* @@ -526,10 +525,10 @@ extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); static inline void fsnotify_init_event(struct fsnotify_event *event, - struct inode *inode) + unsigned long objectid) { INIT_LIST_HEAD(&event->list); - event->inode = inode; + event->objectid = objectid; } #else From f367a62a7cad2447d835a9f14fc63997a9137246 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:16 +0200 Subject: [PATCH 480/809] fanotify: merge duplicate events on parent and child With inotify, when a watch is set on a directory and on its child, an event on the child is reported twice, once with wd of the parent watch and once with wd of the child watch without the filename. With fanotify, when a watch is set on a directory and on its child, an event on the child is reported twice, but it has the exact same information - either an open file descriptor of the child or an encoded fid of the child. The reason that the two identical events are not merged is because the object id used for merging events in the queue is the child inode in one event and parent inode in the other. For events with path or dentry data, use the victim inode instead of the watched inode as the object id for event merging, so that the event reported on parent will be merged with the event reported on the child. Link: https://lore.kernel.org/r/20200319151022.31456-9-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 6a202aaf941f..97d34b958761 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -312,7 +312,12 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, if (!event) goto out; init: __maybe_unused - fsnotify_init_event(&event->fse, (unsigned long)inode); + /* + * Use the victim inode instead of the watching inode as the id for + * event queue, so event reported on parent is merged with event + * reported on child when both directory and child watches exist. + */ + fsnotify_init_event(&event->fse, (unsigned long)id); event->mask = mask; if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) event->pid = get_pid(task_pid(current)); From 55bf882c7f13dda8bbe624040c6d5b4fbb812d16 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:17 +0200 Subject: [PATCH 481/809] fanotify: fix merging marks masks with FAN_ONDIR Change the logic of FAN_ONDIR in two ways that are similar to the logic of FAN_EVENT_ON_CHILD, that was fixed in commit 54a307ba8d3c ("fanotify: fix logic of events on child"): 1. The flag is meaningless in ignore mask 2. The flag refers only to events in the mask of the mark where it is set This is what the fanotify_mark.2 man page says about FAN_ONDIR: "Without this flag, only events for files are created." It doesn't say anything about setting this flag in ignore mask to stop getting events on directories nor can I think of any setup where this capability would be useful. Currently, when marks masks are merged, the FAN_ONDIR flag set in one mark affects the events that are set in another mark's mask and this behavior causes unexpected results. For example, a user adds a mark on a directory with mask FAN_ATTRIB | FAN_ONDIR and a mount mark with mask FAN_OPEN (without FAN_ONDIR). An opendir() of that directory (which is inside that mount) generates a FAN_OPEN event even though neither of the marks requested to get open events on directories. Link: https://lore.kernel.org/r/20200319151022.31456-10-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 97d34b958761..960f4f4d9e8f 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -171,6 +171,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, if (!fsnotify_iter_should_report_type(iter_info, type)) continue; mark = iter_info->marks[type]; + /* + * If the event is on dir and this mark doesn't care about + * events on dir, don't send it! + */ + if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) + continue; + /* * If the event is for a child and this mark doesn't care about * events on a child, don't send it! @@ -203,10 +210,6 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, user_mask &= ~FAN_ONDIR; } - if (event_mask & FS_ISDIR && - !(marks_mask & FS_ISDIR & ~marks_ignored_mask)) - return 0; - return test_mask & user_mask; } From 7b0a0dcb64705d1dbed46d33c9810251667469b9 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 27 Feb 2020 12:39:38 +0800 Subject: [PATCH 482/809] perf report: Support interactive annotation of code without symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For perf report on stripped binaries it is currently impossible to do annotation. The annotation state is all tied to symbols, but there are either no symbols, or symbols are not covering all the code. We should support the annotation functionality even without symbols. This patch fakes a symbol and the symbol name is the string of address. After that, we just follow current annotation working flow. For example, 1. perf report Overhead Command Shared Object Symbol 20.67% div libc-2.27.so [.] __random_r 17.29% div libc-2.27.so [.] __random 10.59% div div [.] 0x0000000000000628 9.25% div div [.] 0x0000000000000612 6.11% div div [.] 0x0000000000000645 2. Select the line of "10.59% div div [.] 0x0000000000000628" and ENTER. Annotate 0x0000000000000628 Zoom into div thread Zoom into div DSO (use the 'k' hotkey to zoom directly into the kernel) Browse map details Run scripts for samples of symbol [0x0000000000000628] Run scripts for all samples Switch to another data file in PWD Exit 3. Select the "Annotate 0x0000000000000628" and ENTER. Percent│ │ │ │ Disassembly of section .text: │ │ 0000000000000628 <.text+0x68>: │ divsd %xmm4,%xmm0 │ divsd %xmm3,%xmm1 │ movsd (%rsp),%xmm2 │ addsd %xmm1,%xmm0 │ addsd %xmm2,%xmm0 │ movsd %xmm0,(%rsp) Now we can see the dump of object starting from 0x628. v5: --- Remove the hotkey 'a' implementation from this patch. It will be moved to a separate patch. v4: --- 1. Support the hotkey 'a'. When we press 'a' on address, now it supports the annotation. 2. Change the patch title from "Support interactive annotation of code without symbols" to "perf report: Support interactive annotation of code without symbols" v3: --- Keep just the ANNOTATION_DUMMY_LEN, and remove the opts->annotate_dummy_len since it's the "maybe in future we will provide" feature. v2: --- Fix a crash issue when annotating an address in "unknown" object. The steps to reproduce this issue: perf record -e cycles:u ls perf report 75.29% ls ld-2.27.so [.] do_lookup_x 23.64% ls ld-2.27.so [.] __GI___tunables_init 1.04% ls [unknown] [k] 0xffffffff85c01210 0.03% ls ld-2.27.so [.] _start When annotating 0xffffffff85c01210, the crash happens. v2 adds checking for ms->map in add_annotate_opt(). If the object is "unknown", ms->map is NULL. Committer notes: Renamed new_annotate_sym() to symbol__new_unresolved(). Use PRIx64 to fix this issue in some 32-bit arches: ui/browsers/hists.c: In function 'symbol__new_unresolved': ui/browsers/hists.c:2474:38: error: format '%lx' expects argument of type 'long unsigned int', but argument 5 has type 'u64' {aka 'long long unsigned int'} [-Werror=format=] snprintf(name, sizeof(name), "%-#.*lx", BITS_PER_LONG / 4, addr); ~~~~~~^ ~~~~ %-#.*llx Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Tested-by: Ravi Bangoria Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200227043939.4403-3-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 43 +++++++++++++++++++++++++++++----- tools/perf/util/annotate.h | 1 + 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index f36dee499320..d0f9745856fd 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2465,13 +2465,41 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) return 0; } +static struct symbol *symbol__new_unresolved(u64 addr, struct map *map) +{ + struct annotated_source *src; + struct symbol *sym; + char name[64]; + + snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr); + + sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name); + if (sym) { + src = symbol__hists(sym, 1); + if (!src) { + symbol__delete(sym); + return NULL; + } + + dso__insert_symbol(map->dso, sym); + } + + return sym; +} + static int add_annotate_opt(struct hist_browser *browser __maybe_unused, struct popup_action *act, char **optstr, - struct map_symbol *ms) + struct map_symbol *ms, + u64 addr) { - if (ms->sym == NULL || ms->map->dso->annotate_warned || - symbol__annotation(ms->sym)->src == NULL) + if (!ms->map || !ms->map->dso || ms->map->dso->annotate_warned) + return 0; + + if (!ms->sym) + ms->sym = symbol__new_unresolved(addr, ms->map); + + if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL) return 0; if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0) @@ -3219,17 +3247,20 @@ do_hotkey: // key came straight from options ui__popup_menu() nr_options += add_annotate_opt(browser, &actions[nr_options], &options[nr_options], - &bi->from.ms); + &bi->from.ms, + bi->from.al_addr); if (bi->to.ms.sym != bi->from.ms.sym) nr_options += add_annotate_opt(browser, &actions[nr_options], &options[nr_options], - &bi->to.ms); + &bi->to.ms, + bi->to.al_addr); } else { nr_options += add_annotate_opt(browser, &actions[nr_options], &options[nr_options], - browser->selection); + browser->selection, + browser->he_selection->ip); } skip_annotation: nr_options += add_thread_opt(browser, &actions[nr_options], diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 07c775938d46..2d88069d6428 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -74,6 +74,7 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); #define ANNOTATION__CYCLES_WIDTH 6 #define ANNOTATION__MINMAX_CYCLES_WIDTH 19 #define ANNOTATION__AVG_IPC_WIDTH 36 +#define ANNOTATION_DUMMY_LEN 256 struct annotation_options { bool hide_src_code, From ec0479a63b7657e57665a9fc81d11a99131cfc62 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 27 Feb 2020 12:39:39 +0800 Subject: [PATCH 483/809] perf report/top TUI: Support hotkey 'a' for annotation of unresolved addresses In previous patch, we have supported the annotation functionality even without symbols. For this patch, it supports the hotkey 'a' on address in report view. Note that, for branch mode, we only support the annotation for "branch to" address. Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200227043939.4403-4-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 48 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d0f9745856fd..1103a019d83f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3061,21 +3061,45 @@ do_hotkey: // key came straight from options ui__popup_menu() continue; } - if (browser->selection == NULL || - browser->selection->sym == NULL || - browser->selection->map->dso->annotate_warned) - continue; - - if (symbol__annotation(browser->selection->sym)->src == NULL) { - ui_browser__warning(&browser->b, delay_secs * 2, - "No samples for the \"%s\" symbol.\n\n" - "Probably appeared just in a callchain", - browser->selection->sym->name); + if (!browser->selection || + !browser->selection->map || + !browser->selection->map->dso || + browser->selection->map->dso->annotate_warned) { continue; } - actions->ms.map = browser->selection->map; - actions->ms.sym = browser->selection->sym; + if (!browser->selection->sym) { + if (!browser->he_selection) + continue; + + if (sort__mode == SORT_MODE__BRANCH) { + bi = browser->he_selection->branch_info; + if (!bi || !bi->to.ms.map) + continue; + + actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map); + actions->ms.map = bi->to.ms.map; + } else { + actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip, + browser->selection->map); + actions->ms.map = browser->selection->map; + } + + if (!actions->ms.sym) + continue; + } else { + if (symbol__annotation(browser->selection->sym)->src == NULL) { + ui_browser__warning(&browser->b, delay_secs * 2, + "No samples for the \"%s\" symbol.\n\n" + "Probably appeared just in a callchain", + browser->selection->sym->name); + continue; + } + + actions->ms.map = browser->selection->map; + actions->ms.sym = browser->selection->sym; + } + do_annotate(browser, actions); continue; case 'P': From 429a5f9d89fc52256b2a59cd1277afbfafb739b3 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 20 Feb 2020 09:36:14 +0800 Subject: [PATCH 484/809] perf report: Allow specifying event to be used as sort key in --group output When performing "perf report --group", it shows the event group information together. By default, the output is sorted by the first event in group. It would be nice for user to select any event for sorting. This patch introduces a new option "--group-sort-idx" to sort the output by the event at the index n in event group. For example, Before: # perf report --group --stdio # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 12K of events 'cpu/instructions,period=2000003/, cpu/cpu-cycles,period=200003/, BR_MISP_RETIRED.ALL_BRANCHES:pp, cpu/event=0xc0,umask=1,cmask=1, # Event count (approx.): 6451235635 # # Overhead Command Shared Object Symbol # ................................ ......... ....................... ................................... # 92.19% 98.68% 0.00% 93.30% mgen mgen [.] LOOP1 3.12% 0.29% 0.00% 0.16% gsd-color libglib-2.0.so.0.5600.4 [.] 0x0000000000049515 1.56% 0.03% 0.00% 0.04% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494b7 1.56% 0.01% 0.00% 0.00% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494ce 1.56% 0.00% 0.00% 0.00% mgen [kernel.kallsyms] [k] task_tick_fair 0.00% 0.15% 0.00% 0.04% perf [kernel.kallsyms] [k] smp_call_function_single 0.00% 0.13% 0.00% 6.08% swapper [kernel.kallsyms] [k] intel_idle 0.00% 0.03% 0.00% 0.00% gsd-color libglib-2.0.so.0.5600.4 [.] g_main_context_check 0.00% 0.03% 0.00% 0.00% swapper [kernel.kallsyms] [k] apic_timer_interrupt ... After: # perf report --group --stdio --group-sort-idx 3 # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 12K of events 'cpu/instructions,period=2000003/, cpu/cpu-cycles,period=200003/, BR_MISP_RETIRED.ALL_BRANCHES:pp, cpu/event=0xc0,umask=1,cmask=1, # Event count (approx.): 6451235635 # # Overhead Command Shared Object Symbol # ................................ ......... ....................... ................................... # 92.19% 98.68% 0.00% 93.30% mgen mgen [.] LOOP1 0.00% 0.13% 0.00% 6.08% swapper [kernel.kallsyms] [k] intel_idle 3.12% 0.29% 0.00% 0.16% gsd-color libglib-2.0.so.0.5600.4 [.] 0x0000000000049515 0.00% 0.00% 0.00% 0.06% swapper [kernel.kallsyms] [k] hrtimer_start_range_ns 1.56% 0.03% 0.00% 0.04% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494b7 0.00% 0.15% 0.00% 0.04% perf [kernel.kallsyms] [k] smp_call_function_single 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] update_curr 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] apic_timer_interrupt 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] native_apic_msr_eoi_write 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] __update_load_avg_se 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] scheduler_tick Now the output is sorted by the fourth event in group. v7: --- Rebase to latest perf/core, no other change. v4: --- 1. Update Documentation/perf-report.txt to mention '--group-sort-idx' support multiple groups with different amount of events and it should be used on grouped events. 2. Update __hpp__group_sort_idx(), just return when the idx is out of limit. 3. Return failure on symbol_conf.group_sort_idx && !session->evlist->nr_groups. So now we don't need to use together with --group. v3: --- Refine the code in __hpp__group_sort_idx(). Before: for (i = 1; i < nr_members; i++) { if (i == idx) { ret = field_cmp(fields_a[i], fields_b[i]); if (ret) goto out; } } After: if (idx >= 1 && idx < nr_members) { ret = field_cmp(fields_a[idx], fields_b[idx]); if (ret) goto out; } Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200220013616.19916-2-yao.jin@linux.intel.com [ Renamed pair_fields_alloc() to hist_entry__new_pair() and combined decl + assignment of vars ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 5 ++ tools/perf/builtin-report.c | 10 +++ tools/perf/ui/hist.c | 93 ++++++++++++++++++++---- tools/perf/util/symbol_conf.h | 1 + 4 files changed, 94 insertions(+), 15 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index bd0a029d4c08..e56e3f1344a7 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -377,6 +377,11 @@ OPTIONS Show event group information together. It forces group output also if there are no groups defined in data file. +--group-sort-idx:: + Sort the output by the event at the index n in group. If n is invalid, + sort by the first event. It can support multiple groups with different + amount of events. WARNING: This should be used on grouped events. + --demangle:: Demangle symbol names to human readable form. It's enabled by default, disable with --no-demangle. diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5f4045df76f4..fa21c5ae3a51 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1227,6 +1227,10 @@ int cmd_report(int argc, const char **argv) "Show a column with the sum of periods"), OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set, "Show event group information together"), + OPT_INTEGER(0, "group-sort-idx", &symbol_conf.group_sort_idx, + "Sort the output by the event at the index n in group. " + "If n is invalid, sort by the first event. " + "WARNING: should be used on grouped events."), OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "", "use branch records for per branch histogram filling", parse_branch_mode), @@ -1369,6 +1373,12 @@ repeat: setup_forced_leader(&report, session->evlist); + if (symbol_conf.group_sort_idx && !session->evlist->nr_groups) { + parse_options_usage(NULL, options, "group-sort-idx", 0); + ret = -EINVAL; + goto error; + } + if (itrace_synth_opts.last_branch) has_br_stack = true; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index f73675500061..025f4c7f96bf 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -151,15 +151,90 @@ static int field_cmp(u64 field_a, u64 field_b) return 0; } +static int hist_entry__new_pair(struct hist_entry *a, struct hist_entry *b, + hpp_field_fn get_field, int nr_members, + u64 **fields_a, u64 **fields_b) +{ + u64 *fa = calloc(nr_members, sizeof(*fa)), + *fb = calloc(nr_members, sizeof(*fb)); + struct hist_entry *pair; + + if (!fa || !fb) + goto out_free; + + list_for_each_entry(pair, &a->pairs.head, pairs.node) { + struct evsel *evsel = hists_to_evsel(pair->hists); + fa[perf_evsel__group_idx(evsel)] = get_field(pair); + } + + list_for_each_entry(pair, &b->pairs.head, pairs.node) { + struct evsel *evsel = hists_to_evsel(pair->hists); + fb[perf_evsel__group_idx(evsel)] = get_field(pair); + } + + *fields_a = fa; + *fields_b = fb; + return 0; +out_free: + free(fa); + free(fb); + *fields_a = *fields_b = NULL; + return -1; +} + +static int __hpp__group_sort_idx(struct hist_entry *a, struct hist_entry *b, + hpp_field_fn get_field, int idx) +{ + struct evsel *evsel = hists_to_evsel(a->hists); + u64 *fields_a, *fields_b; + int cmp, nr_members, ret, i; + + cmp = field_cmp(get_field(a), get_field(b)); + if (!perf_evsel__is_group_event(evsel)) + return cmp; + + nr_members = evsel->core.nr_members; + if (idx < 1 || idx >= nr_members) + return cmp; + + ret = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b); + if (ret) { + ret = cmp; + goto out; + } + + ret = field_cmp(fields_a[idx], fields_b[idx]); + if (ret) + goto out; + + for (i = 1; i < nr_members; i++) { + if (i != idx) { + ret = field_cmp(fields_a[i], fields_b[i]); + if (ret) + goto out; + } + } + +out: + free(fields_a); + free(fields_b); + + return ret; +} + static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, hpp_field_fn get_field) { s64 ret; int i, nr_members; struct evsel *evsel; - struct hist_entry *pair; u64 *fields_a, *fields_b; + if (symbol_conf.group_sort_idx && symbol_conf.event_group) { + return __hpp__group_sort_idx(a, b, get_field, + symbol_conf.group_sort_idx); + } + ret = field_cmp(get_field(a), get_field(b)); if (ret || !symbol_conf.event_group) return ret; @@ -169,22 +244,10 @@ static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, return ret; nr_members = evsel->core.nr_members; - fields_a = calloc(nr_members, sizeof(*fields_a)); - fields_b = calloc(nr_members, sizeof(*fields_b)); - - if (!fields_a || !fields_b) + i = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b); + if (i) goto out; - list_for_each_entry(pair, &a->pairs.head, pairs.node) { - evsel = hists_to_evsel(pair->hists); - fields_a[perf_evsel__group_idx(evsel)] = get_field(pair); - } - - list_for_each_entry(pair, &b->pairs.head, pairs.node) { - evsel = hists_to_evsel(pair->hists); - fields_b[perf_evsel__group_idx(evsel)] = get_field(pair); - } - for (i = 1; i < nr_members; i++) { ret = field_cmp(fields_a[i], fields_b[i]); if (ret) diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index 10f1ec3e0349..b916afb95ec5 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -73,6 +73,7 @@ struct symbol_conf { const char *symfs; int res_sample; int pad_output_len_dso; + int group_sort_idx; }; extern struct symbol_conf symbol_conf; From 5e3b810aac49e960c80529e2c9aa8c101c5848ce Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 20 Feb 2020 09:36:15 +0800 Subject: [PATCH 485/809] perf report: Support a new key to reload the browser Sometimes we may need to reload the browser to update the output since some options are changed. This patch creates a new key K_RELOAD. Once the __cmd_report() returns K_RELOAD, it would repeat the whole process, such as, read samples from data file, sort the data and display in the browser. v5: --- 1. Fix the 'make NO_SLANG=1' error. Define K_RELOAD in util/hist.h. 2. Skip setup_sorting() in repeat path if last key is K_RELOAD. v4: --- Need to quit in perf_evsel_menu__run if key is K_RELOAD. Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200220013616.19916-3-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 6 +++--- tools/perf/ui/browsers/hists.c | 1 + tools/perf/ui/keysyms.h | 1 + tools/perf/util/hist.h | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fa21c5ae3a51..ea673b7eb3f4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -635,7 +635,7 @@ static int report__browse_hists(struct report *rep) * Usually "ret" is the last pressed key, and we only * care if the key notifies us to switch data file. */ - if (ret != K_SWITCH_INPUT_DATA) + if (ret != K_SWITCH_INPUT_DATA && ret != K_RELOAD) ret = 0; break; case 2: @@ -1480,7 +1480,7 @@ repeat: sort_order = sort_tmp; } - if ((last_key != K_SWITCH_INPUT_DATA) && + if ((last_key != K_SWITCH_INPUT_DATA && last_key != K_RELOAD) && (setup_sorting(session->evlist) < 0)) { if (sort_order) parse_options_usage(report_usage, options, "s", 1); @@ -1559,7 +1559,7 @@ repeat: sort__setup_elide(stdout); ret = __cmd_report(&report); - if (ret == K_SWITCH_INPUT_DATA) { + if (ret == K_SWITCH_INPUT_DATA || ret == K_RELOAD) { perf_session__delete(session); last_key = K_SWITCH_INPUT_DATA; goto repeat; diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 1103a019d83f..9f3401fd2cf6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3495,6 +3495,7 @@ browse_hists: pos = perf_evsel__prev(pos); goto browse_hists; case K_SWITCH_INPUT_DATA: + case K_RELOAD: case 'q': case CTRL('c'): goto out; diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h index fbfac29077f2..04cc4e5c031f 100644 --- a/tools/perf/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h @@ -25,5 +25,6 @@ #define K_ERROR -2 #define K_RESIZE -3 #define K_SWITCH_INPUT_DATA -4 +#define K_RELOAD -5 #endif /* _PERF_KEYSYMS_H_ */ diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0aa63aeb58ec..bb994e030495 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -536,6 +536,7 @@ static inline int block_hists_tui_browse(struct block_hist *bh __maybe_unused, #define K_LEFT -1000 #define K_RIGHT -2000 #define K_SWITCH_INPUT_DATA -3000 +#define K_RELOAD -4000 #endif unsigned int hists__sort_list_width(struct hists *hists); From dbddf17474411f5725fc76fc7e507410f0d4077f Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 20 Feb 2020 09:36:16 +0800 Subject: [PATCH 486/809] perf report/top TUI: Support hotkeys to let user select any event for sorting When performing "perf report --group", it shows the event group information together. In previous patch, we have supported a new option "--group-sort-idx" to sort the output by the event at the index n in event group. It would be nice if we can use a hotkey in browser to select a event to sort. For example, # perf report --group Samples: 12K of events 'cpu/instructions,period=2000003/, cpu/cpu-cycles,period=200003/, ... Overhead Command Shared Object Symbol 92.19% 98.68% 0.00% 93.30% mgen mgen [.] LOOP1 3.12% 0.29% 0.00% 0.16% gsd-color libglib-2.0.so.0.5600.4 [.] 0x0000000000049515 1.56% 0.03% 0.00% 0.04% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494b7 1.56% 0.01% 0.00% 0.00% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494ce 1.56% 0.00% 0.00% 0.00% mgen [kernel.kallsyms] [k] task_tick_fair 0.00% 0.15% 0.00% 0.04% perf [kernel.kallsyms] [k] smp_call_function_single 0.00% 0.13% 0.00% 6.08% swapper [kernel.kallsyms] [k] intel_idle 0.00% 0.03% 0.00% 0.00% gsd-color libglib-2.0.so.0.5600.4 [.] g_main_context_check 0.00% 0.03% 0.00% 0.00% swapper [kernel.kallsyms] [k] apic_timer_interrupt 0.00% 0.03% 0.00% 0.00% swapper [kernel.kallsyms] [k] check_preempt_curr When user press hotkey '3' (event index, starting from 0), it indicates to sort output by the forth event in group. Samples: 12K of events 'cpu/instructions,period=2000003/, cpu/cpu-cycles,period=200003/, ... Overhead Command Shared Object Symbol 92.19% 98.68% 0.00% 93.30% mgen mgen [.] LOOP1 0.00% 0.13% 0.00% 6.08% swapper [kernel.kallsyms] [k] intel_idle 3.12% 0.29% 0.00% 0.16% gsd-color libglib-2.0.so.0.5600.4 [.] 0x0000000000049515 0.00% 0.00% 0.00% 0.06% swapper [kernel.kallsyms] [k] hrtimer_start_range_ns 1.56% 0.03% 0.00% 0.04% gsd-color libglib-2.0.so.0.5600.4 [.] 0x00000000000494b7 0.00% 0.15% 0.00% 0.04% perf [kernel.kallsyms] [k] smp_call_function_single 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] update_curr 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] apic_timer_interrupt 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] native_apic_msr_eoi_write 0.00% 0.00% 0.00% 0.02% mgen [kernel.kallsyms] [k] __update_load_avg_se v6: --- Jiri provided a good improvement to eliminate unneeded refresh. This improvement is added to v6. v2: --- 1. Report warning at helpline when index is invalid. 2. Report warning at helpline when it's not group event. 3. Use "case '0' ... '9'" to refine the code 4. Split K_RELOAD implementation to another patch. Signed-off-by: Jin Yao Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200220013616.19916-4-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 9f3401fd2cf6..95ac5e2ea949 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2992,7 +2992,8 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, "s Switch to another data file in PWD\n" "t Zoom into current Thread\n" "V Verbose (DSO names in callchains, etc)\n" - "/ Filter symbol by name"; + "/ Filter symbol by name\n" + "0-9 Sort by event n in group"; static const char top_help[] = HIST_BROWSER_HELP_COMMON "P Print histograms to perf.hist.N\n" "t Zoom into current Thread\n" @@ -3053,6 +3054,31 @@ do_hotkey: // key came straight from options ui__popup_menu() * go to the next or previous */ goto out_free_stack; + case '0' ... '9': + if (!symbol_conf.event_group || + evsel->core.nr_members < 2) { + snprintf(buf, sizeof(buf), + "Sort by index only available with group events!"); + helpline = buf; + continue; + } + + if (key - '0' == symbol_conf.group_sort_idx) + continue; + + symbol_conf.group_sort_idx = key - '0'; + + if (symbol_conf.group_sort_idx >= evsel->core.nr_members) { + snprintf(buf, sizeof(buf), + "Max event group index to sort is %d (index from 0 to %d)", + evsel->core.nr_members - 1, + evsel->core.nr_members - 1); + helpline = buf; + continue; + } + + key = K_RELOAD; + goto out_free_stack; case 'a': if (!hists__has(hists, sym)) { ui_browser__warning(&browser->b, delay_secs * 2, From d13e9e413e5b470c4364bbbce559383081201811 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 18 Feb 2020 15:16:14 +0800 Subject: [PATCH 487/809] perf stat: Align the output for interval aggregation mode There is a slight misalignment in -A -I output. For example: # perf stat -e cpu/event=cpu-cycles/ -a -A -I 1000 # time CPU counts unit events 1.000440863 CPU0 1,068,388 cpu/event=cpu-cycles/ 1.000440863 CPU1 875,954 cpu/event=cpu-cycles/ 1.000440863 CPU2 3,072,538 cpu/event=cpu-cycles/ 1.000440863 CPU3 4,026,870 cpu/event=cpu-cycles/ 1.000440863 CPU4 5,919,630 cpu/event=cpu-cycles/ 1.000440863 CPU5 2,714,260 cpu/event=cpu-cycles/ 1.000440863 CPU6 2,219,240 cpu/event=cpu-cycles/ 1.000440863 CPU7 1,299,232 cpu/event=cpu-cycles/ The value of counts is not aligned with the column "counts" and the event name is not aligned with the column "events". With this patch, the output is, # perf stat -e cpu/event=cpu-cycles/ -a -A -I 1000 # time CPU counts unit events 1.000423009 CPU0 997,421 cpu/event=cpu-cycles/ 1.000423009 CPU1 1,422,042 cpu/event=cpu-cycles/ 1.000423009 CPU2 484,651 cpu/event=cpu-cycles/ 1.000423009 CPU3 525,791 cpu/event=cpu-cycles/ 1.000423009 CPU4 1,370,100 cpu/event=cpu-cycles/ 1.000423009 CPU5 442,072 cpu/event=cpu-cycles/ 1.000423009 CPU6 205,643 cpu/event=cpu-cycles/ 1.000423009 CPU7 1,302,250 cpu/event=cpu-cycles/ Now output is aligned. Signed-off-by: Jin Yao Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200218071614.25736-1-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/stat-display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 76c6052b12e2..9e757d18d713 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -115,11 +115,11 @@ static void aggr_printout(struct perf_stat_config *config, fprintf(config->output, "S%d-D%d-C%*d%s", cpu_map__id_to_socket(id), cpu_map__id_to_die(id), - config->csv_output ? 0 : -5, + config->csv_output ? 0 : -3, cpu_map__id_to_cpu(id), config->csv_sep); } else { - fprintf(config->output, "CPU%*d%s ", - config->csv_output ? 0 : -5, + fprintf(config->output, "CPU%*d%s", + config->csv_output ? 0 : -7, evsel__cpus(evsel)->map[id], config->csv_sep); } From 58fc90fda0cc983c11c5290c7a9e992b08ac4a5c Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Fri, 21 Feb 2020 15:41:21 +0530 Subject: [PATCH 488/809] perf metricgroup: Fix printing event names of metric group with multiple events incase of overlapping events Commit f01642e4912b ("perf metricgroup: Support multiple events for metricgroup") introduced support for multiple events in a metric group. But with the current upstream, metric events names are not printed properly incase we try to run multiple metric groups with overlapping event. With current upstream version, incase of overlapping metric events issue is, we always start our comparision logic from start. So, the events which already matched with some metric group also take part in comparision logic. Because of that when we have overlapping events, we end up matching current metric group event with already matched one. For example, in skylake machine we have metric event CoreIPC and Instructions. Both of them need 'inst_retired.any' event value. As events in Instructions is subset of events in CoreIPC, they endup in pointing to same 'inst_retired.any' value. In skylake platform: command:# ./perf stat -M CoreIPC,Instructions -C 0 sleep 1 Performance counter stats for 'CPU(s) 0': 1,254,992,790 inst_retired.any # 1254992790.0 Instructions # 1.3 CoreIPC 977,172,805 cycles 1,254,992,756 inst_retired.any 1.000802596 seconds time elapsed command:# sudo ./perf stat -M UPI,IPC sleep 1 Performance counter stats for 'sleep 1': 948,650 uops_retired.retire_slots 866,182 inst_retired.any # 0.7 IPC 866,182 inst_retired.any 1,175,671 cpu_clk_unhalted.thread Patch fixes the issue by adding a new bool pointer 'evlist_used' to keep track of events which already matched with some group by setting it true. So, we skip all used events in list when we start comparision logic. Patch also make some changes in comparision logic, incase we get a match miss, we discard the whole match and start again with first event id in metric event. With this patch: In skylake platform: command:# ./perf stat -M CoreIPC,Instructions -C 0 sleep 1 Performance counter stats for 'CPU(s) 0': 3,348,415 inst_retired.any # 0.3 CoreIPC 11,779,026 cycles 3,348,381 inst_retired.any # 3348381.0 Instructions 1.001649056 seconds time elapsed command:# ./perf stat -M UPI,IPC sleep 1 Performance counter stats for 'sleep 1': 1,023,148 uops_retired.retire_slots # 1.1 UPI 924,976 inst_retired.any 924,976 inst_retired.any # 0.6 IPC 1,489,414 cpu_clk_unhalted.thread 1.003064672 seconds time elapsed Signed-off-by: Kajol Jain Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anju T Sudhakar Cc: Jin Yao Cc: Kan Liang Cc: Madhavan Srinivasan Cc: Peter Zijlstra Cc: Ravi Bangoria Link: http://lore.kernel.org/lkml/20200221101121.28920-1-kjain@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/metricgroup.c | 47 +++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index c3a8c701609a..926449a7cdbf 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -95,13 +95,16 @@ struct egroup { static struct evsel *find_evsel_group(struct evlist *perf_evlist, const char **ids, int idnum, - struct evsel **metric_events) + struct evsel **metric_events, + bool *evlist_used) { struct evsel *ev; - int i = 0; + int i = 0, j = 0; bool leader_found; evlist__for_each_entry (perf_evlist, ev) { + if (evlist_used[j++]) + continue; if (!strcmp(ev->name, ids[i])) { if (!metric_events[i]) metric_events[i] = ev; @@ -109,22 +112,17 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, if (i == idnum) break; } else { - if (i + 1 == idnum) { - /* Discard the whole match and start again */ - i = 0; - memset(metric_events, 0, - sizeof(struct evsel *) * idnum); - continue; - } + /* Discard the whole match and start again */ + i = 0; + memset(metric_events, 0, + sizeof(struct evsel *) * idnum); - if (!strcmp(ev->name, ids[i])) - metric_events[i] = ev; - else { - /* Discard the whole match and start again */ - i = 0; - memset(metric_events, 0, - sizeof(struct evsel *) * idnum); - continue; + if (!strcmp(ev->name, ids[i])) { + if (!metric_events[i]) + metric_events[i] = ev; + i++; + if (i == idnum) + break; } } } @@ -146,7 +144,10 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, !strcmp(ev->name, metric_events[i]->name)) { ev->metric_leader = metric_events[i]; } + j++; } + ev = metric_events[i]; + evlist_used[ev->idx] = true; } return metric_events[0]; @@ -162,6 +163,13 @@ static int metricgroup__setup_events(struct list_head *groups, int ret = 0; struct egroup *eg; struct evsel *evsel; + bool *evlist_used; + + evlist_used = calloc(perf_evlist->core.nr_entries, sizeof(bool)); + if (!evlist_used) { + ret = -ENOMEM; + return ret; + } list_for_each_entry (eg, groups, nd) { struct evsel **metric_events; @@ -172,7 +180,7 @@ static int metricgroup__setup_events(struct list_head *groups, break; } evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum, - metric_events); + metric_events, evlist_used); if (!evsel) { pr_debug("Cannot resolve %s: %s\n", eg->metric_name, eg->metric_expr); @@ -196,6 +204,9 @@ static int metricgroup__setup_events(struct list_head *groups, expr->metric_events = metric_events; list_add(&expr->nd, &me->head); } + + free(evlist_used); + return ret; } From c5f18e9e94bad244115dc5e47f27bd061ecc5552 Mon Sep 17 00:00:00 2001 From: Vijay Thakkar Date: Wed, 18 Mar 2020 15:00:00 -0400 Subject: [PATCH 489/809] perf vendor events amd: Restrict model detection for zen1 based processors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes the previous blanket detection of AMD Family 17h processors to be more specific to Zen1 core based products only by replacing model detection regex pattern [[:xdigit:]]+ with ([12][0-9A-F]|[0-9A-F]), restricting to models 0 though 2f only. This change is required to allow for the addition of separate PMU events for Zen2 core based models in the following patches as those belong to family 17h but have different PMCs. Current PMU events directory has also been renamed to "amdzen1" from "amdfam17h" to reflect this specificity. Note that although this change does not break PMU counters for existing zen1 based systems, it does disable the current set of counters for zen2 based systems. Counters for zen2 have been added in the following patches in this patchset. Signed-off-by: Vijay Thakkar Acked-by: Kim Phillips Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Jon Grimm Cc: Martin Liška Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200318190002.307290-2-vijaythakkar@me.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/branch.json | 0 .../perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/cache.json | 0 tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/core.json | 0 .../arch/x86/{amdfam17h => amdzen1}/floating-point.json | 0 .../perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/memory.json | 0 .../perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/other.json | 0 tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/branch.json (100%) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/cache.json (100%) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/core.json (100%) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/floating-point.json (100%) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/memory.json (100%) rename tools/perf/pmu-events/arch/x86/{amdfam17h => amdzen1}/other.json (100%) diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/branch.json b/tools/perf/pmu-events/arch/x86/amdzen1/branch.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/branch.json rename to tools/perf/pmu-events/arch/x86/amdzen1/branch.json diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/cache.json b/tools/perf/pmu-events/arch/x86/amdzen1/cache.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/cache.json rename to tools/perf/pmu-events/arch/x86/amdzen1/cache.json diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/core.json b/tools/perf/pmu-events/arch/x86/amdzen1/core.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/core.json rename to tools/perf/pmu-events/arch/x86/amdzen1/core.json diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/floating-point.json rename to tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/memory.json b/tools/perf/pmu-events/arch/x86/amdzen1/memory.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/memory.json rename to tools/perf/pmu-events/arch/x86/amdzen1/memory.json diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/other.json b/tools/perf/pmu-events/arch/x86/amdzen1/other.json similarity index 100% rename from tools/perf/pmu-events/arch/x86/amdfam17h/other.json rename to tools/perf/pmu-events/arch/x86/amdzen1/other.json diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 745ced083844..82a9db00125e 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -36,4 +36,4 @@ GenuineIntel-6-55-[56789ABCDEF],v1,cascadelakex,core GenuineIntel-6-7D,v1,icelake,core GenuineIntel-6-7E,v1,icelake,core GenuineIntel-6-86,v1,tremontx,core -AuthenticAMD-23-[[:xdigit:]]+,v1,amdfam17h,core +AuthenticAMD-23-([12][0-9A-F]|[0-9A-F]),v1,amdzen1,core From 2079f7aa0a49d3ae83a82f70785a28b07bb9b16b Mon Sep 17 00:00:00 2001 From: Vijay Thakkar Date: Wed, 18 Mar 2020 15:00:01 -0400 Subject: [PATCH 490/809] perf vendor events amd: Add Zen2 events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds PMU events for AMD Zen2 core based processors, namely, Matisse (model 71h), Castle Peak (model 31h) and Rome (model 2xh), as documented in the AMD Processor Programming Reference for Matisse [1]. The model number regex has been set to detect all the models under family 17 that do not match those of Zen1, as the range is larger for zen2. Zen2 adds some additional counters that are not present in Zen1 and events for them have been added in this patch. Some counters have also been removed for Zen2 thatwere previously present in Zen1 and have been confirmed to always sample zero on zen2. These added/removed counters have been omitted for brevity but can be found here: https://gist.github.com/thakkarV/5b12ca5fd7488eb2c42e451e40bdd5f3 Note that PPR for Zen2 [1] does not include some counters that were documented in the PPR for Zen1 based processors [2]. After having tested these counters, some of them that still work for zen2 systems have been preserved in the events for zen2. The counters that are omitted in [1] but are still measurable and non-zero on zen2 (tested on a Ryzen 3900X system) are the following: PMC 0x000 fpu_pipe_assignment.{total|total0|total1|total2|total3} PMC 0x004 fp_num_mov_elim_scal_op.* PMC 0x046 ls_tablewalker.* PMC 0x062 l2_latency.l2_cycles_waiting_on_fills PMC 0x063 l2_wcb_req.* PMC 0x06D l2_fill_pending.l2_fill_busy PMC 0x080 ic_fw32 PMC 0x081 ic_fw32_miss PMC 0x086 bp_snp_re_sync PMC 0x087 ic_fetch_stall.* PMC 0x08C ic_cache_inval.* PMC 0x099 bp_tlb_rel PMC 0x0C7 ex_ret_brn_resync PMC 0x28A ic_oc_mode_switch.* L3PMC 0x001 l3_request_g1.* L3PMC 0x006 l3_comb_clstr_state.* [1]: Processor Programming Reference (PPR) for AMD Family 17h Model 71h, Revision B0 Processors, 56176 Rev 3.06 - Jul 17, 2019 [2]: Processor Programming Reference (PPR) for AMD Family 17h Models 01h,08h, Revision B2 Processors, 54945 Rev 3.03 - Jun 14, 2019 All of the PPRs can be found at: https://bugzilla.kernel.org/show_bug.cgi?id=206537 Here are the results of running "fpu_pipe_assignment.total" events on my Ryzen 3900X family 17h model 71h system: Before this patch: $> perf list *fpu_pipe_assignment* List of pre-defined events (to be used in -e): After: $> perf list *fpu_pipe_assignment* floating point: fpu_pipe_assignment.total [Total number of fp uOps] fpu_pipe_assignment.total0 [Total number uOps assigned to pipe 0] fpu_pipe_assignment.total1 [Total number uOps assigned to pipe 1] fpu_pipe_assignment.total2 [Total number uOps assigned to pipe 2] fpu_pipe_assignment.total3 [Total number uOps assigned to pipe 3] Metric Groups: $> perf stat -e fpu_pipe_assignment.total sleep 1 Performance counter stats for 'sleep 1': 25,883 fpu_pipe_assignment.total 1.004145868 seconds time elapsed 0.001805000 seconds user 0.000000000 seconds sys Usage tests while running Linpackin the background: $> perf stat -I1000 -e fpu_pipe_assignment.total 1.000266796 79,313,191,516 fpu_pipe_assignment.total 2.000809630 68,091,474,430 fpu_pipe_assignment.total 3.001028115 52,925,023,174 fpu_pipe_assignment.total $> perf record -e fpu_pipe_assignment.total,fpu_pipe_assignment.total0 -a sleep 1 [ perf record: Woken up 9 times to write data ] [ perf record: Captured and wrote 4.031 MB perf.data (64764 samples) ] $> perf report --stdio --no-header | head -30 98.33% xhpl xhpl [.] dgemm_kernel 0.28% xhpl xhpl [.] dtrsm_kernel_LT 0.10% xhpl [kernel.kallsyms] [k] entry_SYSCALL_64 0.08% xhpl xhpl [.] idamax_k 0.07% baloo_file_extr liblmdb.so [.] mdb_mid2l_insert 0.06% xhpl xhpl [.] dgemm_itcopy 0.06% xhpl xhpl [.] dgemm_oncopy 0.06% xhpl [kernel.kallsyms] [k] __schedule 0.06% xhpl [kernel.kallsyms] [k] syscall_trace_enter 0.06% xhpl [kernel.kallsyms] [k] native_sched_clock 0.06% xhpl [kernel.kallsyms] [k] pick_next_task_fair 0.05% xhpl xhpl [.] blas_thread_server.llvm.15009391670273914865 0.04% xhpl [kernel.kallsyms] [k] do_syscall_64 0.04% xhpl [kernel.kallsyms] [k] yield_task_fair 0.04% xhpl libpthread-2.31.so [.] __pthread_mutex_unlock_usercnt 0.03% xhpl [kernel.kallsyms] [k] cpuacct_charge 0.03% xhpl [kernel.kallsyms] [k] syscall_return_via_sysret 0.03% xhpl libc-2.31.so [.] __sched_yield 0.03% xhpl [kernel.kallsyms] [k] __calc_delta $> perf annotate --stdio2 dgemm_kernel | egrep '^ {0,2}[0-9]+' -B2 -A2 sub $0x60,%rsp mov %rbx,(%rsp) 0.00 mov %rbp,0x8(%rsp) mov %r12,0x10(%rsp) 0.00 mov %r13,0x18(%rsp) mov %r14,0x20(%rsp) mov %r15,0x28(%rsp) -- mov %rdi,%r13 mov %rsi,0x28(%rsp) 0.00 mov %rdx,%r12 vmovsd %xmm0,0x30(%rsp) shl $0x3,%r10 mov 0x28(%rsp),%rax 0.00 xor %rdx,%rdx mov $0x18,%rdi div %rdi -- nop a0: mov %r12,%rax 0.00 shl $0x3,%rax mov %r8,%rdi lea (%r8,%rax,8),%r15 -- mov %r12,%rax nop 0.00 c0: vmovups (%rdi),%ymm1 0.09 vmovups 0x20(%rdi),%ymm2 0.02 vmovups (%r15),%ymm3 0.10 vmovups %ymm1,(%rsi) 0.07 vmovups %ymm2,0x20(%rsi) 0.07 vmovups %ymm3,0x40(%rsi) 0.06 add $0x40,%rdi add $0x40,%r15 add $0x60,%rsi 0.00 dec %rax ↑ jne c0 mov %r9,%r15 -- nop 110: lea 0x80(%rsp),%rsi 0.01 add $0x60,%rsi 0.03 mov %r12,%rax 0.00 sar $0x3,%rax cmp $0x2,%rax ↓ jl d26 prefetcht0 0x200(%rdi) 0.01 vmovups -0x60(%rsi),%ymm1 0.02 prefetcht0 0xa0(%rsi) 0.00 vbroadcastsd -0x80(%rdi),%ymm0 0.00 prefetcht0 0xe0(%rsi) 0.03 vmovups -0x40(%rsi),%ymm2 0.00 prefetcht0 0x120(%rsi) vmovups -0x20(%rsi),%ymm3 vmulpd %ymm0,%ymm1,%ymm4 0.01 prefetcht0 0x160(%rsi) vmulpd %ymm0,%ymm2,%ymm8 0.01 vmulpd %ymm0,%ymm3,%ymm12 0.02 prefetcht0 0x1a0(%rsi) 0.01 vbroadcastsd -0x78(%rdi),%ymm0 vmulpd %ymm0,%ymm1,%ymm5 0.01 vmulpd %ymm0,%ymm2,%ymm9 vmulpd %ymm0,%ymm3,%ymm13 0.01 vbroadcastsd -0x70(%rdi),%ymm0 vmulpd %ymm0,%ymm1,%ymm6 0.00 vmulpd %ymm0,%ymm2,%ymm10 0.00 add $0x60,%rsi ... snip ... nop 65e0: vmovddup -0x60(%rsi),%xmm2 0.00 vmovups -0x80(%rdi),%xmm0 vmovups -0x70(%rdi),%xmm1 0.00 vmovddup -0x58(%rsi),%xmm3 vfmadd231pd %xmm0,%xmm2,%xmm4 0.00 vfmadd231pd %xmm1,%xmm2,%xmm5 0.00 vfmadd231pd %xmm0,%xmm3,%xmm6 0.00 vfmadd231pd %xmm1,%xmm3,%xmm7 0.00 add $0x10,%rsi add $0x20,%rdi 0.00 dec %rax ↑ jne 65e0 nop nop 6620: vmovddup 0x30(%rsp),%xmm0 0.00 vmulpd %xmm0,%xmm4,%xmm4 0.00 vmulpd %xmm0,%xmm5,%xmm5 vmulpd %xmm0,%xmm6,%xmm6 vmulpd %xmm0,%xmm7,%xmm7 vaddpd (%r15),%xmm4,%xmm4 vaddpd 0x10(%r15),%xmm5,%xmm5 0.00 vaddpd (%r15,%r10,1),%xmm6,%xmm6 0.00 vaddpd 0x10(%r15,%r10,1),%xmm7,%xmm7 0.00 vmovups %xmm4,(%r15) vmovups %xmm5,0x10(%r15) 0.00 vmovups %xmm6,(%r15,%r10,1) vmovups %xmm7,0x10(%r15,%r10,1) add $0x20,%r15 -- lea (%r8,%rax,8),%r8 69d8: mov 0x20(%rsp),%r14 0.00 test $0x1,%r14 ↓ je 6d84 mov %r9,%r15 -- vbroadcastsd -0x28(%rsi),%ymm3 vfmadd231pd (%rdi),%ymm0,%ymm4 0.00 vfmadd231pd 0x20(%rdi),%ymm1,%ymm5 vfmadd231pd 0x40(%rdi),%ymm2,%ymm6 vfmadd231pd 0x60(%rdi),%ymm3,%ymm7 -- vmulpd %ymm0,%ymm4,%ymm4 vaddpd (%r15),%ymm4,%ymm4 0.00 vmovups %ymm4,(%r15) add $0x20,%r15 dec %r11 -- mov %rbx,%rsp mov (%rsp),%rbx 0.01 mov 0x8(%rsp),%rbp mov 0x10(%rsp),%r12 mov 0x18(%rsp),%r13 Signed-off-by: Vijay Thakkar Tested-by: Arnaldo Carvalho de Melo Acked-by: Kim Phillips Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Jon Grimm Cc: Martin Liška Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200318190002.307290-3-vijaythakkar@me.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/amdzen2/branch.json | 52 +++ .../pmu-events/arch/x86/amdzen2/cache.json | 338 +++++++++++++++++ .../pmu-events/arch/x86/amdzen2/core.json | 130 +++++++ .../arch/x86/amdzen2/floating-point.json | 140 +++++++ .../pmu-events/arch/x86/amdzen2/memory.json | 341 ++++++++++++++++++ .../pmu-events/arch/x86/amdzen2/other.json | 115 ++++++ tools/perf/pmu-events/arch/x86/mapfile.csv | 1 + 7 files changed, 1117 insertions(+) create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/branch.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/cache.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/core.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/floating-point.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/memory.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen2/other.json diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/branch.json b/tools/perf/pmu-events/arch/x86/amdzen2/branch.json new file mode 100644 index 000000000000..ef4166a66288 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/branch.json @@ -0,0 +1,52 @@ +[ + { + "EventName": "bp_l1_btb_correct", + "EventCode": "0x8a", + "BriefDescription": "L1 Branch Prediction Overrides Existing Prediction (speculative)." + }, + { + "EventName": "bp_l2_btb_correct", + "EventCode": "0x8b", + "BriefDescription": "L2 Branch Prediction Overrides Existing Prediction (speculative)." + }, + { + "EventName": "bp_dyn_ind_pred", + "EventCode": "0x8e", + "BriefDescription": "Dynamic Indirect Predictions.", + "PublicDescription": "Indirect Branch Prediction for potential multi-target branch (speculative)." + }, + { + "EventName": "bp_de_redirect", + "EventCode": "0x91", + "BriefDescription": "Decoder Overrides Existing Branch Prediction (speculative)." + }, + { + "EventName": "bp_l1_tlb_fetch_hit", + "EventCode": "0x94", + "BriefDescription": "The number of instruction fetches that hit in the L1 ITLB.", + "UMask": "0xFF" + }, + { + "EventName": "bp_l1_tlb_fetch_hit.if1g", + "EventCode": "0x94", + "BriefDescription": "The number of instruction fetches that hit in the L1 ITLB. Instruction fetches to a 1GB page.", + "UMask": "0x4" + }, + { + "EventName": "bp_l1_tlb_fetch_hit.if2m", + "EventCode": "0x94", + "BriefDescription": "The number of instruction fetches that hit in the L1 ITLB. Instruction fetches to a 2MB page.", + "UMask": "0x2" + }, + { + "EventName": "bp_l1_tlb_fetch_hit.if4k", + "EventCode": "0x94", + "BriefDescription": "The number of instruction fetches that hit in the L1 ITLB. Instruction fetches to a 4KB page.", + "UMask": "0x1" + }, + { + "EventName": "bp_tlb_rel", + "EventCode": "0x99", + "BriefDescription": "The number of ITLB reload requests." + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/cache.json b/tools/perf/pmu-events/arch/x86/amdzen2/cache.json new file mode 100644 index 000000000000..1c60bfa0f00b --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/cache.json @@ -0,0 +1,338 @@ +[ + { + "EventName": "l2_request_g1.rd_blk_l", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache reads (including hardware and software prefetch).", + "UMask": "0x80" + }, + { + "EventName": "l2_request_g1.rd_blk_x", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache stores.", + "UMask": "0x40" + }, + { + "EventName": "l2_request_g1.ls_rd_blk_c_s", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache shared reads.", + "UMask": "0x20" + }, + { + "EventName": "l2_request_g1.cacheable_ic_read", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Instruction cache reads.", + "UMask": "0x10" + }, + { + "EventName": "l2_request_g1.change_to_x", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache state change requests. Request change to writable, check L2 for current state.", + "UMask": "0x8" + }, + { + "EventName": "l2_request_g1.prefetch_l2_cmd", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). PrefetchL2Cmd.", + "UMask": "0x4" + }, + { + "EventName": "l2_request_g1.l2_hw_pf", + "EventCode": "0x60", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). L2 Prefetcher. All prefetches accepted by L2 pipeline, hit or miss. Types of PF and L2 hit/miss broken out in a separate perfmon event.", + "UMask": "0x2" + }, + { + "EventName": "l2_request_g1.group2", + "EventCode": "0x60", + "BriefDescription": "Miscellaneous events covered in more detail by l2_request_g2 (PMCx061).", + "UMask": "0x1" + }, + { + "EventName": "l2_request_g2.group1", + "EventCode": "0x61", + "BriefDescription": "Miscellaneous events covered in more detail by l2_request_g1 (PMCx060).", + "UMask": "0x80" + }, + { + "EventName": "l2_request_g2.ls_rd_sized", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Data cache read sized.", + "UMask": "0x40" + }, + { + "EventName": "l2_request_g2.ls_rd_sized_nc", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Data cache read sized non-cacheable.", + "UMask": "0x20" + }, + { + "EventName": "l2_request_g2.ic_rd_sized", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Instruction cache read sized.", + "UMask": "0x10" + }, + { + "EventName": "l2_request_g2.ic_rd_sized_nc", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Instruction cache read sized non-cacheable.", + "UMask": "0x8" + }, + { + "EventName": "l2_request_g2.smc_inval", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Self-modifying code invalidates.", + "UMask": "0x4" + }, + { + "EventName": "l2_request_g2.bus_locks_originator", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Bus locks.", + "UMask": "0x2" + }, + { + "EventName": "l2_request_g2.bus_locks_responses", + "EventCode": "0x61", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Bus lock response.", + "UMask": "0x1" + }, + { + "EventName": "l2_latency.l2_cycles_waiting_on_fills", + "EventCode": "0x62", + "BriefDescription": "Total cycles spent waiting for L2 fills to complete from L3 or memory, divided by four. Event counts are for both threads. To calculate average latency, the number of fills from both threads must be used.", + "UMask": "0x1" + }, + { + "EventName": "l2_wcb_req.wcb_write", + "EventCode": "0x63", + "BriefDescription": "LS to L2 WCB write requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) write requests.", + "UMask": "0x40" + }, + { + "EventName": "l2_wcb_req.wcb_close", + "EventCode": "0x63", + "BriefDescription": "LS to L2 WCB close requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) close requests.", + "UMask": "0x20" + }, + { + "EventName": "l2_wcb_req.zero_byte_store", + "EventCode": "0x63", + "BriefDescription": "LS to L2 WCB zero byte store requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) zero byte store requests.", + "UMask": "0x4" + }, + { + "EventName": "l2_wcb_req.cl_zero", + "EventCode": "0x63", + "BriefDescription": "LS to L2 WCB cache line zeroing requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) cache line zeroing requests.", + "UMask": "0x1" + }, + { + "EventName": "l2_cache_req_stat.ls_rd_blk_cs", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache shared read hit in L2", + "UMask": "0x80" + }, + { + "EventName": "l2_cache_req_stat.ls_rd_blk_l_hit_x", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache read hit in L2.", + "UMask": "0x40" + }, + { + "EventName": "l2_cache_req_stat.ls_rd_blk_l_hit_s", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache read hit on shared line in L2.", + "UMask": "0x20" + }, + { + "EventName": "l2_cache_req_stat.ls_rd_blk_x", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache store or state change hit in L2.", + "UMask": "0x10" + }, + { + "EventName": "l2_cache_req_stat.ls_rd_blk_c", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache request miss in L2 (all types).", + "UMask": "0x8" + }, + { + "EventName": "l2_cache_req_stat.ic_fill_hit_x", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache hit modifiable line in L2.", + "UMask": "0x4" + }, + { + "EventName": "l2_cache_req_stat.ic_fill_hit_s", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache hit clean line in L2.", + "UMask": "0x2" + }, + { + "EventName": "l2_cache_req_stat.ic_fill_miss", + "EventCode": "0x64", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache request miss in L2.", + "UMask": "0x1" + }, + { + "EventName": "l2_fill_pending.l2_fill_busy", + "EventCode": "0x6d", + "BriefDescription": "Cycles with fill pending from L2. Total cycles spent with one or more fill requests in flight from L2.", + "UMask": "0x1" + }, + { + "EventName": "l2_pf_hit_l2", + "EventCode": "0x70", + "BriefDescription": "L2 prefetch hit in L2.", + "UMask": "0xff" + }, + { + "EventName": "l2_pf_miss_l2_hit_l3", + "EventCode": "0x71", + "BriefDescription": "L2 prefetcher hits in L3. Counts all L2 prefetches accepted by the L2 pipeline which miss the L2 cache and hit the L3.", + "UMask": "0xff" + }, + { + "EventName": "l2_pf_miss_l2_l3", + "EventCode": "0x72", + "BriefDescription": "L2 prefetcher misses in L3. All L2 prefetches accepted by the L2 pipeline which miss the L2 and the L3 caches.", + "UMask": "0xff" + }, + { + "EventName": "ic_fw32", + "EventCode": "0x80", + "BriefDescription": "The number of 32B fetch windows transferred from IC pipe to DE instruction decoder (includes non-cacheable and cacheable fill responses)." + }, + { + "EventName": "ic_fw32_miss", + "EventCode": "0x81", + "BriefDescription": "The number of 32B fetch windows tried to read the L1 IC and missed in the full tag." + }, + { + "EventName": "ic_cache_fill_l2", + "EventCode": "0x82", + "BriefDescription": "The number of 64 byte instruction cache line was fulfilled from the L2 cache." + }, + { + "EventName": "ic_cache_fill_sys", + "EventCode": "0x83", + "BriefDescription": "The number of 64 byte instruction cache line fulfilled from system memory or another cache." + }, + { + "EventName": "bp_l1_tlb_miss_l2_hit", + "EventCode": "0x84", + "BriefDescription": "The number of instruction fetches that miss in the L1 ITLB but hit in the L2 ITLB." + }, + { + "EventName": "bp_l1_tlb_miss_l2_tlb_miss", + "EventCode": "0x85", + "BriefDescription": "The number of instruction fetches that miss in both the L1 and L2 TLBs.", + "UMask": "0xff" + }, + { + "EventName": "bp_l1_tlb_miss_l2_tlb_miss.if1g", + "EventCode": "0x85", + "BriefDescription": "The number of instruction fetches that miss in both the L1 and L2 TLBs. Instruction fetches to a 1GB page.", + "UMask": "0x4" + }, + { + "EventName": "bp_l1_tlb_miss_l2_tlb_miss.if2m", + "EventCode": "0x85", + "BriefDescription": "The number of instruction fetches that miss in both the L1 and L2 TLBs. Instruction fetches to a 2MB page.", + "UMask": "0x2" + }, + { + "EventName": "bp_l1_tlb_miss_l2_tlb_miss.if4k", + "EventCode": "0x85", + "BriefDescription": "The number of instruction fetches that miss in both the L1 and L2 TLBs. Instruction fetches to a 4KB page.", + "UMask": "0x1" + }, + { + "EventName": "bp_snp_re_sync", + "EventCode": "0x86", + "BriefDescription": "The number of pipeline restarts caused by invalidating probes that hit on the instruction stream currently being executed. This would happen if the active instruction stream was being modified by another processor in an MP system - typically a highly unlikely event." + }, + { + "EventName": "ic_fetch_stall.ic_stall_any", + "EventCode": "0x87", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle for any reason (nothing valid in pipe ICM1).", + "UMask": "0x4" + }, + { + "EventName": "ic_fetch_stall.ic_stall_dq_empty", + "EventCode": "0x87", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to DQ empty.", + "UMask": "0x2" + }, + { + "EventName": "ic_fetch_stall.ic_stall_back_pressure", + "EventCode": "0x87", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to back-pressure.", + "UMask": "0x1" + }, + { + "EventName": "ic_cache_inval.l2_invalidating_probe", + "EventCode": "0x8c", + "BriefDescription": "IC line invalidated due to L2 invalidating probe (external or LS). The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core.", + "UMask": "0x2" + }, + { + "EventName": "ic_cache_inval.fill_invalidated", + "EventCode": "0x8c", + "BriefDescription": "IC line invalidated due to overwriting fill response. The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core.", + "UMask": "0x1" + }, + { + "EventName": "ic_oc_mode_switch.oc_ic_mode_switch", + "EventCode": "0x28a", + "BriefDescription": "OC Mode Switch. OC to IC mode switch.", + "UMask": "0x2" + }, + { + "EventName": "ic_oc_mode_switch.ic_oc_mode_switch", + "EventCode": "0x28a", + "BriefDescription": "OC Mode Switch. IC to OC mode switch.", + "UMask": "0x1" + }, + { + "EventName": "l3_request_g1.caching_l3_cache_accesses", + "EventCode": "0x01", + "BriefDescription": "Caching: L3 cache accesses", + "UMask": "0x80", + "Unit": "L3PMC" + }, + { + "EventName": "l3_lookup_state.all_l3_req_typs", + "EventCode": "0x04", + "BriefDescription": "All L3 Request Types", + "UMask": "0xff", + "Unit": "L3PMC" + }, + { + "EventName": "l3_comb_clstr_state.other_l3_miss_typs", + "EventCode": "0x06", + "BriefDescription": "Other L3 Miss Request Types", + "UMask": "0xfe", + "Unit": "L3PMC" + }, + { + "EventName": "l3_comb_clstr_state.request_miss", + "EventCode": "0x06", + "BriefDescription": "L3 cache misses", + "UMask": "0x01", + "Unit": "L3PMC" + }, + { + "EventName": "xi_sys_fill_latency", + "EventCode": "0x90", + "BriefDescription": "L3 Cache Miss Latency. Total cycles for all transactions divided by 16. Ignores SliceMask and ThreadMask.", + "UMask": "0x00", + "Unit": "L3PMC" + }, + { + "EventName": "xi_ccx_sdp_req1.all_l3_miss_req_typs", + "EventCode": "0x9A", + "BriefDescription": "All L3 Miss Request Types. Ignores SliceMask and ThreadMask.", + "UMask": "0x3f", + "Unit": "L3PMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/core.json b/tools/perf/pmu-events/arch/x86/amdzen2/core.json new file mode 100644 index 000000000000..de89e5a44ff1 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/core.json @@ -0,0 +1,130 @@ +[ + { + "EventName": "ex_ret_instr", + "EventCode": "0xc0", + "BriefDescription": "Retired Instructions." + }, + { + "EventName": "ex_ret_cops", + "EventCode": "0xc1", + "BriefDescription": "Retired Uops.", + "PublicDescription": "The number of micro-ops retired. This count includes all processor activity (instructions, exceptions, interrupts, microcode assists, etc.). The number of events logged per cycle can vary from 0 to 8." + }, + { + "EventName": "ex_ret_brn", + "EventCode": "0xc2", + "BriefDescription": "Retired Branch Instructions.", + "PublicDescription": "The number of branch instructions retired. This includes all types of architectural control flow changes, including exceptions and interrupts." + }, + { + "EventName": "ex_ret_brn_misp", + "EventCode": "0xc3", + "BriefDescription": "Retired Branch Instructions Mispredicted.", + "PublicDescription": "The number of branch instructions retired, of any type, that were not correctly predicted. This includes those for which prediction is not attempted (far control transfers, exceptions and interrupts)." + }, + { + "EventName": "ex_ret_brn_tkn", + "EventCode": "0xc4", + "BriefDescription": "Retired Taken Branch Instructions.", + "PublicDescription": "The number of taken branches that were retired. This includes all types of architectural control flow changes, including exceptions and interrupts." + }, + { + "EventName": "ex_ret_brn_tkn_misp", + "EventCode": "0xc5", + "BriefDescription": "Retired Taken Branch Instructions Mispredicted.", + "PublicDescription": "The number of retired taken branch instructions that were mispredicted." + }, + { + "EventName": "ex_ret_brn_far", + "EventCode": "0xc6", + "BriefDescription": "Retired Far Control Transfers.", + "PublicDescription": "The number of far control transfers retired including far call/jump/return, IRET, SYSCALL and SYSRET, plus exceptions and interrupts. Far control transfers are not subject to branch prediction." + }, + { + "EventName": "ex_ret_brn_resync", + "EventCode": "0xc7", + "BriefDescription": "Retired Branch Resyncs.", + "PublicDescription": "The number of resync branches. These reflect pipeline restarts due to certain microcode assists and events such as writes to the active instruction stream, among other things. Each occurrence reflects a restart penalty similar to a branch mispredict. This is relatively rare." + }, + { + "EventName": "ex_ret_near_ret", + "EventCode": "0xc8", + "BriefDescription": "Retired Near Returns.", + "PublicDescription": "The number of near return instructions (RET or RET Iw) retired." + }, + { + "EventName": "ex_ret_near_ret_mispred", + "EventCode": "0xc9", + "BriefDescription": "Retired Near Returns Mispredicted.", + "PublicDescription": "The number of near returns retired that were not correctly predicted by the return address predictor. Each such mispredict incurs the same penalty as a mispredicted conditional branch instruction." + }, + { + "EventName": "ex_ret_brn_ind_misp", + "EventCode": "0xca", + "BriefDescription": "Retired Indirect Branch Instructions Mispredicted." + }, + { + "EventName": "ex_ret_mmx_fp_instr.sse_instr", + "EventCode": "0xcb", + "BriefDescription": "SSE instructions (SSE, SSE2, SSE3, SSSE3, SSE4A, SSE41, SSE42, AVX).", + "PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. SSE instructions (SSE, SSE2, SSE3, SSSE3, SSE4A, SSE41, SSE42, AVX).", + "UMask": "0x4" + }, + { + "EventName": "ex_ret_mmx_fp_instr.mmx_instr", + "EventCode": "0xcb", + "BriefDescription": "MMX instructions.", + "PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. MMX instructions.", + "UMask": "0x2" + }, + { + "EventName": "ex_ret_mmx_fp_instr.x87_instr", + "EventCode": "0xcb", + "BriefDescription": "x87 instructions.", + "PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. x87 instructions.", + "UMask": "0x1" + }, + { + "EventName": "ex_ret_cond", + "EventCode": "0xd1", + "BriefDescription": "Retired Conditional Branch Instructions." + }, + { + "EventName": "ex_ret_cond_misp", + "EventCode": "0xd2", + "BriefDescription": "Retired Conditional Branch Instructions Mispredicted." + }, + { + "EventName": "ex_div_busy", + "EventCode": "0xd3", + "BriefDescription": "Div Cycles Busy count." + }, + { + "EventName": "ex_div_count", + "EventCode": "0xd4", + "BriefDescription": "Div Op Count." + }, + { + "EventName": "ex_tagged_ibs_ops.ibs_count_rollover", + "EventCode": "0x1cf", + "BriefDescription": "Tagged IBS Ops. Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.", + "UMask": "0x4" + }, + { + "EventName": "ex_tagged_ibs_ops.ibs_tagged_ops_ret", + "EventCode": "0x1cf", + "BriefDescription": "Tagged IBS Ops. Number of Ops tagged by IBS that retired.", + "UMask": "0x2" + }, + { + "EventName": "ex_tagged_ibs_ops.ibs_tagged_ops", + "EventCode": "0x1cf", + "BriefDescription": "Tagged IBS Ops. Number of Ops tagged by IBS.", + "UMask": "0x1" + }, + { + "EventName": "ex_ret_fus_brnch_inst", + "EventCode": "0x1d0", + "BriefDescription": "Retired Fused Instructions. The number of fuse-branch instructions retired per cycle. The number of events logged per cycle can vary from 0-8.", + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen2/floating-point.json new file mode 100644 index 000000000000..622a0c420e46 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/floating-point.json @@ -0,0 +1,140 @@ +[ + { + "EventName": "fpu_pipe_assignment.total", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps.", + "PublicDescription": "Total number of fp uOps. The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS.", + "UMask": "0xf" + }, + { + "EventName": "fpu_pipe_assignment.total3", + "EventCode": "0x00", + "BriefDescription": "Total number uOps assigned to pipe 3.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one-cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 3.", + "UMask": "0x8" + }, + { + "EventName": "fpu_pipe_assignment.total2", + "EventCode": "0x00", + "BriefDescription": "Total number uOps assigned to pipe 2.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 2.", + "UMask": "0x4" + }, + { + "EventName": "fpu_pipe_assignment.total1", + "EventCode": "0x00", + "BriefDescription": "Total number uOps assigned to pipe 1.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 1.", + "UMask": "0x2" + }, + { + "EventName": "fpu_pipe_assignment.total0", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps on pipe 0.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 0.", + "UMask": "0x1" + }, + { + "EventName": "fp_ret_sse_avx_ops.all", + "EventCode": "0x03", + "BriefDescription": "All FLOPS. This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.", + "UMask": "0xff" + }, + { + "EventName": "fp_ret_sse_avx_ops.mac_flops", + "EventCode": "0x03", + "BriefDescription": "Multiply-add FLOPS. Multiply-add counts as 2 FLOPS. This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.", + "PublicDescription": "", + "UMask": "0x8" + }, + { + "EventName": "fp_ret_sse_avx_ops.div_flops", + "EventCode": "0x03", + "BriefDescription": "Divide/square root FLOPS. This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.", + "UMask": "0x4" + }, + { + "EventName": "fp_ret_sse_avx_ops.mult_flops", + "EventCode": "0x03", + "BriefDescription": "Multiply FLOPS. This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.", + "UMask": "0x2" + }, + { + "EventName": "fp_ret_sse_avx_ops.add_sub_flops", + "EventCode": "0x03", + "BriefDescription": "Add/subtract FLOPS. This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.", + "UMask": "0x1" + }, + { + "EventName": "fp_num_mov_elim_scal_op.optimized", + "EventCode": "0x04", + "BriefDescription": "Number of Scalar Ops optimized. This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes.", + "UMask": "0x8" + }, + { + "EventName": "fp_num_mov_elim_scal_op.opt_potential", + "EventCode": "0x04", + "BriefDescription": "Number of Ops that are candidates for optimization (have Z-bit either set or pass). This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes.", + "UMask": "0x4" + }, + { + "EventName": "fp_num_mov_elim_scal_op.sse_mov_ops_elim", + "EventCode": "0x04", + "BriefDescription": "Number of SSE Move Ops eliminated. This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes.", + "UMask": "0x2" + }, + { + "EventName": "fp_num_mov_elim_scal_op.sse_mov_ops", + "EventCode": "0x04", + "BriefDescription": "Number of SSE Move Ops. This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes.", + "UMask": "0x1" + }, + { + "EventName": "fp_retired_ser_ops.sse_bot_ret", + "EventCode": "0x05", + "BriefDescription": "SSE bottom-executing uOps retired. The number of serializing Ops retired.", + "UMask": "0x8" + }, + { + "EventName": "fp_retired_ser_ops.sse_ctrl_ret", + "EventCode": "0x05", + "BriefDescription": "The number of serializing Ops retired. SSE control word mispredict traps due to mispredictions in RC, FTZ or DAZ, or changes in mask bits.", + "UMask": "0x4" + }, + { + "EventName": "fp_retired_ser_ops.x87_bot_ret", + "EventCode": "0x05", + "BriefDescription": "x87 bottom-executing uOps retired. The number of serializing Ops retired.", + "UMask": "0x2" + }, + { + "EventName": "fp_retired_ser_ops.x87_ctrl_ret", + "EventCode": "0x05", + "BriefDescription": "x87 control word mispredict traps due to mispredictions in RC or PC, or changes in mask bits. The number of serializing Ops retired.", + "UMask": "0x1" + }, + { + "EventName": "fp_disp_faults.ymm_spill_fault", + "EventCode": "0x0e", + "BriefDescription": "Floating Point Dispatch Faults. YMM spill fault.", + "UMask": "0x8" + }, + { + "EventName": "fp_disp_faults.ymm_fill_fault", + "EventCode": "0x0e", + "BriefDescription": "Floating Point Dispatch Faults. YMM fill fault.", + "UMask": "0x4" + }, + { + "EventName": "fp_disp_faults.xmm_fill_fault", + "EventCode": "0x0e", + "BriefDescription": "Floating Point Dispatch Faults. XMM fill fault.", + "UMask": "0x2" + }, + { + "EventName": "fp_disp_faults.x87_fill_fault", + "EventCode": "0x0e", + "BriefDescription": "Floating Point Dispatch Faults. x87 fill fault.", + "UMask": "0x1" + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/memory.json b/tools/perf/pmu-events/arch/x86/amdzen2/memory.json new file mode 100644 index 000000000000..715046b339cb --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/memory.json @@ -0,0 +1,341 @@ +[ + { + "EventName": "ls_bad_status2.stli_other", + "EventCode": "0x24", + "BriefDescription": "Non-forwardable conflict; used to reduce STLI's via software. All reasons. Store To Load Interlock (STLI) are loads that were unable to complete because of a possible match with an older store, and the older store could not do STLF for some reason.", + "PublicDescription" : "Store-to-load conflicts: A load was unable to complete due to a non-forwardable conflict with an older store. Most commonly, a load's address range partially but not completely overlaps with an uncompleted older store. Software can avoid this problem by using same-size and same-alignment loads and stores when accessing the same data. Vector/SIMD code is particularly susceptible to this problem; software should construct wide vector stores by manipulating vector elements in registers using shuffle/blend/swap instructions prior to storing to memory, instead of using narrow element-by-element stores.", + "UMask": "0x2" + }, + { + "EventName": "ls_locks.spec_lock_hi_spec", + "EventCode": "0x25", + "BriefDescription": "Retired lock instructions. High speculative cacheable lock speculation succeeded.", + "UMask": "0x8" + }, + { + "EventName": "ls_locks.spec_lock_lo_spec", + "EventCode": "0x25", + "BriefDescription": "Retired lock instructions. Low speculative cacheable lock speculation succeeded.", + "UMask": "0x4" + }, + { + "EventName": "ls_locks.non_spec_lock", + "EventCode": "0x25", + "BriefDescription": "Retired lock instructions. Non-speculative lock succeeded.", + "UMask": "0x2" + }, + { + "EventName": "ls_locks.bus_lock", + "EventCode": "0x25", + "BriefDescription": "Retired lock instructions. Bus lock when a locked operations crosses a cache boundary or is done on an uncacheable memory type. Comparable to legacy bus lock.", + "UMask": "0x1" + }, + { + "EventName": "ls_ret_cl_flush", + "EventCode": "0x26", + "BriefDescription": "Number of retired CLFLUSH instructions." + }, + { + "EventName": "ls_ret_cpuid", + "EventCode": "0x27", + "BriefDescription": "Number of retired CPUID instructions." + }, + { + "EventName": "ls_dispatch.ld_st_dispatch", + "EventCode": "0x29", + "BriefDescription": "Dispatch of a single op that performs a load from and store to the same memory address. Number of single ops that do load/store to an address.", + "UMask": "0x4" + }, + { + "EventName": "ls_dispatch.store_dispatch", + "EventCode": "0x29", + "BriefDescription": "Number of stores dispatched. Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", + "UMask": "0x2" + }, + { + "EventName": "ls_dispatch.ld_dispatch", + "EventCode": "0x29", + "BriefDescription": "Number of loads dispatched. Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", + "UMask": "0x1" + }, + { + "EventName": "ls_smi_rx", + "EventCode": "0x2B", + "BriefDescription": "Number of SMIs received." + }, + { + "EventName": "ls_int_taken", + "EventCode": "0x2C", + "BriefDescription": "Number of interrupts taken." + }, + { + "EventName": "ls_rdtsc", + "EventCode": "0x2D", + "BriefDescription": "Number of reads of the TSC (RDTSC instructions). The count is speculative." + }, + { + "EventName": "ls_stlf", + "EventCode": "0x35", + "BriefDescription": "Number of STLF hits." + }, + { + "EventName": "ls_st_commit_cancel2.st_commit_cancel_wcb_full", + "EventCode": "0x37", + "BriefDescription": "A non-cacheable store and the non-cacheable commit buffer is full." + }, + { + "EventName": "ls_dc_accesses", + "EventCode": "0x40", + "BriefDescription": "Number of accesses to the dcache for load/store references.", + "PublicDescription": "The number of accesses to the data cache for load and store references. This may include certain microcode scratchpad accesses, although these are generally rare. Each increment represents an eight-byte access, although the instruction may only be accessing a portion of that. This event is a speculative event." + }, + { + "EventName": "ls_mab_alloc.dc_prefetcher", + "EventCode": "0x41", + "BriefDescription": "LS MAB Allocates by Type. DC prefetcher.", + "UMask": "0x8" + }, + { + "EventName": "ls_mab_alloc.stores", + "EventCode": "0x41", + "BriefDescription": "LS MAB Allocates by Type. Stores.", + "UMask": "0x2" + }, + { + "EventName": "ls_mab_alloc.loads", + "EventCode": "0x41", + "BriefDescription": "LS MAB Allocates by Type. Loads.", + "UMask": "0x1" + }, + { + "EventName": "ls_refills_from_sys.ls_mabresp_rmt_dram", + "EventCode": "0x43", + "BriefDescription": "Demand Data Cache Fills by Data Source. DRAM or IO from different die.", + "UMask": "0x40" + }, + { + "EventName": "ls_refills_from_sys.ls_mabresp_rmt_cache", + "EventCode": "0x43", + "BriefDescription": "Demand Data Cache Fills by Data Source. Hit in cache; Remote CCX and the address's Home Node is on a different die.", + "UMask": "0x10" + }, + { + "EventName": "ls_refills_from_sys.ls_mabresp_lcl_dram", + "EventCode": "0x43", + "BriefDescription": "Demand Data Cache Fills by Data Source. DRAM or IO from this thread's die.", + "UMask": "0x8" + }, + { + "EventName": "ls_refills_from_sys.ls_mabresp_lcl_cache", + "EventCode": "0x43", + "BriefDescription": "Demand Data Cache Fills by Data Source. Hit in cache; local CCX (not Local L2), or Remote CCX and the address's Home Node is on this thread's die.", + "UMask": "0x2" + }, + { + "EventName": "ls_refills_from_sys.ls_mabresp_lcl_l2", + "EventCode": "0x43", + "BriefDescription": "Demand Data Cache Fills by Data Source. Local L2 hit.", + "UMask": "0x1" + }, + { + "EventName": "ls_l1_d_tlb_miss.all", + "EventCode": "0x45", + "BriefDescription": "All L1 DTLB Misses or Reloads.", + "UMask": "0xff" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_miss", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 1G page that miss in the L2 TLB.", + "UMask": "0x80" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_miss", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 2M page that miss in the L2 TLB.", + "UMask": "0x40" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_coalesced_page_miss", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload coalesced page miss.", + "UMask": "0x20" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_miss", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 4K page that miss the L2 TLB.", + "UMask": "0x10" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_hit", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 1G page that hit in the L2 TLB.", + "UMask": "0x8" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_hit", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 2M page that hit in the L2 TLB.", + "UMask": "0x4" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_coalesced_page_hit", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload hit a coalesced page.", + "UMask": "0x2" + }, + { + "EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_hit", + "EventCode": "0x45", + "BriefDescription": "L1 DTLB Miss. DTLB reload to a 4K page that hit in the L2 TLB.", + "UMask": "0x1" + }, + { + "EventName": "ls_tablewalker.iside", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks on I-side.", + "UMask": "0xc" + }, + { + "EventName": "ls_tablewalker.ic_type1", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks IC Type 1.", + "UMask": "0x8" + }, + { + "EventName": "ls_tablewalker.ic_type0", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks IC Type 0.", + "UMask": "0x4" + }, + { + "EventName": "ls_tablewalker.dside", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks on D-side.", + "UMask": "0x3" + }, + { + "EventName": "ls_tablewalker.dc_type1", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks DC Type 1.", + "UMask": "0x2" + }, + { + "EventName": "ls_tablewalker.dc_type0", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks DC Type 0.", + "UMask": "0x1" + }, + { + "EventName": "ls_misal_accesses", + "EventCode": "0x47", + "BriefDescription": "Misaligned loads." + }, + { + "EventName": "ls_pref_instr_disp", + "EventCode": "0x4b", + "BriefDescription": "Software Prefetch Instructions Dispatched (Speculative).", + "UMask": "0xff" + }, + { + "EventName": "ls_pref_instr_disp.prefetch_nta", + "EventCode": "0x4b", + "BriefDescription": "Software Prefetch Instructions Dispatched (Speculative). PrefetchNTA instruction. See docAPM3 PREFETCHlevel.", + "UMask": "0x4" + }, + { + "EventName": "ls_pref_instr_disp.prefetch_w", + "EventCode": "0x4b", + "BriefDescription": "Software Prefetch Instructions Dispatched (Speculative). See docAPM3 PREFETCHW.", + "UMask": "0x2" + }, + { + "EventName": "ls_pref_instr_disp.prefetch", + "EventCode": "0x4b", + "BriefDescription": "Software Prefetch Instructions Dispatched (Speculative). Prefetch_T0_T1_T2. PrefetchT0, T1 and T2 instructions. See docAPM3 PREFETCHlevel.", + "UMask": "0x1" + }, + { + "EventName": "ls_inef_sw_pref.mab_mch_cnt", + "EventCode": "0x52", + "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core. Software PREFETCH instruction saw a match on an already-allocated miss request buffer.", + "UMask": "0x2" + }, + { + "EventName": "ls_inef_sw_pref.data_pipe_sw_pf_dc_hit", + "EventCode": "0x52", + "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core. Software PREFETCH instruction saw a DC hit.", + "UMask": "0x1" + }, + { + "EventName": "ls_sw_pf_dc_fill.ls_mabresp_rmt_dram", + "EventCode": "0x59", + "BriefDescription": "Software Prefetch Data Cache Fills by Data Source. From DRAM (home node remote).", + "UMask": "0x40" + }, + { + "EventName": "ls_sw_pf_dc_fill.ls_mabresp_rmt_cache", + "EventCode": "0x59", + "BriefDescription": "Software Prefetch Data Cache Fills by Data Source. From another cache (home node remote).", + "UMask": "0x10" + }, + { + "EventName": "ls_sw_pf_dc_fill.ls_mabresp_lcl_dram", + "EventCode": "0x59", + "BriefDescription": "Software Prefetch Data Cache Fills by Data Source. DRAM or IO from this thread's die. From DRAM (home node local).", + "UMask": "0x8" + }, + { + "EventName": "ls_sw_pf_dc_fill.ls_mabresp_lcl_cache", + "EventCode": "0x59", + "BriefDescription": "Software Prefetch Data Cache Fills by Data Source. From another cache (home node local).", + "UMask": "0x2" + }, + { + "EventName": "ls_sw_pf_dc_fill.ls_mabresp_lcl_l2", + "EventCode": "0x59", + "BriefDescription": "Software Prefetch Data Cache Fills by Data Source. Local L2 hit.", + "UMask": "0x1" + }, + { + "EventName": "ls_hw_pf_dc_fill.ls_mabresp_rmt_dram", + "EventCode": "0x5A", + "BriefDescription": "Hardware Prefetch Data Cache Fills by Data Source. From DRAM (home node remote).", + "UMask": "0x40" + }, + { + "EventName": "ls_hw_pf_dc_fill.ls_mabresp_rmt_cache", + "EventCode": "0x5A", + "BriefDescription": "Hardware Prefetch Data Cache Fills by Data Source. From another cache (home node remote).", + "UMask": "0x10" + }, + { + "EventName": "ls_hw_pf_dc_fill.ls_mabresp_lcl_dram", + "EventCode": "0x5A", + "BriefDescription": "Hardware Prefetch Data Cache Fills by Data Source. From DRAM (home node local).", + "UMask": "0x8" + }, + { + "EventName": "ls_hw_pf_dc_fill.ls_mabresp_lcl_cache", + "EventCode": "0x5A", + "BriefDescription": "Hardware Prefetch Data Cache Fills by Data Source. From another cache (home node local).", + "UMask": "0x2" + }, + { + "EventName": "ls_hw_pf_dc_fill.ls_mabresp_lcl_l2", + "EventCode": "0x5A", + "BriefDescription": "Hardware Prefetch Data Cache Fills by Data Source. Local L2 hit.", + "UMask": "0x1" + }, + { + "EventName": "ls_not_halted_cyc", + "EventCode": "0x76", + "BriefDescription": "Cycles not in Halt." + }, + { + "EventName": "ls_tlb_flush", + "EventCode": "0x78", + "BriefDescription": "All TLB Flushes" + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen2/other.json b/tools/perf/pmu-events/arch/x86/amdzen2/other.json new file mode 100644 index 000000000000..e94994d4a60e --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen2/other.json @@ -0,0 +1,115 @@ +[ + { + "EventName": "de_dis_uop_queue_empty_di0", + "EventCode": "0xa9", + "BriefDescription": "Cycles where the Micro-Op Queue is empty." + }, + { + "EventName": "de_dis_uops_from_decoder", + "EventCode": "0xaa", + "BriefDescription": "Ops dispatched from either the decoders, OpCache or both.", + "UMask": "0xff" + }, + { + "EventName": "de_dis_uops_from_decoder.opcache_dispatched", + "EventCode": "0xaa", + "BriefDescription": "Count of dispatched Ops from OpCache.", + "UMask": "0x2" + }, + { + "EventName": "de_dis_uops_from_decoder.decoder_dispatched", + "EventCode": "0xaa", + "BriefDescription": "Count of dispatched Ops from Decoder.", + "UMask": "0x1" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.fp_misc_rsrc_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. FP Miscellaneous resource unavailable. Applies to the recovery of mispredicts with FP ops.", + "UMask": "0x80" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.fp_sch_rsrc_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. FP scheduler resource stall. Applies to ops that use the FP scheduler.", + "UMask": "0x40" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.fp_reg_file_rsrc_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Floating point register file resource stall. Applies to all FP ops that have a destination register.", + "UMask": "0x20" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.taken_branch_buffer_rsrc_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Taken branch buffer resource stall.", + "UMask": "0x10" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.int_sched_misc_token_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Integer Scheduler miscellaneous resource stall.", + "UMask": "0x8" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.store_queue_token_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Store queue resource stall. Applies to all ops with store semantics.", + "UMask": "0x4" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.load_queue_token_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Load queue resource stall. Applies to all ops with load semantics.", + "UMask": "0x2" + }, + { + "EventName": "de_dis_dispatch_token_stalls1.int_phy_reg_file_token_stall", + "EventCode": "0xae", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. Integer Physical Register File resource stall. Applies to all ops that have an integer destination register.", + "UMask": "0x1" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.sc_agu_dispatch_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. SC AGU dispatch stall.", + "UMask": "0x40" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.retire_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. RETIRE Tokens unavailable.", + "UMask": "0x20" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.agsq_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. AGSQ Tokens unavailable.", + "UMask": "0x10" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.alu_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALU tokens total unavailable.", + "UMask": "0x8" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.alsq3_0_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ3_0_TokenStall.", + "UMask": "0x4" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.alsq2_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 2 Tokens unavailable.", + "UMask": "0x2" + }, + { + "EventName": "de_dis_dispatch_token_stalls0.alsq1_token_stall", + "EventCode": "0xaf", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 1 Tokens unavailable.", + "UMask": "0x1" + } +] diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 82a9db00125e..244a36e37a3a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -37,3 +37,4 @@ GenuineIntel-6-7D,v1,icelake,core GenuineIntel-6-7E,v1,icelake,core GenuineIntel-6-86,v1,tremontx,core AuthenticAMD-23-([12][0-9A-F]|[0-9A-F]),v1,amdzen1,core +AuthenticAMD-23-[[:xdigit:]]+,v1,amdzen2,core From b5b8a7cf141acba6588d2a43cda0dd258299f902 Mon Sep 17 00:00:00 2001 From: Vijay Thakkar Date: Wed, 18 Mar 2020 15:00:02 -0400 Subject: [PATCH 491/809] perf vendor events amd: Update Zen1 events to V2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch updates the PMCs for AMD Zen1 core based processors (Family 17h; Models 0 through 2F) to be in accordance with PMCs as documented in the latest versions of the AMD Processor Programming Reference [1], [2] and [3]. Note that some events, such as FPU pipe assignment are missing in [1], and therefore [3] is included for full coverage of events. PMCs added: fpu_pipe_assignment.dual{0|1|2|3} fpu_pipe_assignment.total{0|1|2|3} ls_mab_alloc.dc_prefetcher ls_mab_alloc.stores ls_mab_alloc.loads bp_dyn_ind_pred bp_de_redirect PMC removed: ex_ret_cond_misp Cumulative counts, fpu_pipe_assignment.total and fpu_pipe_assignment.dual, existed in v1, but did expose port-level counters. ex_ret_cond_misp has been removed as it has been removed from the latest versions of the PPR, and when tested, always seems to sample zero as tested on a Ryzen 3400G system. [1]: Processor Programming Reference (PPR) for AMD Family 17h Models 01h,08h, Revision B2 Processors, 54945 Rev 3.03 - Jun 14, 2019. [2]: Processor Programming Reference (PPR) for AMD Family 17h Model 18h, Revision B1 Processors, 55570-B1 Rev 3.14 - Sep 26, 2019. [3]: OSRR for AMD Family 17h processors, Models 00h-2Fh, 56255 Rev 3.03 - July, 2018 All of the PPRs can be found at: https://bugzilla.kernel.org/show_bug.cgi?id=206537 Signed-off-by: Vijay Thakkar Acked-by: Kim Phillips Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Jon Grimm Cc: Martin Liška Cc: Namhyung Kim Cc: Peter Zijlstra Cc: vijay thakkar Link: http://lore.kernel.org/lkml/20200318190002.307290-4-vijaythakkar@me.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/amdzen1/branch.json | 11 ++ .../pmu-events/arch/x86/amdzen1/cache.json | 107 ++++++------------ .../pmu-events/arch/x86/amdzen1/core.json | 15 +-- .../arch/x86/amdzen1/floating-point.json | 64 ++++++++++- .../pmu-events/arch/x86/amdzen1/memory.json | 82 +++++++++----- .../pmu-events/arch/x86/amdzen1/other.json | 27 ++--- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 7 files changed, 172 insertions(+), 136 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/branch.json b/tools/perf/pmu-events/arch/x86/amdzen1/branch.json index 93ddfd8053ca..a9943eeb8d6b 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/branch.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/branch.json @@ -8,5 +8,16 @@ "EventName": "bp_l2_btb_correct", "EventCode": "0x8b", "BriefDescription": "L2 BTB Correction." + }, + { + "EventName": "bp_dyn_ind_pred", + "EventCode": "0x8e", + "BriefDescription": "Dynamic Indirect Predictions.", + "PublicDescription": "Indirect Branch Prediction for potential multi-target branch (speculative)." + }, + { + "EventName": "bp_de_redirect", + "EventCode": "0x91", + "BriefDescription": "Decoder Overrides Existing Branch Prediction (speculative)." } ] diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/cache.json b/tools/perf/pmu-events/arch/x86/amdzen1/cache.json index 6221a840fcea..404d4c569c01 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/cache.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/cache.json @@ -37,36 +37,31 @@ { "EventName": "ic_fetch_stall.ic_stall_any", "EventCode": "0x87", - "BriefDescription": "IC pipe was stalled during this clock cycle for any reason (nothing valid in pipe ICM1).", - "PublicDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle for any reason (nothing valid in pipe ICM1).", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle for any reason (nothing valid in pipe ICM1).", "UMask": "0x4" }, { "EventName": "ic_fetch_stall.ic_stall_dq_empty", "EventCode": "0x87", - "BriefDescription": "IC pipe was stalled during this clock cycle (including IC to OC fetches) due to DQ empty.", - "PublicDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to DQ empty.", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to DQ empty.", "UMask": "0x2" }, { "EventName": "ic_fetch_stall.ic_stall_back_pressure", "EventCode": "0x87", - "BriefDescription": "IC pipe was stalled during this clock cycle (including IC to OC fetches) due to back-pressure.", - "PublicDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to back-pressure.", + "BriefDescription": "Instruction Pipe Stall. IC pipe was stalled during this clock cycle (including IC to OC fetches) due to back-pressure.", "UMask": "0x1" }, { "EventName": "ic_cache_inval.l2_invalidating_probe", "EventCode": "0x8c", - "BriefDescription": "IC line invalidated due to L2 invalidating probe (external or LS).", - "PublicDescription": "The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core. IC line invalidated due to L2 invalidating probe (external or LS).", + "BriefDescription": "IC line invalidated due to L2 invalidating probe (external or LS). The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core.", "UMask": "0x2" }, { "EventName": "ic_cache_inval.fill_invalidated", "EventCode": "0x8c", - "BriefDescription": "IC line invalidated due to overwriting fill response.", - "PublicDescription": "The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core. IC line invalidated due to overwriting fill response.", + "BriefDescription": "IC line invalidated due to overwriting fill response. The number of instruction cache lines invalidated. A non-SMC event is CMC (cross modifying code), either from the other thread of the core or another core.", "UMask": "0x1" }, { @@ -77,211 +72,181 @@ { "EventName": "l2_request_g1.rd_blk_l", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache reads (including hardware and software prefetch).", "UMask": "0x80" }, { "EventName": "l2_request_g1.rd_blk_x", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache stores.", "UMask": "0x40" }, { "EventName": "l2_request_g1.ls_rd_blk_c_s", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache shared reads.", "UMask": "0x20" }, { "EventName": "l2_request_g1.cacheable_ic_read", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Instruction cache reads.", "UMask": "0x10" }, { "EventName": "l2_request_g1.change_to_x", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). Data cache state change requests. Request change to writable, check L2 for current state.", "UMask": "0x8" }, { - "EventName": "l2_request_g1.prefetch_l2", + "EventName": "l2_request_g1.prefetch_l2_cmd", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). PrefetchL2Cmd.", "UMask": "0x4" }, { "EventName": "l2_request_g1.l2_hw_pf", "EventCode": "0x60", - "BriefDescription": "Requests to L2 Group1.", - "PublicDescription": "Requests to L2 Group1.", + "BriefDescription": "All L2 Cache Requests (Breakdown 1 - Common). L2 Prefetcher. All prefetches accepted by L2 pipeline, hit or miss. Types of PF and L2 hit/miss broken out in a separate perfmon event.", "UMask": "0x2" }, { - "EventName": "l2_request_g1.other_requests", + "EventName": "l2_request_g1.group2", "EventCode": "0x60", - "BriefDescription": "Events covered by l2_request_g2.", - "PublicDescription": "Requests to L2 Group1. Events covered by l2_request_g2.", + "BriefDescription": "Miscellaneous events covered in more detail by l2_request_g2 (PMCx061).", "UMask": "0x1" }, { "EventName": "l2_request_g2.group1", "EventCode": "0x61", - "BriefDescription": "All Group 1 commands not in unit0.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous. All Group 1 commands not in unit0.", + "BriefDescription": "Miscellaneous events covered in more detail by l2_request_g1 (PMCx060).", "UMask": "0x80" }, { "EventName": "l2_request_g2.ls_rd_sized", "EventCode": "0x61", - "BriefDescription": "RdSized, RdSized32, RdSized64.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous. RdSized, RdSized32, RdSized64.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Data cache read sized.", "UMask": "0x40" }, { "EventName": "l2_request_g2.ls_rd_sized_nc", "EventCode": "0x61", - "BriefDescription": "RdSizedNC, RdSized32NC, RdSized64NC.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous. RdSizedNC, RdSized32NC, RdSized64NC.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Data cache read sized non-cacheable.", "UMask": "0x20" }, { "EventName": "l2_request_g2.ic_rd_sized", "EventCode": "0x61", - "BriefDescription": "Multi-events in that LS and IF requests can be received simultaneous.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Instruction cache read sized.", "UMask": "0x10" }, { "EventName": "l2_request_g2.ic_rd_sized_nc", "EventCode": "0x61", - "BriefDescription": "Multi-events in that LS and IF requests can be received simultaneous.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Instruction cache read sized non-cacheable.", "UMask": "0x8" }, { "EventName": "l2_request_g2.smc_inval", "EventCode": "0x61", - "BriefDescription": "Multi-events in that LS and IF requests can be received simultaneous.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Self-modifying code invalidates.", "UMask": "0x4" }, { "EventName": "l2_request_g2.bus_locks_originator", "EventCode": "0x61", - "BriefDescription": "Multi-events in that LS and IF requests can be received simultaneous.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Bus locks.", "UMask": "0x2" }, { "EventName": "l2_request_g2.bus_locks_responses", "EventCode": "0x61", - "BriefDescription": "Multi-events in that LS and IF requests can be received simultaneous.", - "PublicDescription": "Multi-events in that LS and IF requests can be received simultaneous.", + "BriefDescription": "All L2 Cache Requests (Breakdown 2 - Rare). Bus lock response.", "UMask": "0x1" }, { "EventName": "l2_latency.l2_cycles_waiting_on_fills", "EventCode": "0x62", "BriefDescription": "Total cycles spent waiting for L2 fills to complete from L3 or memory, divided by four. Event counts are for both threads. To calculate average latency, the number of fills from both threads must be used.", - "PublicDescription": "Total cycles spent waiting for L2 fills to complete from L3 or memory, divided by four. Event counts are for both threads. To calculate average latency, the number of fills from both threads must be used.", "UMask": "0x1" }, { "EventName": "l2_wcb_req.wcb_write", "EventCode": "0x63", - "PublicDescription": "LS (Load/Store unit) to L2 WCB (Write Combining Buffer) write requests.", - "BriefDescription": "LS to L2 WCB write requests.", + "BriefDescription": "LS to L2 WCB write requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) write requests.", "UMask": "0x40" }, { "EventName": "l2_wcb_req.wcb_close", "EventCode": "0x63", - "BriefDescription": "LS to L2 WCB close requests.", - "PublicDescription": "LS (Load/Store unit) to L2 WCB (Write Combining Buffer) close requests.", + "BriefDescription": "LS to L2 WCB close requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) close requests.", "UMask": "0x20" }, { "EventName": "l2_wcb_req.zero_byte_store", "EventCode": "0x63", - "BriefDescription": "LS to L2 WCB zero byte store requests.", - "PublicDescription": "LS (Load/Store unit) to L2 WCB (Write Combining Buffer) zero byte store requests.", + "BriefDescription": "LS to L2 WCB zero byte store requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) zero byte store requests.", "UMask": "0x4" }, { "EventName": "l2_wcb_req.cl_zero", "EventCode": "0x63", - "PublicDescription": "LS to L2 WCB cache line zeroing requests.", - "BriefDescription": "LS (Load/Store unit) to L2 WCB (Write Combining Buffer) cache line zeroing requests.", + "BriefDescription": "LS to L2 WCB cache line zeroing requests. LS (Load/Store unit) to L2 WCB (Write Combining Buffer) cache line zeroing requests.", "UMask": "0x1" }, { "EventName": "l2_cache_req_stat.ls_rd_blk_cs", "EventCode": "0x64", - "BriefDescription": "LS ReadBlock C/S Hit.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. LS ReadBlock C/S Hit.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache shared read hit in L2", "UMask": "0x80" }, { "EventName": "l2_cache_req_stat.ls_rd_blk_l_hit_x", "EventCode": "0x64", - "BriefDescription": "LS Read Block L Hit X.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. LS Read Block L Hit X.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache read hit in L2.", "UMask": "0x40" }, { "EventName": "l2_cache_req_stat.ls_rd_blk_l_hit_s", "EventCode": "0x64", - "BriefDescription": "LsRdBlkL Hit Shared.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. LsRdBlkL Hit Shared.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache read hit on shared line in L2.", "UMask": "0x20" }, { "EventName": "l2_cache_req_stat.ls_rd_blk_x", "EventCode": "0x64", - "BriefDescription": "LsRdBlkX/ChgToX Hit X. Count RdBlkX finding Shared as a Miss.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. LsRdBlkX/ChgToX Hit X. Count RdBlkX finding Shared as a Miss.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache store or state change hit in L2.", "UMask": "0x10" }, { "EventName": "l2_cache_req_stat.ls_rd_blk_c", "EventCode": "0x64", - "BriefDescription": "LS Read Block C S L X Change to X Miss.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. LS Read Block C S L X Change to X Miss.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Data cache request miss in L2 (all types).", "UMask": "0x8" }, { "EventName": "l2_cache_req_stat.ic_fill_hit_x", "EventCode": "0x64", - "BriefDescription": "IC Fill Hit Exclusive Stale.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. IC Fill Hit Exclusive Stale.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache hit modifiable line in L2.", "UMask": "0x4" }, { "EventName": "l2_cache_req_stat.ic_fill_hit_s", "EventCode": "0x64", - "BriefDescription": "IC Fill Hit Shared.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. IC Fill Hit Shared.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache hit clean line in L2.", "UMask": "0x2" }, { "EventName": "l2_cache_req_stat.ic_fill_miss", "EventCode": "0x64", - "BriefDescription": "IC Fill Miss.", - "PublicDescription": "This event does not count accesses to the L2 cache by the L2 prefetcher, but it does count accesses by the L1 prefetcher. IC Fill Miss.", + "BriefDescription": "Core to L2 cacheable request access status (not including L2 Prefetch). Instruction cache request miss in L2.", "UMask": "0x1" }, { "EventName": "l2_fill_pending.l2_fill_busy", "EventCode": "0x6d", - "BriefDescription": "Total cycles spent with one or more fill requests in flight from L2.", - "PublicDescription": "Total cycles spent with one or more fill requests in flight from L2.", + "BriefDescription": "Cycles with fill pending from L2. Total cycles spent with one or more fill requests in flight from L2.", "UMask": "0x1" }, { diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/core.json b/tools/perf/pmu-events/arch/x86/amdzen1/core.json index 1079544eeed5..7e1aa8273935 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/core.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/core.json @@ -62,7 +62,6 @@ "EventName": "ex_ret_brn_ind_misp", "EventCode": "0xca", "BriefDescription": "Retired Indirect Branch Instructions Mispredicted.", - "PublicDescription": "Retired Indirect Branch Instructions Mispredicted." }, { "EventName": "ex_ret_mmx_fp_instr.sse_instr", @@ -90,11 +89,6 @@ "EventCode": "0xd1", "BriefDescription": "Retired Conditional Branch Instructions." }, - { - "EventName": "ex_ret_cond_misp", - "EventCode": "0xd2", - "BriefDescription": "Retired Conditional Branch Instructions Mispredicted." - }, { "EventName": "ex_div_busy", "EventCode": "0xd3", @@ -108,22 +102,19 @@ { "EventName": "ex_tagged_ibs_ops.ibs_count_rollover", "EventCode": "0x1cf", - "BriefDescription": "Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.", - "PublicDescription": "Tagged IBS Ops. Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.", + "BriefDescription": "Tagged IBS Ops. Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.", "UMask": "0x4" }, { "EventName": "ex_tagged_ibs_ops.ibs_tagged_ops_ret", "EventCode": "0x1cf", - "BriefDescription": "Number of Ops tagged by IBS that retired.", - "PublicDescription": "Tagged IBS Ops. Number of Ops tagged by IBS that retired.", + "BriefDescription": "Tagged IBS Ops. Number of Ops tagged by IBS that retired.", "UMask": "0x2" }, { "EventName": "ex_tagged_ibs_ops.ibs_tagged_ops", "EventCode": "0x1cf", - "BriefDescription": "Number of Ops tagged by IBS.", - "PublicDescription": "Tagged IBS Ops. Number of Ops tagged by IBS.", + "BriefDescription": "Tagged IBS Ops. Number of Ops tagged by IBS.", "UMask": "0x1" }, { diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json index ea4711983d1d..a35542bd3b36 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/floating-point.json @@ -2,17 +2,73 @@ { "EventName": "fpu_pipe_assignment.dual", "EventCode": "0x00", - "BriefDescription": "Total number multi-pipe uOps.", - "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to Pipe 3.", + "BriefDescription": "Total number multi-pipe uOps assigned to all pipes.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to all pipes.", "UMask": "0xf0" }, + { + "EventName": "fpu_pipe_assignment.dual3", + "EventCode": "0x00", + "BriefDescription": "Total number multi-pipe uOps assigned to pipe 3.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to pipe 3.", + "UMask": "0x80" + }, + { + "EventName": "fpu_pipe_assignment.dual2", + "EventCode": "0x00", + "BriefDescription": "Total number multi-pipe uOps assigned to pipe 2.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to pipe 2.", + "UMask": "0x40" + }, + { + "EventName": "fpu_pipe_assignment.dual1", + "EventCode": "0x00", + "BriefDescription": "Total number multi-pipe uOps assigned to pipe 1.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to pipe 1.", + "UMask": "0x20" + }, + { + "EventName": "fpu_pipe_assignment.dual0", + "EventCode": "0x00", + "BriefDescription": "Total number multi-pipe uOps assigned to pipe 0.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to pipe 0.", + "UMask": "0x10" + }, { "EventName": "fpu_pipe_assignment.total", "EventCode": "0x00", - "BriefDescription": "Total number uOps.", - "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to Pipe 3.", + "BriefDescription": "Total number uOps assigned to all fpu pipes.", + "PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to all pipes.", "UMask": "0xf" }, + { + "EventName": "fpu_pipe_assignment.total3", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps on pipe 3.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one-cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 3.", + "UMask": "0x8" + }, + { + "EventName": "fpu_pipe_assignment.total2", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps on pipe 2.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 2.", + "UMask": "0x4" + }, + { + "EventName": "fpu_pipe_assignment.total1", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps on pipe 1.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 1.", + "UMask": "0x2" + }, + { + "EventName": "fpu_pipe_assignment.total0", + "EventCode": "0x00", + "BriefDescription": "Total number of fp uOps on pipe 0.", + "PublicDescription": "The number of operations (uOps) dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to pipe 0.", + "UMask": "0x1" + }, { "EventName": "fp_sched_empty", "EventCode": "0x01", diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/memory.json b/tools/perf/pmu-events/arch/x86/amdzen1/memory.json index fa2d60d4def0..b33a3c308019 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/memory.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/memory.json @@ -3,28 +3,24 @@ "EventName": "ls_locks.bus_lock", "EventCode": "0x25", "BriefDescription": "Bus lock when a locked operations crosses a cache boundary or is done on an uncacheable memory type.", - "PublicDescription": "Bus lock when a locked operations crosses a cache boundary or is done on an uncacheable memory type.", "UMask": "0x1" }, { "EventName": "ls_dispatch.ld_st_dispatch", "EventCode": "0x29", - "BriefDescription": "Load-op-Stores.", - "PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed. Load-op-Stores.", + "BriefDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed. Load-op-Stores.", "UMask": "0x4" }, { "EventName": "ls_dispatch.store_dispatch", "EventCode": "0x29", - "BriefDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", - "PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", + "BriefDescription": "Counts the number of stores dispatched to the LS unit. Unit Masks ADDed.", "UMask": "0x2" }, { "EventName": "ls_dispatch.ld_dispatch", "EventCode": "0x29", - "BriefDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", - "PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.", + "BriefDescription": "Counts the number of loads dispatched to the LS unit. Unit Masks ADDed.", "UMask": "0x1" }, { @@ -37,83 +33,114 @@ "EventCode": "0x40", "BriefDescription": "The number of accesses to the data cache for load and store references. This may include certain microcode scratchpad accesses, although these are generally rare. Each increment represents an eight-byte access, although the instruction may only be accessing a portion of that. This event is a speculative event." }, + { + "EventName": "ls_mab_alloc.dc_prefetcher", + "EventCode": "0x41", + "BriefDescription": "LS MAB allocates by type - DC prefetcher.", + "UMask": "0x8" + }, + { + "EventName": "ls_mab_alloc.stores", + "EventCode": "0x41", + "BriefDescription": "LS MAB allocates by type - stores.", + "UMask": "0x2" + }, + { + "EventName": "ls_mab_alloc.loads", + "EventCode": "0x41", + "BriefDescription": "LS MAB allocates by type - loads.", + "UMask": "0x01" + }, { "EventName": "ls_l1_d_tlb_miss.all", "EventCode": "0x45", "BriefDescription": "L1 DTLB Miss or Reload off all sizes.", - "PublicDescription": "L1 DTLB Miss or Reload off all sizes.", "UMask": "0xff" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_miss", "EventCode": "0x45", "BriefDescription": "L1 DTLB Miss of a page of 1G size.", - "PublicDescription": "L1 DTLB Miss of a page of 1G size.", "UMask": "0x80" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_miss", "EventCode": "0x45", "BriefDescription": "L1 DTLB Miss of a page of 2M size.", - "PublicDescription": "L1 DTLB Miss of a page of 2M size.", "UMask": "0x40" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_32k_l2_miss", "EventCode": "0x45", "BriefDescription": "L1 DTLB Miss of a page of 32K size.", - "PublicDescription": "L1 DTLB Miss of a page of 32K size.", "UMask": "0x20" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_miss", "EventCode": "0x45", "BriefDescription": "L1 DTLB Miss of a page of 4K size.", - "PublicDescription": "L1 DTLB Miss of a page of 4K size.", "UMask": "0x10" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_hit", "EventCode": "0x45", "BriefDescription": "L1 DTLB Reload of a page of 1G size.", - "PublicDescription": "L1 DTLB Reload of a page of 1G size.", "UMask": "0x8" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_hit", "EventCode": "0x45", "BriefDescription": "L1 DTLB Reload of a page of 2M size.", - "PublicDescription": "L1 DTLB Reload of a page of 2M size.", "UMask": "0x4" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_32k_l2_hit", "EventCode": "0x45", "BriefDescription": "L1 DTLB Reload of a page of 32K size.", - "PublicDescription": "L1 DTLB Reload of a page of 32K size.", "UMask": "0x2" }, { "EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_hit", "EventCode": "0x45", "BriefDescription": "L1 DTLB Reload of a page of 4K size.", - "PublicDescription": "L1 DTLB Reload of a page of 4K size.", "UMask": "0x1" }, { - "EventName": "ls_tablewalker.perf_mon_tablewalk_alloc_iside", + "EventName": "ls_tablewalker.iside", "EventCode": "0x46", - "BriefDescription": "Tablewalker allocation.", - "PublicDescription": "Tablewalker allocation.", + "BriefDescription": "Total Page Table Walks on I-side.", "UMask": "0xc" }, { - "EventName": "ls_tablewalker.perf_mon_tablewalk_alloc_dside", + "EventName": "ls_tablewalker.ic_type1", "EventCode": "0x46", - "BriefDescription": "Tablewalker allocation.", - "PublicDescription": "Tablewalker allocation.", + "BriefDescription": "Total Page Table Walks IC Type 1.", + "UMask": "0x8" + }, + { + "EventName": "ls_tablewalker.ic_type0", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks IC Type 0.", + "UMask": "0x4" + }, + { + "EventName": "ls_tablewalker.dside", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks on D-side.", "UMask": "0x3" }, + { + "EventName": "ls_tablewalker.dc_type1", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks DC Type 1.", + "UMask": "0x2" + }, + { + "EventName": "ls_tablewalker.dc_type0", + "EventCode": "0x46", + "BriefDescription": "Total Page Table Walks DC Type 0.", + "UMask": "0x1" + }, { "EventName": "ls_misal_accesses", "EventCode": "0x47", @@ -123,35 +150,30 @@ "EventName": "ls_pref_instr_disp.prefetch_nta", "EventCode": "0x4b", "BriefDescription": "Software Prefetch Instructions (PREFETCHNTA instruction) Dispatched.", - "PublicDescription": "Software Prefetch Instructions (PREFETCHNTA instruction) Dispatched.", "UMask": "0x4" }, { "EventName": "ls_pref_instr_disp.store_prefetch_w", "EventCode": "0x4b", "BriefDescription": "Software Prefetch Instructions (3DNow PREFETCHW instruction) Dispatched.", - "PublicDescription": "Software Prefetch Instructions (3DNow PREFETCHW instruction) Dispatched.", "UMask": "0x2" }, { "EventName": "ls_pref_instr_disp.load_prefetch_w", "EventCode": "0x4b", - "BriefDescription": "Prefetch, Prefetch_T0_T1_T2.", - "PublicDescription": "Software Prefetch Instructions Dispatched. Prefetch, Prefetch_T0_T1_T2.", + "BriefDescription": "Software Prefetch Instructions Dispatched. Prefetch, Prefetch_T0_T1_T2.", "UMask": "0x1" }, { "EventName": "ls_inef_sw_pref.mab_mch_cnt", "EventCode": "0x52", - "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core.", - "PublicDescription": "The number of software prefetches that did not fetch data outside of the processor core.", + "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core. Software PREFETCH instruction saw a match on an already-allocated miss request buffer.", "UMask": "0x2" }, { "EventName": "ls_inef_sw_pref.data_pipe_sw_pf_dc_hit", "EventCode": "0x52", - "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core.", - "PublicDescription": "The number of software prefetches that did not fetch data outside of the processor core.", + "BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core. Software PREFETCH instruction saw a DC hit.", "UMask": "0x1" }, { diff --git a/tools/perf/pmu-events/arch/x86/amdzen1/other.json b/tools/perf/pmu-events/arch/x86/amdzen1/other.json index b26a00d05a2e..ff780098d36e 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen1/other.json +++ b/tools/perf/pmu-events/arch/x86/amdzen1/other.json @@ -2,64 +2,55 @@ { "EventName": "ic_oc_mode_switch.oc_ic_mode_switch", "EventCode": "0x28a", - "BriefDescription": "OC to IC mode switch.", - "PublicDescription": "OC Mode Switch. OC to IC mode switch.", + "BriefDescription": "OC Mode Switch. OC to IC mode switch.", "UMask": "0x2" }, { "EventName": "ic_oc_mode_switch.ic_oc_mode_switch", "EventCode": "0x28a", - "BriefDescription": "IC to OC mode switch.", - "PublicDescription": "OC Mode Switch. IC to OC mode switch.", + "BriefDescription": "OC Mode Switch. IC to OC mode switch.", "UMask": "0x1" }, { "EventName": "de_dis_dispatch_token_stalls0.retire_token_stall", "EventCode": "0xaf", - "BriefDescription": "RETIRE Tokens unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. RETIRE Tokens unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. RETIRE Tokens unavailable.", "UMask": "0x40" }, { "EventName": "de_dis_dispatch_token_stalls0.agsq_token_stall", "EventCode": "0xaf", - "BriefDescription": "AGSQ Tokens unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. AGSQ Tokens unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. AGSQ Tokens unavailable.", "UMask": "0x20" }, { "EventName": "de_dis_dispatch_token_stalls0.alu_token_stall", "EventCode": "0xaf", - "BriefDescription": "ALU tokens total unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALU tokens total unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALU tokens total unavailable.", "UMask": "0x10" }, { "EventName": "de_dis_dispatch_token_stalls0.alsq3_0_token_stall", "EventCode": "0xaf", - "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 3_0 Tokens unavailable.", "UMask": "0x8" }, { "EventName": "de_dis_dispatch_token_stalls0.alsq3_token_stall", "EventCode": "0xaf", - "BriefDescription": "ALSQ 3 Tokens unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 3 Tokens unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 3 Tokens unavailable.", "UMask": "0x4" }, { "EventName": "de_dis_dispatch_token_stalls0.alsq2_token_stall", "EventCode": "0xaf", - "BriefDescription": "ALSQ 2 Tokens unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 2 Tokens unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 2 Tokens unavailable.", "UMask": "0x2" }, { "EventName": "de_dis_dispatch_token_stalls0.alsq1_token_stall", "EventCode": "0xaf", - "BriefDescription": "ALSQ 1 Tokens unavailable.", - "PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 1 Tokens unavailable.", + "BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 1 Tokens unavailable.", "UMask": "0x1" } ] diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 244a36e37a3a..25b06cf98747 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -36,5 +36,5 @@ GenuineIntel-6-55-[56789ABCDEF],v1,cascadelakex,core GenuineIntel-6-7D,v1,icelake,core GenuineIntel-6-7E,v1,icelake,core GenuineIntel-6-86,v1,tremontx,core -AuthenticAMD-23-([12][0-9A-F]|[0-9A-F]),v1,amdzen1,core +AuthenticAMD-23-([12][0-9A-F]|[0-9A-F]),v2,amdzen1,core AuthenticAMD-23-[[:xdigit:]]+,v1,amdzen2,core From 29f36c168813f1beaf59812cc79ef46fb33c669a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Mar 2020 11:42:56 -0300 Subject: [PATCH 492/809] tools headers uapi: Update linux/in.h copy To get the changes in: 267762538705 ("seg6: fix SRv6 L2 tunnels to use IANA-assigned protocol number") That ends up automatically adding the new IPPROTO_ETHERNET to the socket args beautifiers: $ tools/perf/trace/beauty/socket_ipproto.sh > before Apply this patch: $ tools/perf/trace/beauty/socket_ipproto.sh > after $ diff -u before after --- before 2020-03-19 11:48:36.876673819 -0300 +++ after 2020-03-19 11:49:00.148541377 -0300 @@ -6,6 +6,7 @@ [132] = "SCTP", [136] = "UDPLITE", [137] = "MPLS", + [143] = "ETHERNET", [17] = "UDP", [1] = "ICMP", [22] = "IDP", $ Addresses this tools/perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/in.h' differs from latest version at 'include/uapi/linux/in.h' diff -u tools/include/uapi/linux/in.h include/uapi/linux/in.h Cc: David S. Miller Cc: Paolo Lungaroni Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/in.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/include/uapi/linux/in.h b/tools/include/uapi/linux/in.h index 1521073b6348..8533bf07450f 100644 --- a/tools/include/uapi/linux/in.h +++ b/tools/include/uapi/linux/in.h @@ -74,6 +74,8 @@ enum { #define IPPROTO_UDPLITE IPPROTO_UDPLITE IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */ #define IPPROTO_MPLS IPPROTO_MPLS + IPPROTO_ETHERNET = 143, /* Ethernet-within-IPv6 Encapsulation */ +#define IPPROTO_ETHERNET IPPROTO_ETHERNET IPPROTO_RAW = 255, /* Raw IP packets */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_MPTCP = 262, /* Multipath TCP connection */ From 7cd053d4cf8a3dc1a06bdb4be0ed9b0ecbaa21f5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 18 Mar 2020 21:45:22 +0100 Subject: [PATCH 493/809] perf tools: Unify a bit the build directory output Removing the extra 'SUBDIR' line from clean and doc build output. Because it's annoying.. ;-) Before: $ make clean ... SUBDIR Documentation CLEAN Documentation After: $ make clean ... CLEAN Documentation Before: $ make doc BUILD: Doing 'make -j8' parallel build SUBDIR Documentation ASCIIDOC perf-stat.html ... After: $ make doc BUILD: Doing 'make -j8' parallel build ASCIIDOC perf-stat.html ... Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Michael Petlan Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200318204522.1200981-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 3eda9d4b88e7..a02aca9b21f4 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -231,6 +231,7 @@ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ BPF_DIR = $(srctree)/tools/lib/bpf/ SUBCMD_DIR = $(srctree)/tools/lib/subcmd/ LIBPERF_DIR = $(srctree)/tools/lib/perf/ +DOC_DIR = $(srctree)/tools/perf/Documentation/ # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed. # Without this setting the output feature dump file misses some features, for @@ -792,7 +793,6 @@ $(LIBSUBCMD): FORCE $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a $(LIBSUBCMD)-clean: - $(call QUIET_CLEAN, libsubcmd) $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean help: @@ -832,7 +832,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html # 'make doc' should call 'make -C Documentation all' $(DOC_TARGETS): - $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) + $(Q)$(MAKE) -C $(DOC_DIR) O=$(OUTPUT) $(@:doc=all) TAG_FOLDERS= . ../lib ../include TAG_FILES= ../../include/uapi/linux/perf_event.h @@ -959,7 +959,7 @@ install-python_ext: # 'make install-doc' should call 'make -C Documentation install' $(INSTALL_DOC_TARGETS): - $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=) + $(Q)$(MAKE) -C $(DOC_DIR) O=$(OUTPUT) $(@:-doc=) ### Cleaning rules @@ -1008,7 +1008,8 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea $(OUTPUT)$(rename_flags_array) \ $(OUTPUT)$(arch_errno_name_array) \ $(OUTPUT)$(sync_file_range_arrays) - $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean + $(call QUIET_CLEAN, Documentation) \ + $(MAKE) -C $(DOC_DIR) O=$(OUTPUT) clean >/dev/null # # To provide FEATURE-DUMP into $(FEATURE_DUMP_COPY) From c52db67a74b3a9b834af4588489cfea22ec280a3 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:13 +0800 Subject: [PATCH 494/809] perf jevents: Add some test events Add some test PMU events. The events are randomly chosen from x86 and arm64 JSONs. The events include CPU and uncore events. Signed-off-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-2-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/test/test_cpu/branch.json | 12 +++++++++ .../pmu-events/arch/test/test_cpu/other.json | 26 +++++++++++++++++++ .../pmu-events/arch/test/test_cpu/uncore.json | 21 +++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tools/perf/pmu-events/arch/test/test_cpu/branch.json create mode 100644 tools/perf/pmu-events/arch/test/test_cpu/other.json create mode 100644 tools/perf/pmu-events/arch/test/test_cpu/uncore.json diff --git a/tools/perf/pmu-events/arch/test/test_cpu/branch.json b/tools/perf/pmu-events/arch/test/test_cpu/branch.json new file mode 100644 index 000000000000..93ddfd8053ca --- /dev/null +++ b/tools/perf/pmu-events/arch/test/test_cpu/branch.json @@ -0,0 +1,12 @@ +[ + { + "EventName": "bp_l1_btb_correct", + "EventCode": "0x8a", + "BriefDescription": "L1 BTB Correction." + }, + { + "EventName": "bp_l2_btb_correct", + "EventCode": "0x8b", + "BriefDescription": "L2 BTB Correction." + } +] diff --git a/tools/perf/pmu-events/arch/test/test_cpu/other.json b/tools/perf/pmu-events/arch/test/test_cpu/other.json new file mode 100644 index 000000000000..7d53d7ecd723 --- /dev/null +++ b/tools/perf/pmu-events/arch/test/test_cpu/other.json @@ -0,0 +1,26 @@ +[ + { + "EventCode": "0x6", + "Counter": "0,1", + "UMask": "0x80", + "EventName": "SEGMENT_REG_LOADS.ANY", + "SampleAfterValue": "200000", + "BriefDescription": "Number of segment register loads." + }, + { + "EventCode": "0x9", + "Counter": "0,1", + "UMask": "0x20", + "EventName": "DISPATCH_BLOCKED.ANY", + "SampleAfterValue": "200000", + "BriefDescription": "Memory cluster signals to block micro-op dispatch for any reason" + }, + { + "EventCode": "0x3A", + "Counter": "0,1", + "UMask": "0x0", + "EventName": "EIST_TRANS", + "SampleAfterValue": "200000", + "BriefDescription": "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions" + } +] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/test/test_cpu/uncore.json b/tools/perf/pmu-events/arch/test/test_cpu/uncore.json new file mode 100644 index 000000000000..d0a890cc814d --- /dev/null +++ b/tools/perf/pmu-events/arch/test/test_cpu/uncore.json @@ -0,0 +1,21 @@ +[ + { + "EventCode": "0x02", + "EventName": "uncore_hisi_ddrc.flux_wcmd", + "BriefDescription": "DDRC write commands", + "PublicDescription": "DDRC write commands", + "Unit": "hisi_sccl,ddrc" + }, + { + "Unit": "CBO", + "EventCode": "0x22", + "UMask": "0x81", + "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_EVICTION", + "BriefDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.", + "PublicDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.", + "Counter": "0,1", + "CounterMask": "0", + "Invert": "0", + "EdgeDetect": "0" + } +] From d84478088780acdecfcf50a0e52b71cc4ab7c520 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:14 +0800 Subject: [PATCH 495/809] perf jevents: Support test events folder With the goal of supporting pmu-events test case, introduce support for a test events folder. These test events can be used for testing generation of pmu-event tables and alias creation for any arch. When running the pmu-events test case, these test events will be used as the platform-agnostic events, so aliases can be created per-PMU and validated against known expected values. To support the test events, add a "testcpu" entry in pmu_events_map[]. The pmu-events test will be able to lookup the events map for "testcpu", to verify the generated tables against expected values. The resultant generated pmu-events.c will now look like the following: struct pmu_event pme_ampere_emag[] = { { .name = "ldrex_spec", .event = "event=0x6c", .desc = "Exclusive operation spe...", .topic = "intrinsic", .long_desc = "Exclusive operation ...", }, ... }; struct pmu_event pme_test_cpu[] = { { .name = "uncore_hisi_ddrc.flux_wcmd", .event = "event=0x2", .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", .topic = "uncore", .long_desc = "DDRC write commands", .pmu = "hisi_sccl,ddrc", }, { .name = "unc_cbo_xsnp_response.miss_eviction", .event = "umask=0x81,event=0x22", .desc = "Unit: uncore_cbox A cross-core snoop resulted ...", .topic = "uncore", .long_desc = "A cross-core snoop resulted from L3 ...", .pmu = "uncore_cbox", }, { .name = "eist_trans", .event = "umask=0x0,period=200000,event=0x3a", .desc = "Number of Enhanced Intel SpeedStep(R) ...", .topic = "other", }, { .name = 0, }, }; struct pmu_events_map pmu_events_map[] = { ... { .cpuid = "0x00000000500f0000", .version = "v1", .type = "core", .table = pme_ampere_emag }, ... { .cpuid = "testcpu", .version = "v1", .type = "core", .table = pme_test_cpu, }, { .cpuid = 0, .version = 0, .type = 0, .table = 0, }, }; Signed-off-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-3-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jevents.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index 3c4236a5bad8..fa86c5f997cc 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -771,6 +771,19 @@ static void print_mapping_table_suffix(FILE *outfp) fprintf(outfp, "};\n"); } +static void print_mapping_test_table(FILE *outfp) +{ + /* + * Print the terminating, NULL entry. + */ + fprintf(outfp, "{\n"); + fprintf(outfp, "\t.cpuid = \"testcpu\",\n"); + fprintf(outfp, "\t.version = \"v1\",\n"); + fprintf(outfp, "\t.type = \"core\",\n"); + fprintf(outfp, "\t.table = pme_test_cpu,\n"); + fprintf(outfp, "},\n"); +} + static int process_mapfile(FILE *outfp, char *fpath) { int n = 16384; @@ -848,6 +861,7 @@ static int process_mapfile(FILE *outfp, char *fpath) } out: + print_mapping_test_table(outfp); print_mapping_table_suffix(outfp); fclose(mapfp); free(line); @@ -1168,6 +1182,22 @@ int main(int argc, char *argv[]) goto empty_map; } + sprintf(ldirname, "%s/test", start_dirname); + + rc = nftw(ldirname, process_one_file, maxfds, 0); + if (rc && verbose) { + pr_info("%s: Error walking file tree %s rc=%d for test\n", + prog, ldirname, rc); + goto empty_map; + } else if (rc < 0) { + /* Make build fail */ + free_arch_std_events(); + ret = 1; + goto out_free_mapfile; + } else if (rc) { + goto empty_map; + } + if (close_table) print_events_table_suffix(eventsfp); From e45ad701e784e0eed8a07b537b47afb302c59dab Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:15 +0800 Subject: [PATCH 496/809] perf pmu: Refactor pmu_add_cpu_aliases() Create pmu_add_cpu_aliases_map() from pmu_add_cpu_aliases(), so the caller can pass the map; the pmu-events test would use this since there would be no CPUID matching to a mapfile there. Signed-off-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-4-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 21 +++++++++++++-------- tools/perf/util/pmu.h | 3 +++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 8b99fd312aae..c616a06a34a8 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -21,7 +21,6 @@ #include "pmu.h" #include "parse-events.h" #include "header.h" -#include "pmu-events/pmu-events.h" #include "string2.h" #include "strbuf.h" #include "fncache.h" @@ -744,16 +743,11 @@ out: * to the current running CPU. Then, add all PMU events from that table * as aliases. */ -static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) +void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu, + struct pmu_events_map *map) { int i; - struct pmu_events_map *map; const char *name = pmu->name; - - map = perf_pmu__find_map(pmu); - if (!map) - return; - /* * Found a matching PMU events table. Create aliases */ @@ -788,6 +782,17 @@ new_alias: } } +static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) +{ + struct pmu_events_map *map; + + map = perf_pmu__find_map(pmu); + if (!map) + return; + + pmu_add_cpu_aliases_map(head, pmu, map); +} + struct perf_event_attr * __weak perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) { diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 6737e3d5d568..0b4a0efae38e 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -7,6 +7,7 @@ #include #include #include "parse-events.h" +#include "pmu-events/pmu-events.h" struct perf_evsel_config_term; @@ -97,6 +98,8 @@ int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, int perf_pmu__test(void); struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); +void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu, + struct pmu_events_map *map); struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu); From a6c925fd3aa2aba043a73b0ad57ffd296e1c42c9 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:16 +0800 Subject: [PATCH 497/809] perf test: Add pmu-events test The initial test will verify that the test tables in generated pmu-events.c match against known, expected values. For known events added in pmu-events/arch/test, we need to add an entry in test_cpu_aliases_events[] or test_uncore_events[]. A sample run is as follows for x86: john@linux-3c19:~/linux> tools/perf/perf test -vv 10 10: PMU event aliases : --- start --- test child forked, pid 5316 testing event table bp_l1_btb_correct: pass testing event table bp_l2_btb_correct: pass testing event table segment_reg_loads.any: pass testing event table dispatch_blocked.any: pass testing event table eist_trans: pass testing event table uncore_hisi_ddrc.flux_wcmd: pass testing event table unc_cbo_xsnp_response.miss_eviction: pass test child finished with 0 ---- end ---- PMU event aliases: Ok Signed-off-by: John Garry Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com [ Fixup test_cpu_events[] and test_uncore_events[] sentinels to initialize one of its members to NULL, fixing the build in older compilers ] Link: http://lore.kernel.org/lkml/1584442939-8911-5-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/pmu-events.c | 233 ++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 4 files changed, 239 insertions(+) create mode 100644 tools/perf/tests/pmu-events.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 1692529639b0..b3d1bf13ca07 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -14,6 +14,7 @@ perf-y += evsel-roundtrip-name.o perf-y += evsel-tp-sched.o perf-y += fdarray.o perf-y += pmu.o +perf-y += pmu-events.o perf-y += hists_common.o perf-y += hists_link.o perf-y += hists_filter.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 54d9516c9839..b6322eb0f423 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -72,6 +72,10 @@ static struct test generic_tests[] = { .desc = "Parse perf pmu format", .func = test__pmu, }, + { + .desc = "PMU events", + .func = test__pmu_events, + }, { .desc = "DSO data read", .func = test__dso_data, diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c new file mode 100644 index 000000000000..12fc29746a09 --- /dev/null +++ b/tools/perf/tests/pmu-events.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "parse-events.h" +#include "pmu.h" +#include "tests.h" +#include +#include +#include + +#include "debug.h" +#include "../pmu-events/pmu-events.h" + +struct perf_pmu_test_event { + struct pmu_event event; +}; +static struct perf_pmu_test_event test_cpu_events[] = { + { + .event = { + .name = "bp_l1_btb_correct", + .event = "event=0x8a", + .desc = "L1 BTB Correction", + .topic = "branch", + }, + }, + { + .event = { + .name = "bp_l2_btb_correct", + .event = "event=0x8b", + .desc = "L2 BTB Correction", + .topic = "branch", + }, + }, + { + .event = { + .name = "segment_reg_loads.any", + .event = "umask=0x80,period=200000,event=0x6", + .desc = "Number of segment register loads", + .topic = "other", + }, + }, + { + .event = { + .name = "dispatch_blocked.any", + .event = "umask=0x20,period=200000,event=0x9", + .desc = "Memory cluster signals to block micro-op dispatch for any reason", + .topic = "other", + }, + }, + { + .event = { + .name = "eist_trans", + .event = "umask=0x0,period=200000,event=0x3a", + .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", + .topic = "other", + }, + }, + { /* sentinel */ + .event = { + .name = NULL, + }, + }, +}; + +static struct perf_pmu_test_event test_uncore_events[] = { + { + .event = { + .name = "uncore_hisi_ddrc.flux_wcmd", + .event = "event=0x2", + .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", + .topic = "uncore", + .long_desc = "DDRC write commands", + .pmu = "hisi_sccl,ddrc", + }, + }, + { + .event = { + .name = "unc_cbo_xsnp_response.miss_eviction", + .event = "umask=0x81,event=0x22", + .desc = "Unit: uncore_cbox A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .topic = "uncore", + .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .pmu = "uncore_cbox", + }, + }, + { /* sentinel */ + .event = { + .name = NULL, + }, + } +}; + +const int total_test_events_size = ARRAY_SIZE(test_uncore_events); + +static bool is_same(const char *reference, const char *test) +{ + if (!reference && !test) + return true; + + if (reference && !test) + return false; + + if (!reference && test) + return false; + + return !strcmp(reference, test); +} + +static struct pmu_events_map *__test_pmu_get_events_map(void) +{ + struct pmu_events_map *map; + + for (map = &pmu_events_map[0]; map->cpuid; map++) { + if (!strcmp(map->cpuid, "testcpu")) + return map; + } + + pr_err("could not find test events map\n"); + + return NULL; +} + +/* Verify generated events from pmu-events.c is as expected */ +static int __test_pmu_event_table(void) +{ + struct pmu_events_map *map = __test_pmu_get_events_map(); + struct pmu_event *table; + int map_events = 0, expected_events; + + /* ignore 2x sentinels */ + expected_events = ARRAY_SIZE(test_cpu_events) + + ARRAY_SIZE(test_uncore_events) - 2; + + if (!map) + return -1; + + for (table = map->table; table->name; table++) { + struct perf_pmu_test_event *test; + struct pmu_event *te; + bool found = false; + + if (table->pmu) + test = &test_uncore_events[0]; + else + test = &test_cpu_events[0]; + + te = &test->event; + + for (; te->name; test++, te = &test->event) { + if (strcmp(table->name, te->name)) + continue; + found = true; + map_events++; + + if (!is_same(table->desc, te->desc)) { + pr_debug2("testing event table %s: mismatched desc, %s vs %s\n", + table->name, table->desc, te->desc); + return -1; + } + + if (!is_same(table->topic, te->topic)) { + pr_debug2("testing event table %s: mismatched topic, %s vs %s\n", + table->name, table->topic, + te->topic); + return -1; + } + + if (!is_same(table->long_desc, te->long_desc)) { + pr_debug2("testing event table %s: mismatched long_desc, %s vs %s\n", + table->name, table->long_desc, + te->long_desc); + return -1; + } + + if (!is_same(table->unit, te->unit)) { + pr_debug2("testing event table %s: mismatched unit, %s vs %s\n", + table->name, table->unit, + te->unit); + return -1; + } + + if (!is_same(table->perpkg, te->perpkg)) { + pr_debug2("testing event table %s: mismatched perpkg, %s vs %s\n", + table->name, table->perpkg, + te->perpkg); + return -1; + } + + if (!is_same(table->metric_expr, te->metric_expr)) { + pr_debug2("testing event table %s: mismatched metric_expr, %s vs %s\n", + table->name, table->metric_expr, + te->metric_expr); + return -1; + } + + if (!is_same(table->metric_name, te->metric_name)) { + pr_debug2("testing event table %s: mismatched metric_name, %s vs %s\n", + table->name, table->metric_name, + te->metric_name); + return -1; + } + + if (!is_same(table->deprecated, te->deprecated)) { + pr_debug2("testing event table %s: mismatched deprecated, %s vs %s\n", + table->name, table->deprecated, + te->deprecated); + return -1; + } + + pr_debug("testing event table %s: pass\n", table->name); + } + + if (!found) { + pr_err("testing event table: could not find event %s\n", + table->name); + return -1; + } + } + + if (map_events != expected_events) { + pr_err("testing event table: found %d, but expected %d\n", + map_events, expected_events); + return -1; + } + + return 0; +} +int test__pmu_events(struct test *test __maybe_unused, + int subtest __maybe_unused) +{ + if (__test_pmu_event_table()) + return -1; + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 9a160fef47c9..61a1ab032080 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -49,6 +49,7 @@ int test__perf_evsel__roundtrip_name_test(struct test *test, int subtest); int test__perf_evsel__tp_sched_test(struct test *test, int subtest); int test__syscall_openat_tp_fields(struct test *test, int subtest); int test__pmu(struct test *test, int subtest); +int test__pmu_events(struct test *test, int subtest); int test__attr(struct test *test, int subtest); int test__dso_data(struct test *test, int subtest); int test__dso_data_cache(struct test *test, int subtest); From d504fae93dd61b734aefc403c7653d958aef655a Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:17 +0800 Subject: [PATCH 498/809] perf pmu: Add is_pmu_core() Add a function to decide whether a PMU is a core PMU. Signed-off-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-6-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 5 +++++ tools/perf/util/pmu.h | 1 + 2 files changed, 6 insertions(+) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index c616a06a34a8..55129d09f19d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1400,6 +1400,11 @@ static void wordwrap(char *s, int start, int max, int corr) } } +bool is_pmu_core(const char *name) +{ + return !strcmp(name, "cpu") || is_arm_pmu_core(name); +} + void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, bool long_desc, bool details_flag, bool deprecated) { diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 0b4a0efae38e..b756946ae78d 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -88,6 +88,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); +bool is_pmu_core(const char *name); void print_pmu_events(const char *event_glob, bool name_only, bool quiet, bool long_desc, bool details_flag, bool deprecated); From 5b9a50001b2c23f90f2a21db4763f3a9599588c4 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:18 +0800 Subject: [PATCH 499/809] perf pmu: Make pmu_uncore_alias_match() public The perf pmu-events test will want to use pmu_uncore_alias_match(), so make it public. Signed-off-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-7-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 2 +- tools/perf/util/pmu.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 55129d09f19d..616fbda7c3fc 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -698,7 +698,7 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) return map; } -static bool pmu_uncore_alias_match(const char *pmu_name, const char *name) +bool pmu_uncore_alias_match(const char *pmu_name, const char *name) { char *tmp = NULL, *tok, *str; bool res; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index b756946ae78d..5fb3f16828df 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -103,6 +103,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu, struct pmu_events_map *map); struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu); +bool pmu_uncore_alias_match(const char *pmu_name, const char *name); int perf_pmu__convert_scale(const char *scale, char **end, double *sval); From 956a78356c24c1ac3becf854135dc065b6b74265 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:19 +0800 Subject: [PATCH 500/809] perf test: Test pmu-events aliases Add creating event aliases to the pmu-events test. So currently we verify that the generated pmu-events.c is as expected for some test events. Now test that we generate aliases as expected for those events during normal operation. For that, we cycle through each HW PMU in the system, and use the test events to create aliases, and verify those against known, expected values. For core PMUs, we should create an alias for every event in test_cpu_events[]. However, for uncore PMUs, they need to be matched by the pmu_event.pmu member, so use test_uncore_events[]; so check the match beforehand with pmu_uncore_alias_match(). A sample run is as follows for my x86 machine: john@linux-3c19:~/linux> tools/perf/perf test -vv 10 10: PMU events : --- start --- ... testing PMU uncore_arb aliases: no events to match testing PMU cstate_pkg aliases: no events to match skipping testing PMU breakpoint testing aliases PMU uncore_cbox_1: matched event unc_cbo_xsnp_response.miss_eviction testing PMU uncore_cbox_1 aliases: pass testing PMU power aliases: no events to match testing aliases PMU cpu: matched event bp_l1_btb_correct testing aliases PMU cpu: matched event bp_l2_btb_correct testing aliases PMU cpu: matched event segment_reg_loads.any testing aliases PMU cpu: matched event dispatch_blocked.any testing aliases PMU cpu: matched event eist_trans testing PMU cpu aliases: pass testing PMU intel_pt aliases: no events to match skipping testing PMU software skipping testing PMU intel_bts testing PMU uncore_imc aliases: no events to match testing aliases PMU uncore_cbox_0: matched event unc_cbo_xsnp_response.miss_eviction testing PMU uncore_cbox_0 aliases: pass testing PMU cstate_core aliases: no events to match skipping testing PMU tracepoint testing PMU msr aliases: no events to match test child finished with 0 Signed-off-by: John Garry Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-8-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu-events.c | 148 +++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 12fc29746a09..d64261da8bf7 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -5,13 +5,24 @@ #include #include #include - +#include #include "debug.h" #include "../pmu-events/pmu-events.h" struct perf_pmu_test_event { struct pmu_event event; + + /* extra events for aliases */ + const char *alias_str; + + /* + * Note: For when PublicDescription does not exist in the JSON, we + * will have no long_desc in pmu_event.long_desc, but long_desc may + * be set in the alias. + */ + const char *alias_long_desc; }; + static struct perf_pmu_test_event test_cpu_events[] = { { .event = { @@ -20,6 +31,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "L1 BTB Correction", .topic = "branch", }, + .alias_str = "event=0x8a", + .alias_long_desc = "L1 BTB Correction", }, { .event = { @@ -28,6 +41,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "L2 BTB Correction", .topic = "branch", }, + .alias_str = "event=0x8b", + .alias_long_desc = "L2 BTB Correction", }, { .event = { @@ -36,6 +51,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Number of segment register loads", .topic = "other", }, + .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", + .alias_long_desc = "Number of segment register loads", }, { .event = { @@ -44,6 +61,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Memory cluster signals to block micro-op dispatch for any reason", .topic = "other", }, + .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", + .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", }, { .event = { @@ -52,6 +71,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", .topic = "other", }, + .alias_str = "umask=0,(null)=0x30d40,event=0x3a", + .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", }, { /* sentinel */ .event = { @@ -70,6 +91,8 @@ static struct perf_pmu_test_event test_uncore_events[] = { .long_desc = "DDRC write commands", .pmu = "hisi_sccl,ddrc", }, + .alias_str = "event=0x2", + .alias_long_desc = "DDRC write commands", }, { .event = { @@ -80,6 +103,8 @@ static struct perf_pmu_test_event test_uncore_events[] = { .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", .pmu = "uncore_cbox", }, + .alias_str = "umask=0x81,event=0x22", + .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", }, { /* sentinel */ .event = { @@ -223,11 +248,132 @@ static int __test_pmu_event_table(void) return 0; } + +static struct perf_pmu_alias *find_alias(const char *test_event, struct list_head *aliases) +{ + struct perf_pmu_alias *alias; + + list_for_each_entry(alias, aliases, list) + if (!strcmp(test_event, alias->name)) + return alias; + + return NULL; +} + +/* Verify aliases are as expected */ +static int __test__pmu_event_aliases(char *pmu_name, int *count) +{ + struct perf_pmu_test_event *test; + struct pmu_event *te; + struct perf_pmu *pmu; + LIST_HEAD(aliases); + int res = 0; + bool use_uncore_table; + struct pmu_events_map *map = __test_pmu_get_events_map(); + + if (!map) + return -1; + + if (is_pmu_core(pmu_name)) { + test = &test_cpu_events[0]; + use_uncore_table = false; + } else { + test = &test_uncore_events[0]; + use_uncore_table = true; + } + + pmu = zalloc(sizeof(*pmu)); + if (!pmu) + return -1; + + pmu->name = pmu_name; + + pmu_add_cpu_aliases_map(&aliases, pmu, map); + + for (te = &test->event; te->name; test++, te = &test->event) { + struct perf_pmu_alias *alias = find_alias(te->name, &aliases); + + if (!alias) { + bool uncore_match = pmu_uncore_alias_match(pmu_name, + te->pmu); + + if (use_uncore_table && !uncore_match) { + pr_debug3("testing aliases PMU %s: skip matching alias %s\n", + pmu_name, te->name); + continue; + } + + pr_debug2("testing aliases PMU %s: no alias, alias_table->name=%s\n", + pmu_name, te->name); + res = -1; + break; + } + + if (!is_same(alias->desc, te->desc)) { + pr_debug2("testing aliases PMU %s: mismatched desc, %s vs %s\n", + pmu_name, alias->desc, te->desc); + res = -1; + break; + } + + if (!is_same(alias->long_desc, test->alias_long_desc)) { + pr_debug2("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", + pmu_name, alias->long_desc, + test->alias_long_desc); + res = -1; + break; + } + + if (!is_same(alias->str, test->alias_str)) { + pr_debug2("testing aliases PMU %s: mismatched str, %s vs %s\n", + pmu_name, alias->str, test->alias_str); + res = -1; + break; + } + + if (!is_same(alias->topic, te->topic)) { + pr_debug2("testing aliases PMU %s: mismatched topic, %s vs %s\n", + pmu_name, alias->topic, te->topic); + res = -1; + break; + } + + (*count)++; + pr_debug2("testing aliases PMU %s: matched event %s\n", + pmu_name, alias->name); + } + + free(pmu); + return res; +} + int test__pmu_events(struct test *test __maybe_unused, int subtest __maybe_unused) { + struct perf_pmu *pmu = NULL; + if (__test_pmu_event_table()) return -1; + while ((pmu = perf_pmu__scan(pmu)) != NULL) { + int count = 0; + + if (list_empty(&pmu->format)) { + pr_debug2("skipping testing PMU %s\n", pmu->name); + continue; + } + + if (__test__pmu_event_aliases(pmu->name, &count)) { + pr_debug("testing PMU %s aliases: failed\n", pmu->name); + return -1; + } + + if (count == 0) + pr_debug3("testing PMU %s aliases: no events to match\n", + pmu->name); + else + pr_debug("testing PMU %s aliases: pass\n", pmu->name); + } + return 0; } From d74b181a028bb5a468f0c609553eff6a8fdf4887 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 24 Mar 2020 08:03:19 +0100 Subject: [PATCH 501/809] perf cpumap: Fix snprintf overflow check 'snprintf' returns the number of characters which would be generated for the given input. If the returned value is *greater than* or equal to the buffer size, it means that the output has been truncated. Fix the overflow test accordingly. Fixes: 7780c25bae59f ("perf tools: Allow ability to map cpus to nodes easily") Fixes: 92a7e1278005b ("perf cpumap: Add cpu__max_present_cpu()") Signed-off-by: Christophe JAILLET Suggested-by: David Laight Cc: Alexander Shishkin Cc: Don Zickus Cc: He Zhe Cc: Jan Stancek Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: kernel-janitors@vger.kernel.org Link: http://lore.kernel.org/lkml/20200324070319.10901-1-christophe.jaillet@wanadoo.fr Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 983b7388f22b..dc5c5e6fc502 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -317,7 +317,7 @@ static void set_max_cpu_num(void) /* get the highest possible cpu number for a sparse allocation */ ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt); - if (ret == PATH_MAX) { + if (ret >= PATH_MAX) { pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); goto out; } @@ -328,7 +328,7 @@ static void set_max_cpu_num(void) /* get the highest present cpu number for a sparse allocation */ ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/present", mnt); - if (ret == PATH_MAX) { + if (ret >= PATH_MAX) { pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); goto out; } @@ -356,7 +356,7 @@ static void set_max_node_num(void) /* get the highest possible cpu number for a sparse allocation */ ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt); - if (ret == PATH_MAX) { + if (ret >= PATH_MAX) { pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); goto out; } @@ -441,7 +441,7 @@ int cpu__setup_cpunode_map(void) return 0; n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt); - if (n == PATH_MAX) { + if (n >= PATH_MAX) { pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); return -1; } @@ -456,7 +456,7 @@ int cpu__setup_cpunode_map(void) continue; n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name); - if (n == PATH_MAX) { + if (n >= PATH_MAX) { pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); continue; } From 0d33b34352531ff7029c58eda2321340c0ea3f5f Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Tue, 24 Mar 2020 09:54:24 +0530 Subject: [PATCH 502/809] perf dso: Fix dso comparison Perf gets dso details from two different sources. 1st, from builid headers in perf.data and 2nd from MMAP2 samples. Dso from buildid header does not have dso_id detail. And dso from MMAP2 samples does not have buildid information. If detail of the same dso is present at both the places, filename is common. Previously, __dsos__findnew_link_by_longname_id() used to compare only long or short names, but Commit 0e3149f86b99 ("perf dso: Move dso_id from 'struct map' to 'struct dso'") also added a dso_id comparison. Because of that, now perf is creating two different dso objects of the same file, one from buildid header (with dso_id but without buildid) and second from MMAP2 sample (with buildid but without dso_id). This is causing issues with archive, buildid-list etc subcommands. Fix this by comparing dso_id only when it's present. And incase dso is present in 'dsos' list without dso_id, inject dso_id detail as well. Before: $ sudo ./perf buildid-list -H 0000000000000000000000000000000000000000 /usr/bin/ls 0000000000000000000000000000000000000000 /usr/lib64/ld-2.30.so 0000000000000000000000000000000000000000 /usr/lib64/libc-2.30.so $ ./perf archive perf archive: no build-ids found After: $ ./perf buildid-list -H b6b1291d0cead046ed0fa5734037fa87a579adee /usr/bin/ls 641f0c90cfa15779352f12c0ec3c7a2b2b6f41e8 /usr/lib64/ld-2.30.so 675ace3ca07a0b863df01f461a7b0984c65c8b37 /usr/lib64/libc-2.30.so $ ./perf archive Now please run: $ tar xvf perf.data.tar.bz2 -C ~/.debug wherever you need to run 'perf report' on. Committer notes: Renamed is_empty_dso_id() to dso_id__empty() and inject_dso_id() to dso__inject_id() to keep namespacing consistent. Fixes: 0e3149f86b99 ("perf dso: Move dso_id from 'struct map' to 'struct dso'") Reported-by: Naveen N. Rao Signed-off-by: Ravi Bangoria Tested-by: Arnaldo Carvalho de Melo Tested-by: Naveen N. Rao Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Link: http://lore.kernel.org/lkml/20200324042424.68366-1-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dsos.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index 591707c69c39..939471731ea6 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -26,13 +26,29 @@ static int __dso_id__cmp(struct dso_id *a, struct dso_id *b) return 0; } +static bool dso_id__empty(struct dso_id *id) +{ + if (!id) + return true; + + return !id->maj && !id->min && !id->ino && !id->ino_generation; +} + +static void dso__inject_id(struct dso *dso, struct dso_id *id) +{ + dso->id.maj = id->maj; + dso->id.min = id->min; + dso->id.ino = id->ino; + dso->id.ino_generation = id->ino_generation; +} + static int dso_id__cmp(struct dso_id *a, struct dso_id *b) { /* * The second is always dso->id, so zeroes if not set, assume passing * NULL for a means a zeroed id */ - if (a == NULL) + if (dso_id__empty(a) || dso_id__empty(b)) return 0; return __dso_id__cmp(a, b); @@ -249,6 +265,10 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name) static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id) { struct dso *dso = __dsos__find_id(dsos, name, id, false); + + if (dso && dso_id__empty(&dso->id) && !dso_id__empty(id)) + dso__inject_id(dso, id); + return dso ? dso : __dsos__addnew_id(dsos, name, id); } From 723fe298ad85ad1278bd2312469ad14738953cc6 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 24 Mar 2020 09:26:30 -0600 Subject: [PATCH 503/809] vfio: platform: Switch to platform_get_irq_optional() Since commit 7723f4c5ecdb ("driver core: platform: Add an error message to platform_get_irq*()"), platform_get_irq() calls dev_err() on an error. As we enumerate all interrupts until platform_get_irq() fails, we now systematically get a message such as: "vfio-platform fff51000.ethernet: IRQ index 3 not found" which is a false positive. Let's use platform_get_irq_optional() instead. Signed-off-by: Eric Auger Cc: stable@vger.kernel.org # v5.3+ Reviewed-by: Andre Przywara Tested-by: Andre Przywara Signed-off-by: Alex Williamson --- drivers/vfio/platform/vfio_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c index ae1a5eb98620..1e2769010089 100644 --- a/drivers/vfio/platform/vfio_platform.c +++ b/drivers/vfio/platform/vfio_platform.c @@ -44,7 +44,7 @@ static int get_platform_irq(struct vfio_platform_device *vdev, int i) { struct platform_device *pdev = (struct platform_device *) vdev->opaque; - return platform_get_irq(pdev, i); + return platform_get_irq_optional(pdev, i); } static int vfio_platform_probe(struct platform_device *pdev) From c0560f51cf77472f4ed113539b0a02ca6cda7961 Mon Sep 17 00:00:00 2001 From: Yan Zhao Date: Tue, 24 Mar 2020 09:27:56 -0600 Subject: [PATCH 504/809] vfio: allow external user to get vfio group from device external user calls vfio_group_get_external_user_from_dev() with a device pointer to get the VFIO group associated with this device. The VFIO group is checked to be vialbe and have IOMMU set. Then container user counter is increased and VFIO group reference is hold to prevent the VFIO group from disposal before external user exits. when the external user finishes using of the VFIO group, it calls vfio_group_put_external_user() to dereference the VFIO group and the container user counter. Suggested-by: Alex Williamson Signed-off-by: Yan Zhao Signed-off-by: Alex Williamson --- drivers/vfio/vfio.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/vfio.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index c8482624ca34..97b972bfb735 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -1720,6 +1720,44 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep) } EXPORT_SYMBOL_GPL(vfio_group_get_external_user); +/** + * External user API, exported by symbols to be linked dynamically. + * The external user passes in a device pointer + * to verify that: + * - A VFIO group is assiciated with the device; + * - IOMMU is set for the group. + * If both checks passed, vfio_group_get_external_user_from_dev() + * increments the container user counter to prevent the VFIO group + * from disposal before external user exits and returns the pointer + * to the VFIO group. + * + * When the external user finishes using the VFIO group, it calls + * vfio_group_put_external_user() to release the VFIO group and + * decrement the container user counter. + * + * @dev [in] : device + * Return error PTR or pointer to VFIO group. + */ + +struct vfio_group *vfio_group_get_external_user_from_dev(struct device *dev) +{ + struct vfio_group *group; + int ret; + + group = vfio_group_get_from_dev(dev); + if (!group) + return ERR_PTR(-ENODEV); + + ret = vfio_group_add_container_user(group); + if (ret) { + vfio_group_put(group); + return ERR_PTR(ret); + } + + return group; +} +EXPORT_SYMBOL_GPL(vfio_group_get_external_user_from_dev); + void vfio_group_put_external_user(struct vfio_group *group) { vfio_group_try_dissolve_container(group); diff --git a/include/linux/vfio.h b/include/linux/vfio.h index e42a711a2800..fb71e0ac0e76 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -94,6 +94,8 @@ extern void vfio_unregister_iommu_driver( */ extern struct vfio_group *vfio_group_get_external_user(struct file *filep); extern void vfio_group_put_external_user(struct vfio_group *group); +extern struct vfio_group *vfio_group_get_external_user_from_dev(struct device + *dev); extern bool vfio_external_group_match_file(struct vfio_group *group, struct file *filep); extern int vfio_external_user_iommu_id(struct vfio_group *group); From 8d46c0cca5f4dc0538173d62cd36b1119b5105bc Mon Sep 17 00:00:00 2001 From: Yan Zhao Date: Tue, 24 Mar 2020 09:27:57 -0600 Subject: [PATCH 505/809] vfio: introduce vfio_dma_rw to read/write a range of IOVAs vfio_dma_rw will read/write a range of user space memory pointed to by IOVA into/from a kernel buffer without enforcing pinning the user space memory. TODO: mark the IOVAs to user space memory dirty if they are written in vfio_dma_rw(). Cc: Kevin Tian Signed-off-by: Yan Zhao Signed-off-by: Alex Williamson --- drivers/vfio/vfio.c | 49 +++++++++++++++++++++ drivers/vfio/vfio_iommu_type1.c | 76 +++++++++++++++++++++++++++++++++ include/linux/vfio.h | 5 +++ 3 files changed, 130 insertions(+) diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 97b972bfb735..6997f711b925 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -1999,6 +1999,55 @@ err_unpin_pages: } EXPORT_SYMBOL(vfio_unpin_pages); + +/* + * This interface allows the CPUs to perform some sort of virtual DMA on + * behalf of the device. + * + * CPUs read/write from/into a range of IOVAs pointing to user space memory + * into/from a kernel buffer. + * + * As the read/write of user space memory is conducted via the CPUs and is + * not a real device DMA, it is not necessary to pin the user space memory. + * + * The caller needs to call vfio_group_get_external_user() or + * vfio_group_get_external_user_from_dev() prior to calling this interface, + * so as to prevent the VFIO group from disposal in the middle of the call. + * But it can keep the reference to the VFIO group for several calls into + * this interface. + * After finishing using of the VFIO group, the caller needs to release the + * VFIO group by calling vfio_group_put_external_user(). + * + * @group [in] : VFIO group + * @user_iova [in] : base IOVA of a user space buffer + * @data [in] : pointer to kernel buffer + * @len [in] : kernel buffer length + * @write : indicate read or write + * Return error code on failure or 0 on success. + */ +int vfio_dma_rw(struct vfio_group *group, dma_addr_t user_iova, + void *data, size_t len, bool write) +{ + struct vfio_container *container; + struct vfio_iommu_driver *driver; + int ret = 0; + + if (!group || !data || len <= 0) + return -EINVAL; + + container = group->container; + driver = container->iommu_driver; + + if (likely(driver && driver->ops->dma_rw)) + ret = driver->ops->dma_rw(container->iommu_data, + user_iova, data, len, write); + else + ret = -ENOTTY; + + return ret; +} +EXPORT_SYMBOL(vfio_dma_rw); + static int vfio_register_iommu_notifier(struct vfio_group *group, unsigned long *events, struct notifier_block *nb) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index a177bf2c6683..9fdfae1cb17a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -2305,6 +2306,80 @@ static int vfio_iommu_type1_unregister_notifier(void *iommu_data, return blocking_notifier_chain_unregister(&iommu->notifier, nb); } +static int vfio_iommu_type1_dma_rw_chunk(struct vfio_iommu *iommu, + dma_addr_t user_iova, void *data, + size_t count, bool write, + size_t *copied) +{ + struct mm_struct *mm; + unsigned long vaddr; + struct vfio_dma *dma; + bool kthread = current->mm == NULL; + size_t offset; + + *copied = 0; + + dma = vfio_find_dma(iommu, user_iova, 1); + if (!dma) + return -EINVAL; + + if ((write && !(dma->prot & IOMMU_WRITE)) || + !(dma->prot & IOMMU_READ)) + return -EPERM; + + mm = get_task_mm(dma->task); + + if (!mm) + return -EPERM; + + if (kthread) + use_mm(mm); + else if (current->mm != mm) + goto out; + + offset = user_iova - dma->iova; + + if (count > dma->size - offset) + count = dma->size - offset; + + vaddr = dma->vaddr + offset; + + if (write) + *copied = __copy_to_user((void __user *)vaddr, data, + count) ? 0 : count; + else + *copied = __copy_from_user(data, (void __user *)vaddr, + count) ? 0 : count; + if (kthread) + unuse_mm(mm); +out: + mmput(mm); + return *copied ? 0 : -EFAULT; +} + +static int vfio_iommu_type1_dma_rw(void *iommu_data, dma_addr_t user_iova, + void *data, size_t count, bool write) +{ + struct vfio_iommu *iommu = iommu_data; + int ret = 0; + size_t done; + + mutex_lock(&iommu->lock); + while (count > 0) { + ret = vfio_iommu_type1_dma_rw_chunk(iommu, user_iova, data, + count, write, &done); + if (ret) + break; + + count -= done; + data += done; + user_iova += done; + } + + mutex_unlock(&iommu->lock); + return ret; +} + static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = { .name = "vfio-iommu-type1", .owner = THIS_MODULE, @@ -2317,6 +2392,7 @@ static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = { .unpin_pages = vfio_iommu_type1_unpin_pages, .register_notifier = vfio_iommu_type1_register_notifier, .unregister_notifier = vfio_iommu_type1_unregister_notifier, + .dma_rw = vfio_iommu_type1_dma_rw, }; static int __init vfio_iommu_type1_init(void) diff --git a/include/linux/vfio.h b/include/linux/vfio.h index fb71e0ac0e76..34b2fdf4de6e 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -82,6 +82,8 @@ struct vfio_iommu_driver_ops { struct notifier_block *nb); int (*unregister_notifier)(void *iommu_data, struct notifier_block *nb); + int (*dma_rw)(void *iommu_data, dma_addr_t user_iova, + void *data, size_t count, bool write); }; extern int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops); @@ -109,6 +111,9 @@ extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn, extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn, int npage); +extern int vfio_dma_rw(struct vfio_group *group, dma_addr_t user_iova, + void *data, size_t len, bool write); + /* each type has independent events */ enum vfio_notify_type { VFIO_IOMMU_NOTIFY = 0, From 40280cf7e8ca7d31bb0a9d626f36f458fec32815 Mon Sep 17 00:00:00 2001 From: Yan Zhao Date: Tue, 24 Mar 2020 09:27:57 -0600 Subject: [PATCH 506/809] vfio: avoid inefficient operations on VFIO group in vfio_pin/unpin_pages vfio_group_pin_pages() and vfio_group_unpin_pages() are introduced to avoid inefficient search/check/ref/deref opertions associated with VFIO group as those in each calling into vfio_pin_pages() and vfio_unpin_pages(). VFIO group is taken as arg directly. The callers combine search/check/ref/deref operations associated with VFIO group by calling vfio_group_get_external_user()/vfio_group_get_external_user_from_dev() beforehand, and vfio_group_put_external_user() afterwards. Suggested-by: Alex Williamson Signed-off-by: Yan Zhao Signed-off-by: Alex Williamson --- drivers/vfio/vfio.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/vfio.h | 6 +++ 2 files changed, 97 insertions(+) diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 6997f711b925..210fcf426643 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -1999,6 +1999,97 @@ err_unpin_pages: } EXPORT_SYMBOL(vfio_unpin_pages); +/* + * Pin a set of guest IOVA PFNs and return their associated host PFNs for a + * VFIO group. + * + * The caller needs to call vfio_group_get_external_user() or + * vfio_group_get_external_user_from_dev() prior to calling this interface, + * so as to prevent the VFIO group from disposal in the middle of the call. + * But it can keep the reference to the VFIO group for several calls into + * this interface. + * After finishing using of the VFIO group, the caller needs to release the + * VFIO group by calling vfio_group_put_external_user(). + * + * @group [in] : VFIO group + * @user_iova_pfn [in] : array of user/guest IOVA PFNs to be pinned. + * @npage [in] : count of elements in user_iova_pfn array. + * This count should not be greater + * VFIO_PIN_PAGES_MAX_ENTRIES. + * @prot [in] : protection flags + * @phys_pfn [out] : array of host PFNs + * Return error or number of pages pinned. + */ +int vfio_group_pin_pages(struct vfio_group *group, + unsigned long *user_iova_pfn, int npage, + int prot, unsigned long *phys_pfn) +{ + struct vfio_container *container; + struct vfio_iommu_driver *driver; + int ret; + + if (!group || !user_iova_pfn || !phys_pfn || !npage) + return -EINVAL; + + if (npage > VFIO_PIN_PAGES_MAX_ENTRIES) + return -E2BIG; + + container = group->container; + driver = container->iommu_driver; + if (likely(driver && driver->ops->pin_pages)) + ret = driver->ops->pin_pages(container->iommu_data, + user_iova_pfn, npage, + prot, phys_pfn); + else + ret = -ENOTTY; + + return ret; +} +EXPORT_SYMBOL(vfio_group_pin_pages); + +/* + * Unpin a set of guest IOVA PFNs for a VFIO group. + * + * The caller needs to call vfio_group_get_external_user() or + * vfio_group_get_external_user_from_dev() prior to calling this interface, + * so as to prevent the VFIO group from disposal in the middle of the call. + * But it can keep the reference to the VFIO group for several calls into + * this interface. + * After finishing using of the VFIO group, the caller needs to release the + * VFIO group by calling vfio_group_put_external_user(). + * + * @group [in] : vfio group + * @user_iova_pfn [in] : array of user/guest IOVA PFNs to be unpinned. + * @npage [in] : count of elements in user_iova_pfn array. + * This count should not be greater than + * VFIO_PIN_PAGES_MAX_ENTRIES. + * Return error or number of pages unpinned. + */ +int vfio_group_unpin_pages(struct vfio_group *group, + unsigned long *user_iova_pfn, int npage) +{ + struct vfio_container *container; + struct vfio_iommu_driver *driver; + int ret; + + if (!group || !user_iova_pfn || !npage) + return -EINVAL; + + if (npage > VFIO_PIN_PAGES_MAX_ENTRIES) + return -E2BIG; + + container = group->container; + driver = container->iommu_driver; + if (likely(driver && driver->ops->unpin_pages)) + ret = driver->ops->unpin_pages(container->iommu_data, + user_iova_pfn, npage); + else + ret = -ENOTTY; + + return ret; +} +EXPORT_SYMBOL(vfio_group_unpin_pages); + /* * This interface allows the CPUs to perform some sort of virtual DMA on diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 34b2fdf4de6e..be2bd358b952 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -111,6 +111,12 @@ extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn, extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn, int npage); +extern int vfio_group_pin_pages(struct vfio_group *group, + unsigned long *user_iova_pfn, int npage, + int prot, unsigned long *phys_pfn); +extern int vfio_group_unpin_pages(struct vfio_group *group, + unsigned long *user_iova_pfn, int npage); + extern int vfio_dma_rw(struct vfio_group *group, dma_addr_t user_iova, void *data, size_t len, bool write); From 5f3874c2a2310d9bd6969ca6764961d27a843b9d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:25 -0600 Subject: [PATCH 507/809] vfio: Include optional device match in vfio_device_ops callbacks Allow bus drivers to provide their own callback to match a device to the user provided string. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/vfio.c | 20 ++++++++++++++++---- include/linux/vfio.h | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index c8482624ca34..0bd77d6ea691 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -875,11 +875,23 @@ EXPORT_SYMBOL_GPL(vfio_device_get_from_dev); static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group, char *buf) { - struct vfio_device *it, *device = NULL; + struct vfio_device *it, *device = ERR_PTR(-ENODEV); mutex_lock(&group->device_lock); list_for_each_entry(it, &group->device_list, group_next) { - if (!strcmp(dev_name(it->dev), buf)) { + int ret; + + if (it->ops->match) { + ret = it->ops->match(it->device_data, buf); + if (ret < 0) { + device = ERR_PTR(ret); + break; + } + } else { + ret = !strcmp(dev_name(it->dev), buf); + } + + if (ret) { device = it; vfio_device_get(device); break; @@ -1430,8 +1442,8 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) return -EPERM; device = vfio_device_get_from_name(group, buf); - if (!device) - return -ENODEV; + if (IS_ERR(device)) + return PTR_ERR(device); ret = device->ops->open(device->device_data); if (ret) { diff --git a/include/linux/vfio.h b/include/linux/vfio.h index e42a711a2800..029694b977f2 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -26,6 +26,9 @@ * operations documented below * @mmap: Perform mmap(2) on a region of the device file descriptor * @request: Request for the bus driver to release the device + * @match: Optional device name match callback (return: 0 for no-match, >0 for + * match, -errno for abort (ex. match with insufficient or incorrect + * additional args) */ struct vfio_device_ops { char *name; @@ -39,6 +42,7 @@ struct vfio_device_ops { unsigned long arg); int (*mmap)(void *device_data, struct vm_area_struct *vma); void (*request)(void *device_data, unsigned int count); + int (*match)(void *device_data, char *buf); }; extern struct iommu_group *vfio_iommu_group_get(struct device *dev); From 467c084f9ad393899dc7ce527dd03ee588640ae1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:26 -0600 Subject: [PATCH 508/809] vfio/pci: Implement match ops This currently serves the same purpose as the default implementation but will be expanded for additional functionality. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 379a02c36e37..2ec6c31d0ab0 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1278,6 +1278,13 @@ static void vfio_pci_request(void *device_data, unsigned int count) mutex_unlock(&vdev->igate); } +static int vfio_pci_match(void *device_data, char *buf) +{ + struct vfio_pci_device *vdev = device_data; + + return !strcmp(pci_name(vdev->pdev), buf); +} + static const struct vfio_device_ops vfio_pci_ops = { .name = "vfio-pci", .open = vfio_pci_open, @@ -1287,6 +1294,7 @@ static const struct vfio_device_ops vfio_pci_ops = { .write = vfio_pci_write, .mmap = vfio_pci_mmap, .request = vfio_pci_request, + .match = vfio_pci_match, }; static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev); From cc20d7999000996557333910bcc99399b7244cd9 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:27 -0600 Subject: [PATCH 509/809] vfio/pci: Introduce VF token If we enable SR-IOV on a vfio-pci owned PF, the resulting VFs are not fully isolated from the PF. The PF can always cause a denial of service to the VF, even if by simply resetting itself. The degree to which a PF can access the data passed through a VF or interfere with its operation is dependent on a given SR-IOV implementation. Therefore we want to avoid a scenario where an existing vfio-pci based userspace driver might assume the PF driver is trusted, for example assigning a PF to one VM and VF to another with some expectation of isolation. IOMMU grouping could be a solution to this, but imposes an unnecessarily strong relationship between PF and VF drivers if they need to operate with the same IOMMU context. Instead we introduce a "VF token", which is essentially just a shared secret between PF and VF drivers, implemented as a UUID. The VF token can be set by a vfio-pci based PF driver and must be known by the vfio-pci based VF driver in order to gain access to the device. This allows the degree to which this VF token is considered secret to be determined by the applications and environment. For example a VM might generate a random UUID known only internally to the hypervisor while a userspace networking appliance might use a shared, or even well know, UUID among the application drivers. To incorporate this VF token, the VFIO_GROUP_GET_DEVICE_FD interface is extended to accept key=value pairs in addition to the device name. This allows us to most easily deny user access to the device without risk that existing userspace drivers assume region offsets, IRQs, and other device features, leading to more elaborate error paths. The format of these options are expected to take the form: "$DEVICE_NAME $OPTION1=$VALUE1 $OPTION2=$VALUE2" Where the device name is always provided first for compatibility and additional options are specified in a space separated list. The relation between and requirements for the additional options will be vfio bus driver dependent, however unknown or unused option within this schema should return error. This allow for future use of unknown options as well as a positive indication to the user that an option is used. An example VF token option would take this form: "0000:03:00.0 vf_token=2ab74924-c335-45f4-9b16-8569e5b08258" When accessing a VF where the PF is making use of vfio-pci, the user MUST provide the current vf_token. When accessing a PF, the user MUST provide the current vf_token IF there are active VF users or MAY provide a vf_token in order to set the current VF token when no VF users are active. The former requirement assures VF users that an unassociated driver cannot usurp the PF device. These semantics also imply that a VF token MUST be set by a PF driver before VF drivers can access their device, the default token is random and mechanisms to read the token are not provided in order to protect the VF token of previous users. Use of the vf_token option outside of these cases will return an error, as discussed above. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 198 +++++++++++++++++++++++++++- drivers/vfio/pci/vfio_pci_private.h | 8 ++ 2 files changed, 205 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 2ec6c31d0ab0..5277c6c2fa72 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -466,6 +466,44 @@ out: vfio_pci_set_power_state(vdev, PCI_D3hot); } +static struct pci_driver vfio_pci_driver; + +static struct vfio_pci_device *get_pf_vdev(struct vfio_pci_device *vdev, + struct vfio_device **pf_dev) +{ + struct pci_dev *physfn = pci_physfn(vdev->pdev); + + if (!vdev->pdev->is_virtfn) + return NULL; + + *pf_dev = vfio_device_get_from_dev(&physfn->dev); + if (!*pf_dev) + return NULL; + + if (pci_dev_driver(physfn) != &vfio_pci_driver) { + vfio_device_put(*pf_dev); + return NULL; + } + + return vfio_device_data(*pf_dev); +} + +static void vfio_pci_vf_token_user_add(struct vfio_pci_device *vdev, int val) +{ + struct vfio_device *pf_dev; + struct vfio_pci_device *pf_vdev = get_pf_vdev(vdev, &pf_dev); + + if (!pf_vdev) + return; + + mutex_lock(&pf_vdev->vf_token->lock); + pf_vdev->vf_token->users += val; + WARN_ON(pf_vdev->vf_token->users < 0); + mutex_unlock(&pf_vdev->vf_token->lock); + + vfio_device_put(pf_dev); +} + static void vfio_pci_release(void *device_data) { struct vfio_pci_device *vdev = device_data; @@ -473,6 +511,7 @@ static void vfio_pci_release(void *device_data) mutex_lock(&vdev->reflck->lock); if (!(--vdev->refcnt)) { + vfio_pci_vf_token_user_add(vdev, -1); vfio_spapr_pci_eeh_release(vdev->pdev); vfio_pci_disable(vdev); } @@ -498,6 +537,7 @@ static int vfio_pci_open(void *device_data) goto error; vfio_spapr_pci_eeh_open(vdev->pdev); + vfio_pci_vf_token_user_add(vdev, 1); } vdev->refcnt++; error: @@ -1278,11 +1318,148 @@ static void vfio_pci_request(void *device_data, unsigned int count) mutex_unlock(&vdev->igate); } +static int vfio_pci_validate_vf_token(struct vfio_pci_device *vdev, + bool vf_token, uuid_t *uuid) +{ + /* + * There's always some degree of trust or collaboration between SR-IOV + * PF and VFs, even if just that the PF hosts the SR-IOV capability and + * can disrupt VFs with a reset, but often the PF has more explicit + * access to deny service to the VF or access data passed through the + * VF. We therefore require an opt-in via a shared VF token (UUID) to + * represent this trust. This both prevents that a VF driver might + * assume the PF driver is a trusted, in-kernel driver, and also that + * a PF driver might be replaced with a rogue driver, unknown to in-use + * VF drivers. + * + * Therefore when presented with a VF, if the PF is a vfio device and + * it is bound to the vfio-pci driver, the user needs to provide a VF + * token to access the device, in the form of appending a vf_token to + * the device name, for example: + * + * "0000:04:10.0 vf_token=bd8d9d2b-5a5f-4f5a-a211-f591514ba1f3" + * + * When presented with a PF which has VFs in use, the user must also + * provide the current VF token to prove collaboration with existing + * VF users. If VFs are not in use, the VF token provided for the PF + * device will act to set the VF token. + * + * If the VF token is provided but unused, an error is generated. + */ + if (!vdev->pdev->is_virtfn && !vdev->vf_token && !vf_token) + return 0; /* No VF token provided or required */ + + if (vdev->pdev->is_virtfn) { + struct vfio_device *pf_dev; + struct vfio_pci_device *pf_vdev = get_pf_vdev(vdev, &pf_dev); + bool match; + + if (!pf_vdev) { + if (!vf_token) + return 0; /* PF is not vfio-pci, no VF token */ + + pci_info_ratelimited(vdev->pdev, + "VF token incorrectly provided, PF not bound to vfio-pci\n"); + return -EINVAL; + } + + if (!vf_token) { + vfio_device_put(pf_dev); + pci_info_ratelimited(vdev->pdev, + "VF token required to access device\n"); + return -EACCES; + } + + mutex_lock(&pf_vdev->vf_token->lock); + match = uuid_equal(uuid, &pf_vdev->vf_token->uuid); + mutex_unlock(&pf_vdev->vf_token->lock); + + vfio_device_put(pf_dev); + + if (!match) { + pci_info_ratelimited(vdev->pdev, + "Incorrect VF token provided for device\n"); + return -EACCES; + } + } else if (vdev->vf_token) { + mutex_lock(&vdev->vf_token->lock); + if (vdev->vf_token->users) { + if (!vf_token) { + mutex_unlock(&vdev->vf_token->lock); + pci_info_ratelimited(vdev->pdev, + "VF token required to access device\n"); + return -EACCES; + } + + if (!uuid_equal(uuid, &vdev->vf_token->uuid)) { + mutex_unlock(&vdev->vf_token->lock); + pci_info_ratelimited(vdev->pdev, + "Incorrect VF token provided for device\n"); + return -EACCES; + } + } else if (vf_token) { + uuid_copy(&vdev->vf_token->uuid, uuid); + } + + mutex_unlock(&vdev->vf_token->lock); + } else if (vf_token) { + pci_info_ratelimited(vdev->pdev, + "VF token incorrectly provided, not a PF or VF\n"); + return -EINVAL; + } + + return 0; +} + +#define VF_TOKEN_ARG "vf_token=" + static int vfio_pci_match(void *device_data, char *buf) { struct vfio_pci_device *vdev = device_data; + bool vf_token = false; + uuid_t uuid; + int ret; - return !strcmp(pci_name(vdev->pdev), buf); + if (strncmp(pci_name(vdev->pdev), buf, strlen(pci_name(vdev->pdev)))) + return 0; /* No match */ + + if (strlen(buf) > strlen(pci_name(vdev->pdev))) { + buf += strlen(pci_name(vdev->pdev)); + + if (*buf != ' ') + return 0; /* No match: non-whitespace after name */ + + while (*buf) { + if (*buf == ' ') { + buf++; + continue; + } + + if (!vf_token && !strncmp(buf, VF_TOKEN_ARG, + strlen(VF_TOKEN_ARG))) { + buf += strlen(VF_TOKEN_ARG); + + if (strlen(buf) < UUID_STRING_LEN) + return -EINVAL; + + ret = uuid_parse(buf, &uuid); + if (ret) + return ret; + + vf_token = true; + buf += UUID_STRING_LEN; + } else { + /* Unknown/duplicate option */ + return -EINVAL; + } + } + } + + ret = vfio_pci_validate_vf_token(vdev, vf_token, &uuid); + if (ret) + return ret; + + return 1; /* Match */ } static const struct vfio_device_ops vfio_pci_ops = { @@ -1354,6 +1531,19 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } + if (pdev->is_physfn) { + vdev->vf_token = kzalloc(sizeof(*vdev->vf_token), GFP_KERNEL); + if (!vdev->vf_token) { + vfio_pci_reflck_put(vdev->reflck); + vfio_del_group_dev(&pdev->dev); + vfio_iommu_group_put(group, &pdev->dev); + kfree(vdev); + return -ENOMEM; + } + mutex_init(&vdev->vf_token->lock); + uuid_gen(&vdev->vf_token->uuid); + } + if (vfio_pci_is_vga(pdev)) { vga_client_register(pdev, vdev, NULL, vfio_pci_set_vga_decode); vga_set_legacy_decoding(pdev, @@ -1387,6 +1577,12 @@ static void vfio_pci_remove(struct pci_dev *pdev) if (!vdev) return; + if (vdev->vf_token) { + WARN_ON(vdev->vf_token->users); + mutex_destroy(&vdev->vf_token->lock); + kfree(vdev->vf_token); + } + vfio_pci_reflck_put(vdev->reflck); vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index 8a2c7607d513..76c11c915949 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifndef VFIO_PCI_PRIVATE_H #define VFIO_PCI_PRIVATE_H @@ -84,6 +85,12 @@ struct vfio_pci_reflck { struct mutex lock; }; +struct vfio_pci_vf_token { + struct mutex lock; + uuid_t uuid; + int users; +}; + struct vfio_pci_device { struct pci_dev *pdev; void __iomem *barmap[PCI_STD_NUM_BARS]; @@ -122,6 +129,7 @@ struct vfio_pci_device { struct list_head dummy_resources_list; struct mutex ioeventfds_lock; struct list_head ioeventfds_list; + struct vfio_pci_vf_token *vf_token; }; #define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX) From 43eeeecc8ed5fa05652d68032a8bfb1308ee9baa Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:27 -0600 Subject: [PATCH 510/809] vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user The VFIO_DEVICE_FEATURE ioctl is meant to be a general purpose, device agnostic ioctl for setting, retrieving, and probing device features. This implementation provides a 16-bit field for specifying a feature index, where the data porition of the ioctl is determined by the semantics for the given feature. Additional flag bits indicate the direction and nature of the operation; SET indicates user data is provided into the device feature, GET indicates the device feature is written out into user data. The PROBE flag augments determining whether the given feature is supported, and if provided, whether the given operation on the feature is supported. The first user of this ioctl is for setting the vfio-pci VF token, where the user provides a shared secret key (UUID) on a SR-IOV PF device, which users must provide when opening associated VF devices. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 59 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/vfio.h | 37 +++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 5277c6c2fa72..6c28860f768a 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1180,6 +1180,65 @@ hot_reset_release: return vfio_pci_ioeventfd(vdev, ioeventfd.offset, ioeventfd.data, count, ioeventfd.fd); + } else if (cmd == VFIO_DEVICE_FEATURE) { + struct vfio_device_feature feature; + uuid_t uuid; + + minsz = offsetofend(struct vfio_device_feature, flags); + + if (copy_from_user(&feature, (void __user *)arg, minsz)) + return -EFAULT; + + if (feature.argsz < minsz) + return -EINVAL; + + /* Check unknown flags */ + if (feature.flags & ~(VFIO_DEVICE_FEATURE_MASK | + VFIO_DEVICE_FEATURE_SET | + VFIO_DEVICE_FEATURE_GET | + VFIO_DEVICE_FEATURE_PROBE)) + return -EINVAL; + + /* GET & SET are mutually exclusive except with PROBE */ + if (!(feature.flags & VFIO_DEVICE_FEATURE_PROBE) && + (feature.flags & VFIO_DEVICE_FEATURE_SET) && + (feature.flags & VFIO_DEVICE_FEATURE_GET)) + return -EINVAL; + + switch (feature.flags & VFIO_DEVICE_FEATURE_MASK) { + case VFIO_DEVICE_FEATURE_PCI_VF_TOKEN: + if (!vdev->vf_token) + return -ENOTTY; + + /* + * We do not support GET of the VF Token UUID as this + * could expose the token of the previous device user. + */ + if (feature.flags & VFIO_DEVICE_FEATURE_GET) + return -EINVAL; + + if (feature.flags & VFIO_DEVICE_FEATURE_PROBE) + return 0; + + /* Don't SET unless told to do so */ + if (!(feature.flags & VFIO_DEVICE_FEATURE_SET)) + return -EINVAL; + + if (feature.argsz < minsz + sizeof(uuid)) + return -EINVAL; + + if (copy_from_user(&uuid, (void __user *)(arg + minsz), + sizeof(uuid))) + return -EFAULT; + + mutex_lock(&vdev->vf_token->lock); + uuid_copy(&vdev->vf_token->uuid, &uuid); + mutex_unlock(&vdev->vf_token->lock); + + return 0; + default: + return -ENOTTY; + } } return -ENOTTY; diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 9e843a147ead..015516bcfaa3 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -707,6 +707,43 @@ struct vfio_device_ioeventfd { #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) +/** + * VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17, + * struct vfio_device_feature) + * + * Get, set, or probe feature data of the device. The feature is selected + * using the FEATURE_MASK portion of the flags field. Support for a feature + * can be probed by setting both the FEATURE_MASK and PROBE bits. A probe + * may optionally include the GET and/or SET bits to determine read vs write + * access of the feature respectively. Probing a feature will return success + * if the feature is supported and all of the optionally indicated GET/SET + * methods are supported. The format of the data portion of the structure is + * specific to the given feature. The data portion is not required for + * probing. GET and SET are mutually exclusive, except for use with PROBE. + * + * Return 0 on success, -errno on failure. + */ +struct vfio_device_feature { + __u32 argsz; + __u32 flags; +#define VFIO_DEVICE_FEATURE_MASK (0xffff) /* 16-bit feature index */ +#define VFIO_DEVICE_FEATURE_GET (1 << 16) /* Get feature into data[] */ +#define VFIO_DEVICE_FEATURE_SET (1 << 17) /* Set feature from data[] */ +#define VFIO_DEVICE_FEATURE_PROBE (1 << 18) /* Probe feature support */ + __u8 data[]; +}; + +#define VFIO_DEVICE_FEATURE _IO(VFIO_TYPE, VFIO_BASE + 17) + +/* + * Provide support for setting a PCI VF Token, which is used as a shared + * secret between PF and VF drivers. This feature may only be set on a + * PCI SR-IOV PF when SR-IOV is enabled on the PF and there are no existing + * open VFs. Data provided when setting this feature is a 16-byte array + * (__u8 b[16]), representing a UUID. + */ +#define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) + /* -------- API for Type1 VFIO IOMMU -------- */ /** From 137e5531351db258eff58ea28f4dc8fdf7ca2990 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:28 -0600 Subject: [PATCH 511/809] vfio/pci: Add sriov_configure support With the VF Token interface we can now expect that a vfio userspace driver must be in collaboration with the PF driver, an unwitting userspace driver will not be able to get past the GET_DEVICE_FD step in accessing the device. We can now move on to actually allowing SR-IOV to be enabled by vfio-pci on the PF. Support for this is not enabled by default in this commit, but it does provide a module option for this to be enabled (enable_sriov=1). Enabling VFs is rather straightforward, except we don't want to risk that a VF might get autoprobed and bound to other drivers, so a bus notifier is used to "capture" VFs to vfio-pci using the driver_override support. We assume any later action to bind the device to other drivers is condoned by the system admin and allow it with a log warning. vfio-pci will disable SR-IOV on a PF before releasing the device, allowing a VF driver to be assured other drivers cannot take over the PF and that any other userspace driver must know the shared VF token. This support also does not provide a mechanism for the PF userspace driver itself to manipulate SR-IOV through the vfio API. With this patch SR-IOV can only be enabled via the host sysfs interface and the PF driver user cannot create or remove VFs. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 106 +++++++++++++++++++++++++--- drivers/vfio/pci/vfio_pci_private.h | 2 + 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 6c28860f768a..df6bae75c8dd 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -54,6 +54,12 @@ module_param(disable_idle_d3, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(disable_idle_d3, "Disable using the PCI D3 low power state for idle, unused devices"); +static bool enable_sriov; +#ifdef CONFIG_PCI_IOV +module_param(enable_sriov, bool, 0644); +MODULE_PARM_DESC(enable_sriov, "Enable support for SR-IOV configuration. Enabling SR-IOV on a PF typically requires support of the userspace PF driver, enabling VFs without such support may result in non-functional VFs or PF."); +#endif + static inline bool vfio_vga_disabled(void) { #ifdef CONFIG_VFIO_PCI_VGA @@ -1535,6 +1541,35 @@ static const struct vfio_device_ops vfio_pci_ops = { static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev); static void vfio_pci_reflck_put(struct vfio_pci_reflck *reflck); +static struct pci_driver vfio_pci_driver; + +static int vfio_pci_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct vfio_pci_device *vdev = container_of(nb, + struct vfio_pci_device, nb); + struct device *dev = data; + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev *physfn = pci_physfn(pdev); + + if (action == BUS_NOTIFY_ADD_DEVICE && + pdev->is_virtfn && physfn == vdev->pdev) { + pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n", + pci_name(pdev)); + pdev->driver_override = kasprintf(GFP_KERNEL, "%s", + vfio_pci_ops.name); + } else if (action == BUS_NOTIFY_BOUND_DRIVER && + pdev->is_virtfn && physfn == vdev->pdev) { + struct pci_driver *drv = pci_dev_driver(pdev); + + if (drv && drv != &vfio_pci_driver) + pci_warn(vdev->pdev, + "VF %s bound to driver %s while PF bound to vfio-pci\n", + pci_name(pdev), drv->name); + } + + return 0; +} static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1546,12 +1581,12 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -EINVAL; /* - * Prevent binding to PFs with VFs enabled, this too easily allows - * userspace instance with VFs and PFs from the same device, which - * cannot work. Disabling SR-IOV here would initiate removing the - * VFs, which would unbind the driver, which is prone to blocking - * if that VF is also in use by vfio-pci. Just reject these PFs - * and let the user sort it out. + * Prevent binding to PFs with VFs enabled, the VFs might be in use + * by the host or other users. We cannot capture the VFs if they + * already exist, nor can we track VF users. Disabling SR-IOV here + * would initiate removing the VFs, which would unbind the driver, + * which is prone to blocking if that VF is also in use by vfio-pci. + * Just reject these PFs and let the user sort it out. */ if (pci_num_vf(pdev)) { pci_warn(pdev, "Cannot bind to PF with SR-IOV enabled\n"); @@ -1599,6 +1634,18 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) kfree(vdev); return -ENOMEM; } + + vdev->nb.notifier_call = vfio_pci_bus_notifier; + ret = bus_register_notifier(&pci_bus_type, &vdev->nb); + if (ret) { + kfree(vdev->vf_token); + vfio_pci_reflck_put(vdev->reflck); + vfio_del_group_dev(&pdev->dev); + vfio_iommu_group_put(group, &pdev->dev); + kfree(vdev); + return ret; + } + mutex_init(&vdev->vf_token->lock); uuid_gen(&vdev->vf_token->uuid); } @@ -1632,6 +1679,8 @@ static void vfio_pci_remove(struct pci_dev *pdev) { struct vfio_pci_device *vdev; + pci_disable_sriov(pdev); + vdev = vfio_del_group_dev(&pdev->dev); if (!vdev) return; @@ -1642,6 +1691,9 @@ static void vfio_pci_remove(struct pci_dev *pdev) kfree(vdev->vf_token); } + if (vdev->nb.notifier_call) + bus_unregister_notifier(&pci_bus_type, &vdev->nb); + vfio_pci_reflck_put(vdev->reflck); vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); @@ -1690,16 +1742,48 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_CAN_RECOVER; } +static int vfio_pci_sriov_configure(struct pci_dev *pdev, int nr_virtfn) +{ + struct vfio_pci_device *vdev; + struct vfio_device *device; + int ret = 0; + + might_sleep(); + + if (!enable_sriov) + return -ENOENT; + + device = vfio_device_get_from_dev(&pdev->dev); + if (!device) + return -ENODEV; + + vdev = vfio_device_data(device); + if (!vdev) { + vfio_device_put(device); + return -ENODEV; + } + + if (nr_virtfn == 0) + pci_disable_sriov(pdev); + else + ret = pci_enable_sriov(pdev, nr_virtfn); + + vfio_device_put(device); + + return ret < 0 ? ret : nr_virtfn; +} + static const struct pci_error_handlers vfio_err_handlers = { .error_detected = vfio_pci_aer_err_detected, }; static struct pci_driver vfio_pci_driver = { - .name = "vfio-pci", - .id_table = NULL, /* only dynamic ids */ - .probe = vfio_pci_probe, - .remove = vfio_pci_remove, - .err_handler = &vfio_err_handlers, + .name = "vfio-pci", + .id_table = NULL, /* only dynamic ids */ + .probe = vfio_pci_probe, + .remove = vfio_pci_remove, + .sriov_configure = vfio_pci_sriov_configure, + .err_handler = &vfio_err_handlers, }; static DEFINE_MUTEX(reflck_lock); diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index 76c11c915949..36ec69081ecd 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifndef VFIO_PCI_PRIVATE_H #define VFIO_PCI_PRIVATE_H @@ -130,6 +131,7 @@ struct vfio_pci_device { struct mutex ioeventfds_lock; struct list_head ioeventfds_list; struct vfio_pci_vf_token *vf_token; + struct notifier_block nb; }; #define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX) From 959e1b75cc87e5215622d8344d9d6ede8666480e Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:29 -0600 Subject: [PATCH 512/809] vfio/pci: Remove dev_fmt definition It currently results in messages like: "vfio-pci 0000:03:00.0: vfio_pci: ..." Which is quite a bit redundant. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index df6bae75c8dd..af1ba9867201 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -9,7 +9,6 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define dev_fmt pr_fmt #include #include From b66574a3fb32e2bac5bf3589dae6d335b7a70689 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 24 Mar 2020 09:28:29 -0600 Subject: [PATCH 513/809] vfio/pci: Cleanup .probe() exit paths The cleanup is getting a tad long. Reviewed-by: Cornelia Huck Reviewed-by: Kevin Tian Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci.c | 54 +++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index af1ba9867201..6c6b37b5c04e 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1598,8 +1598,8 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); if (!vdev) { - vfio_iommu_group_put(group, &pdev->dev); - return -ENOMEM; + ret = -ENOMEM; + goto out_group_put; } vdev->pdev = pdev; @@ -1610,43 +1610,27 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&vdev->ioeventfds_list); ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); - if (ret) { - vfio_iommu_group_put(group, &pdev->dev); - kfree(vdev); - return ret; - } + if (ret) + goto out_free; ret = vfio_pci_reflck_attach(vdev); - if (ret) { - vfio_del_group_dev(&pdev->dev); - vfio_iommu_group_put(group, &pdev->dev); - kfree(vdev); - return ret; - } + if (ret) + goto out_del_group_dev; if (pdev->is_physfn) { vdev->vf_token = kzalloc(sizeof(*vdev->vf_token), GFP_KERNEL); if (!vdev->vf_token) { - vfio_pci_reflck_put(vdev->reflck); - vfio_del_group_dev(&pdev->dev); - vfio_iommu_group_put(group, &pdev->dev); - kfree(vdev); - return -ENOMEM; - } - - vdev->nb.notifier_call = vfio_pci_bus_notifier; - ret = bus_register_notifier(&pci_bus_type, &vdev->nb); - if (ret) { - kfree(vdev->vf_token); - vfio_pci_reflck_put(vdev->reflck); - vfio_del_group_dev(&pdev->dev); - vfio_iommu_group_put(group, &pdev->dev); - kfree(vdev); - return ret; + ret = -ENOMEM; + goto out_reflck; } mutex_init(&vdev->vf_token->lock); uuid_gen(&vdev->vf_token->uuid); + + vdev->nb.notifier_call = vfio_pci_bus_notifier; + ret = bus_register_notifier(&pci_bus_type, &vdev->nb); + if (ret) + goto out_vf_token; } if (vfio_pci_is_vga(pdev)) { @@ -1672,6 +1656,18 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } return ret; + +out_vf_token: + kfree(vdev->vf_token); +out_reflck: + vfio_pci_reflck_put(vdev->reflck); +out_del_group_dev: + vfio_del_group_dev(&pdev->dev); +out_free: + kfree(vdev); +out_group_put: + vfio_iommu_group_put(group, &pdev->dev); + return ret; } static void vfio_pci_remove(struct pci_dev *pdev) From f05a3849f6449f67843113778bf56e02f2b4ddf8 Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:46:48 +0100 Subject: [PATCH 514/809] fs: Constify vma argument to vma_is_dax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is used by upcoming vma_is_special_huge() with which we want to use a const vma argument. Since for vma_is_dax() the vma argument is only dereferenced for reading, constify it. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Acked-by: Christian König --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 3cd4fe6b845e..2b38ce5b73ad 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3391,7 +3391,7 @@ static inline bool io_is_direct(struct file *filp) return (filp->f_flags & O_DIRECT) || IS_DAX(filp->f_mapping->host); } -static inline bool vma_is_dax(struct vm_area_struct *vma) +static inline bool vma_is_dax(const struct vm_area_struct *vma) { return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); } From 2484ca9b6a20451debb789d0a89af6f15de99826 Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:47:17 +0100 Subject: [PATCH 515/809] mm: Introduce vma_is_special_huge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For VM_PFNMAP and VM_MIXEDMAP vmas that want to support transhuge pages and -page table entries, introduce vma_is_special_huge() that takes the same codepaths as vma_is_dax(). The use of "special" follows the definition in memory.c, vm_normal_page(): "Special" mappings do not wish to be associated with a "struct page" (either it doesn't exist, or it exists but they don't want to touch it) For PAGE_SIZE pages, "special" is determined per page table entry to be able to deal with COW pages. But since we don't have huge COW pages, we can classify a vma as either "special huge" or "normal huge". Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Acked-by: Christian König Acked-by: Andrew Morton --- include/linux/mm.h | 17 +++++++++++++++++ mm/huge_memory.c | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index c54fb96cb1e6..bdd79a72bb42 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2867,6 +2867,23 @@ extern long copy_huge_page_from_user(struct page *dst_page, const void __user *usr_src, unsigned int pages_per_huge_page, bool allow_pagefault); + +/** + * vma_is_special_huge - Are transhuge page-table entries considered special? + * @vma: Pointer to the struct vm_area_struct to consider + * + * Whether transhuge page-table entries are considered "special" following + * the definition in vm_normal_page(). + * + * Return: true if transhuge page-table entries should be considered special, + * false otherwise. + */ +static inline bool vma_is_special_huge(const struct vm_area_struct *vma) +{ + return vma_is_dax(vma) || (vma->vm_file && + (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))); +} + #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */ #ifdef CONFIG_DEBUG_PAGEALLOC diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 24ad53b4dfc0..19c8d462ab08 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1802,7 +1802,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd, tlb->fullmm); tlb_remove_pmd_tlb_entry(tlb, pmd, addr); - if (vma_is_dax(vma)) { + if (vma_is_special_huge(vma)) { if (arch_needs_pgtable_deposit()) zap_deposited_table(tlb->mm, pmd); spin_unlock(ptl); @@ -2066,7 +2066,7 @@ int zap_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma, */ pudp_huge_get_and_clear_full(tlb->mm, addr, pud, tlb->fullmm); tlb_remove_pud_tlb_entry(tlb, pud, addr); - if (vma_is_dax(vma)) { + if (vma_is_special_huge(vma)) { spin_unlock(ptl); /* No zero page support yet */ } else { @@ -2175,7 +2175,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, */ if (arch_needs_pgtable_deposit()) zap_deposited_table(mm, pmd); - if (vma_is_dax(vma)) + if (vma_is_special_huge(vma)) return; page = pmd_page(_pmd); if (!PageDirty(page) && pmd_dirty(_pmd)) From 327e9fd489727aa83e13c80ae517f46cdbe8979e Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:47:47 +0100 Subject: [PATCH 516/809] mm: Split huge pages on write-notify or COW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions wp_huge_pmd() and wp_huge_pud() currently relies on the huge_fault() callback to split huge page table entries if needed. However for module users that requires export of the split_huge_xxx() functionality which may be undesired. Instead split pre-existing huge page-table entries on VM_FAULT_FALLBACK return. We currently only do COW and write-notify on the PTE level, so if the huge_fault() handler returns VM_FAULT_FALLBACK on wp faults, split the huge pages and page-table entries. Also do this for huge PUDs if there is no huge_fault() handler and the vma is not anonymous, similar to how it's done for PMDs. Note that fs/dax.c still does the splitting in the huge_fault() handler, but as huge_fault() A follow-up patch can remove the dax.c split_huge_pmd() if needed. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Acked-by: Christian König Acked-by: Andrew Morton --- mm/memory.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index e8bfdf0d9d1d..efa59b1b109c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3951,11 +3951,14 @@ static inline vm_fault_t wp_huge_pmd(struct vm_fault *vmf, pmd_t orig_pmd) { if (vma_is_anonymous(vmf->vma)) return do_huge_pmd_wp_page(vmf, orig_pmd); - if (vmf->vma->vm_ops->huge_fault) - return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PMD); + if (vmf->vma->vm_ops->huge_fault) { + vm_fault_t ret = vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PMD); - /* COW handled on pte level: split pmd */ - VM_BUG_ON_VMA(vmf->vma->vm_flags & VM_SHARED, vmf->vma); + if (!(ret & VM_FAULT_FALLBACK)) + return ret; + } + + /* COW or write-notify handled on pte level: split pmd. */ __split_huge_pmd(vmf->vma, vmf->pmd, vmf->address, false, NULL); return VM_FAULT_FALLBACK; @@ -3968,12 +3971,20 @@ static inline bool vma_is_accessible(struct vm_area_struct *vma) static vm_fault_t create_huge_pud(struct vm_fault *vmf) { -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && \ + defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD) /* No support for anonymous transparent PUD pages yet */ if (vma_is_anonymous(vmf->vma)) - return VM_FAULT_FALLBACK; - if (vmf->vma->vm_ops->huge_fault) - return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD); + goto split; + if (vmf->vma->vm_ops->huge_fault) { + vm_fault_t ret = vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD); + + if (!(ret & VM_FAULT_FALLBACK)) + return ret; + } +split: + /* COW or write-notify not handled on PUD level: split pud.*/ + __split_huge_pud(vmf->vma, vmf->pud, vmf->address); #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ return VM_FAULT_FALLBACK; } From 9a9731b18c9bb70c023f0b2c731726fd5167673e Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:48:09 +0100 Subject: [PATCH 517/809] mm: Add vmf_insert_pfn_xxx_prot() for huge page-table entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For graphics drivers needing to modify the page-protection, add huge page-table entries counterparts to vmf_insert_pfn_prot(). Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Acked-by: Christian König Acked-by: Andrew Morton --- include/linux/huge_mm.h | 41 +++++++++++++++++++++++++++++++++++++++-- mm/huge_memory.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 5aca3d1bdb32..f63b0882c1b3 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -47,8 +47,45 @@ extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr, extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, pgprot_t newprot, int prot_numa); -vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write); -vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write); +vm_fault_t vmf_insert_pfn_pmd_prot(struct vm_fault *vmf, pfn_t pfn, + pgprot_t pgprot, bool write); + +/** + * vmf_insert_pfn_pmd - insert a pmd size pfn + * @vmf: Structure describing the fault + * @pfn: pfn to insert + * @pgprot: page protection to use + * @write: whether it's a write fault + * + * Insert a pmd size pfn. See vmf_insert_pfn() for additional info. + * + * Return: vm_fault_t value. + */ +static inline vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, + bool write) +{ + return vmf_insert_pfn_pmd_prot(vmf, pfn, vmf->vma->vm_page_prot, write); +} +vm_fault_t vmf_insert_pfn_pud_prot(struct vm_fault *vmf, pfn_t pfn, + pgprot_t pgprot, bool write); + +/** + * vmf_insert_pfn_pud - insert a pud size pfn + * @vmf: Structure describing the fault + * @pfn: pfn to insert + * @pgprot: page protection to use + * @write: whether it's a write fault + * + * Insert a pud size pfn. See vmf_insert_pfn() for additional info. + * + * Return: vm_fault_t value. + */ +static inline vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, + bool write) +{ + return vmf_insert_pfn_pud_prot(vmf, pfn, vmf->vma->vm_page_prot, write); +} + enum transparent_hugepage_flag { TRANSPARENT_HUGEPAGE_FLAG, TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 19c8d462ab08..4036d5e0a6f3 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -824,11 +824,24 @@ out_unlock: pte_free(mm, pgtable); } -vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write) +/** + * vmf_insert_pfn_pmd_prot - insert a pmd size pfn + * @vmf: Structure describing the fault + * @pfn: pfn to insert + * @pgprot: page protection to use + * @write: whether it's a write fault + * + * Insert a pmd size pfn. See vmf_insert_pfn() for additional info and + * also consult the vmf_insert_mixed_prot() documentation when + * @pgprot != @vmf->vma->vm_page_prot. + * + * Return: vm_fault_t value. + */ +vm_fault_t vmf_insert_pfn_pmd_prot(struct vm_fault *vmf, pfn_t pfn, + pgprot_t pgprot, bool write) { unsigned long addr = vmf->address & PMD_MASK; struct vm_area_struct *vma = vmf->vma; - pgprot_t pgprot = vma->vm_page_prot; pgtable_t pgtable = NULL; /* @@ -856,7 +869,7 @@ vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write) insert_pfn_pmd(vma, addr, vmf->pmd, pfn, pgprot, write, pgtable); return VM_FAULT_NOPAGE; } -EXPORT_SYMBOL_GPL(vmf_insert_pfn_pmd); +EXPORT_SYMBOL_GPL(vmf_insert_pfn_pmd_prot); #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD static pud_t maybe_pud_mkwrite(pud_t pud, struct vm_area_struct *vma) @@ -902,11 +915,24 @@ out_unlock: spin_unlock(ptl); } -vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write) +/** + * vmf_insert_pfn_pud_prot - insert a pud size pfn + * @vmf: Structure describing the fault + * @pfn: pfn to insert + * @pgprot: page protection to use + * @write: whether it's a write fault + * + * Insert a pud size pfn. See vmf_insert_pfn() for additional info and + * also consult the vmf_insert_mixed_prot() documentation when + * @pgprot != @vmf->vma->vm_page_prot. + * + * Return: vm_fault_t value. + */ +vm_fault_t vmf_insert_pfn_pud_prot(struct vm_fault *vmf, pfn_t pfn, + pgprot_t pgprot, bool write) { unsigned long addr = vmf->address & PUD_MASK; struct vm_area_struct *vma = vmf->vma; - pgprot_t pgprot = vma->vm_page_prot; /* * If we had pud_special, we could avoid all these restrictions, @@ -927,7 +953,7 @@ vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write) insert_pfn_pud(vma, addr, vmf->pud, pfn, pgprot, write); return VM_FAULT_NOPAGE; } -EXPORT_SYMBOL_GPL(vmf_insert_pfn_pud); +EXPORT_SYMBOL_GPL(vmf_insert_pfn_pud_prot); #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ static void touch_pmd(struct vm_area_struct *vma, unsigned long addr, From 314b6580adc543cf21a1a84bce9c6a58a8dcb38c Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:48:33 +0100 Subject: [PATCH 518/809] drm/ttm, drm/vmwgfx: Support huge TTM pagefaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support huge (PMD-size and PUD-size) page-table entries by providing a huge_fault() callback. We still support private mappings and write-notify by splitting the huge page-table entries on write-access. Note that for huge page-faults to occur, either the kernel needs to be compiled with trans-huge-pages always enabled, or the kernel needs to be compiled with trans-huge-pages enabled using madvise, and the user-space app needs to call madvise() to enable trans-huge pages on a per-mapping basis. Furthermore huge page-faults will not succeed unless buffer objects and user-space addresses are aligned on huge page size boundaries. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Reviewed-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 161 ++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 2 +- include/drm/ttm/ttm_bo_api.h | 3 +- 3 files changed, 161 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 389128b8c4dd..0af14835504c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -156,6 +156,89 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, } EXPORT_SYMBOL(ttm_bo_vm_reserve); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/** + * ttm_bo_vm_insert_huge - Insert a pfn for PUD or PMD faults + * @vmf: Fault data + * @bo: The buffer object + * @page_offset: Page offset from bo start + * @fault_page_size: The size of the fault in pages. + * @pgprot: The page protections. + * Does additional checking whether it's possible to insert a PUD or PMD + * pfn and performs the insertion. + * + * Return: VM_FAULT_NOPAGE on successful insertion, VM_FAULT_FALLBACK if + * a huge fault was not possible, or on insertion error. + */ +static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf, + struct ttm_buffer_object *bo, + pgoff_t page_offset, + pgoff_t fault_page_size, + pgprot_t pgprot) +{ + pgoff_t i; + vm_fault_t ret; + unsigned long pfn; + pfn_t pfnt; + struct ttm_tt *ttm = bo->ttm; + bool write = vmf->flags & FAULT_FLAG_WRITE; + + /* Fault should not cross bo boundary. */ + page_offset &= ~(fault_page_size - 1); + if (page_offset + fault_page_size > bo->num_pages) + goto out_fallback; + + if (bo->mem.bus.is_iomem) + pfn = ttm_bo_io_mem_pfn(bo, page_offset); + else + pfn = page_to_pfn(ttm->pages[page_offset]); + + /* pfn must be fault_page_size aligned. */ + if ((pfn & (fault_page_size - 1)) != 0) + goto out_fallback; + + /* Check that memory is contiguous. */ + if (!bo->mem.bus.is_iomem) { + for (i = 1; i < fault_page_size; ++i) { + if (page_to_pfn(ttm->pages[page_offset + i]) != pfn + i) + goto out_fallback; + } + } else if (bo->bdev->driver->io_mem_pfn) { + for (i = 1; i < fault_page_size; ++i) { + if (ttm_bo_io_mem_pfn(bo, page_offset + i) != pfn + i) + goto out_fallback; + } + } + + pfnt = __pfn_to_pfn_t(pfn, PFN_DEV); + if (fault_page_size == (HPAGE_PMD_SIZE >> PAGE_SHIFT)) + ret = vmf_insert_pfn_pmd_prot(vmf, pfnt, pgprot, write); +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD + else if (fault_page_size == (HPAGE_PUD_SIZE >> PAGE_SHIFT)) + ret = vmf_insert_pfn_pud_prot(vmf, pfnt, pgprot, write); +#endif + else + WARN_ON_ONCE(ret = VM_FAULT_FALLBACK); + + if (ret != VM_FAULT_NOPAGE) + goto out_fallback; + + return VM_FAULT_NOPAGE; +out_fallback: + count_vm_event(THP_FAULT_FALLBACK); + return VM_FAULT_FALLBACK; +} +#else +static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf, + struct ttm_buffer_object *bo, + pgoff_t page_offset, + pgoff_t fault_page_size, + pgprot_t pgprot) +{ + return VM_FAULT_FALLBACK; +} +#endif + /** * ttm_bo_vm_fault_reserved - TTM fault helper * @vmf: The struct vm_fault given as argument to the fault callback @@ -163,6 +246,7 @@ EXPORT_SYMBOL(ttm_bo_vm_reserve); * @num_prefault: Maximum number of prefault pages. The caller may want to * specify this based on madvice settings and the size of the GPU object * backed by the memory. + * @fault_page_size: The size of the fault in pages. * * This function inserts one or more page table entries pointing to the * memory backing the buffer object, and then returns a return code @@ -176,7 +260,8 @@ EXPORT_SYMBOL(ttm_bo_vm_reserve); */ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, pgprot_t prot, - pgoff_t num_prefault) + pgoff_t num_prefault, + pgoff_t fault_page_size) { struct vm_area_struct *vma = vmf->vma; struct ttm_buffer_object *bo = vma->vm_private_data; @@ -268,6 +353,13 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, prot = pgprot_decrypted(prot); } + /* We don't prefault on huge faults. Yet. */ + if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && fault_page_size != 1) { + ret = ttm_bo_vm_insert_huge(vmf, bo, page_offset, + fault_page_size, prot); + goto out_io_unlock; + } + /* * Speculatively prefault a number of pages. Only error on * first page. @@ -334,7 +426,7 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) return ret; prot = vma->vm_page_prot; - ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT); + ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT, 1); if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) return ret; @@ -344,6 +436,66 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) } EXPORT_SYMBOL(ttm_bo_vm_fault); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/** + * ttm_pgprot_is_wrprotecting - Is a page protection value write-protecting? + * @prot: The page protection value + * + * Return: true if @prot is write-protecting. false otherwise. + */ +static bool ttm_pgprot_is_wrprotecting(pgprot_t prot) +{ + /* + * This is meant to say "pgprot_wrprotect(prot) == prot" in a generic + * way. Unfortunately there is no generic pgprot_wrprotect. + */ + return pte_val(pte_wrprotect(__pte(pgprot_val(prot)))) == + pgprot_val(prot); +} + +static vm_fault_t ttm_bo_vm_huge_fault(struct vm_fault *vmf, + enum page_entry_size pe_size) +{ + struct vm_area_struct *vma = vmf->vma; + pgprot_t prot; + struct ttm_buffer_object *bo = vma->vm_private_data; + vm_fault_t ret; + pgoff_t fault_page_size = 0; + bool write = vmf->flags & FAULT_FLAG_WRITE; + + switch (pe_size) { + case PE_SIZE_PMD: + fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT; + break; +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD + case PE_SIZE_PUD: + fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT; + break; +#endif + default: + WARN_ON_ONCE(1); + return VM_FAULT_FALLBACK; + } + + /* Fallback on write dirty-tracking or COW */ + if (write && ttm_pgprot_is_wrprotecting(vma->vm_page_prot)) + return VM_FAULT_FALLBACK; + + ret = ttm_bo_vm_reserve(bo, vmf); + if (ret) + return ret; + + prot = vm_get_page_prot(vma->vm_flags); + ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size); + if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) + return ret; + + dma_resv_unlock(bo->base.resv); + + return ret; +} +#endif + void ttm_bo_vm_open(struct vm_area_struct *vma) { struct ttm_buffer_object *bo = vma->vm_private_data; @@ -445,7 +597,10 @@ static const struct vm_operations_struct ttm_bo_vm_ops = { .fault = ttm_bo_vm_fault, .open = ttm_bo_vm_open, .close = ttm_bo_vm_close, - .access = ttm_bo_vm_access + .access = ttm_bo_vm_access, +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + .huge_fault = ttm_bo_vm_huge_fault, +#endif }; static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c index 60cfbfadd3f2..8cf7a77c9b2f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c @@ -477,7 +477,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf) else prot = vm_get_page_prot(vma->vm_flags); - ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault); + ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault, 1); if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) return ret; diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index b9bc1b00142e..0a9d042e075a 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -727,7 +727,8 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, pgprot_t prot, - pgoff_t num_prefault); + pgoff_t num_prefault, + pgoff_t fault_page_size); vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf); From 75390281ab68534fbecc71f370203d7981f04a3a Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:48:55 +0100 Subject: [PATCH 519/809] drm/vmwgfx: Support huge page faults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With vmwgfx dirty-tracking we need a specialized huge_fault callback. Implement and hook it up. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Acked-by: Christian König --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++ drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 74 +++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 5 +- 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index b70d73225707..6fc8d5c171c6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1402,6 +1402,10 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo, pgoff_t start, pgoff_t end); vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf); vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf, + enum page_entry_size pe_size); +#endif /** * VMW_DEBUG_KMS - Debug output for kernel mode-setting diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c index 8cf7a77c9b2f..d4d66532f9c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c @@ -473,7 +473,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf) * a lot of unnecessary write faults. */ if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE) - prot = vma->vm_page_prot; + prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED); else prot = vm_get_page_prot(vma->vm_flags); @@ -486,3 +486,75 @@ out_unlock: return ret; } + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf, + enum page_entry_size pe_size) +{ + struct vm_area_struct *vma = vmf->vma; + struct ttm_buffer_object *bo = (struct ttm_buffer_object *) + vma->vm_private_data; + struct vmw_buffer_object *vbo = + container_of(bo, struct vmw_buffer_object, base); + pgprot_t prot; + vm_fault_t ret; + pgoff_t fault_page_size; + bool write = vmf->flags & FAULT_FLAG_WRITE; + bool is_cow_mapping = + (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; + + switch (pe_size) { + case PE_SIZE_PMD: + fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT; + break; +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD + case PE_SIZE_PUD: + fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT; + break; +#endif + default: + WARN_ON_ONCE(1); + return VM_FAULT_FALLBACK; + } + + /* Always do write dirty-tracking and COW on PTE level. */ + if (write && (READ_ONCE(vbo->dirty) || is_cow_mapping)) + return VM_FAULT_FALLBACK; + + ret = ttm_bo_vm_reserve(bo, vmf); + if (ret) + return ret; + + if (vbo->dirty) { + pgoff_t allowed_prefault; + unsigned long page_offset; + + page_offset = vmf->pgoff - + drm_vma_node_start(&bo->base.vma_node); + if (page_offset >= bo->num_pages || + vmw_resources_clean(vbo, page_offset, + page_offset + PAGE_SIZE, + &allowed_prefault)) { + ret = VM_FAULT_SIGBUS; + goto out_unlock; + } + + /* + * Write protect, so we get a new fault on write, and can + * split. + */ + prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED); + } else { + prot = vm_get_page_prot(vma->vm_flags); + } + + ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size); + if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) + return ret; + +out_unlock: + dma_resv_unlock(bo->base.resv); + + return ret; +} +#endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index aa7e50f63b94..3c03b1746661 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -34,7 +34,10 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) .page_mkwrite = vmw_bo_vm_mkwrite, .fault = vmw_bo_vm_fault, .open = ttm_bo_vm_open, - .close = ttm_bo_vm_close + .close = ttm_bo_vm_close, +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + .huge_fault = vmw_bo_vm_huge_fault, +#endif }; struct drm_file *file_priv = filp->private_data; struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev); From b182341667091c8edfb24a7caae600a2f08d7857 Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:49:26 +0100 Subject: [PATCH 520/809] drm: Add a drm_get_unmapped_area() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unaligned virtual addresses makes it unlikely that huge page-table entries can be used. So align virtual buffer object address huge page boundaries to the underlying physical address huge page boundaries taking buffer object sizes into account to determine when it might be possible to use huge page-table entries. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Acked-by: Christian König --- drivers/gpu/drm/drm_file.c | 140 +++++++++++++++++++++++++++++++++++++ include/drm/drm_file.h | 9 +++ 2 files changed, 149 insertions(+) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index c4c704e01961..d1fcb0c61622 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -48,6 +48,11 @@ #include "drm_internal.h" #include "drm_legacy.h" +#if defined(CONFIG_MMU) && defined(CONFIG_TRANSPARENT_HUGEPAGE) +#include +#include +#endif + /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); @@ -872,3 +877,138 @@ struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags) return file; } EXPORT_SYMBOL_FOR_TESTS_ONLY(mock_drm_getfile); + +#ifdef CONFIG_MMU +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/* + * drm_addr_inflate() attempts to construct an aligned area by inflating + * the area size and skipping the unaligned start of the area. + * adapted from shmem_get_unmapped_area() + */ +static unsigned long drm_addr_inflate(unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags, + unsigned long huge_size) +{ + unsigned long offset, inflated_len; + unsigned long inflated_addr; + unsigned long inflated_offset; + + offset = (pgoff << PAGE_SHIFT) & (huge_size - 1); + if (offset && offset + len < 2 * huge_size) + return addr; + if ((addr & (huge_size - 1)) == offset) + return addr; + + inflated_len = len + huge_size - PAGE_SIZE; + if (inflated_len > TASK_SIZE) + return addr; + if (inflated_len < len) + return addr; + + inflated_addr = current->mm->get_unmapped_area(NULL, 0, inflated_len, + 0, flags); + if (IS_ERR_VALUE(inflated_addr)) + return addr; + if (inflated_addr & ~PAGE_MASK) + return addr; + + inflated_offset = inflated_addr & (huge_size - 1); + inflated_addr += offset - inflated_offset; + if (inflated_offset > offset) + inflated_addr += huge_size; + + if (inflated_addr > TASK_SIZE - len) + return addr; + + return inflated_addr; +} + +/** + * drm_get_unmapped_area() - Get an unused user-space virtual memory area + * suitable for huge page table entries. + * @file: The struct file representing the address space being mmap()'d. + * @uaddr: Start address suggested by user-space. + * @len: Length of the area. + * @pgoff: The page offset into the address space. + * @flags: mmap flags + * @mgr: The address space manager used by the drm driver. This argument can + * probably be removed at some point when all drivers use the same + * address space manager. + * + * This function attempts to find an unused user-space virtual memory area + * that can accommodate the size we want to map, and that is properly + * aligned to facilitate huge page table entries matching actual + * huge pages or huge page aligned memory in buffer objects. Buffer objects + * are assumed to start at huge page boundary pfns (io memory) or be + * populated by huge pages aligned to the start of the buffer object + * (system- or coherent memory). Adapted from shmem_get_unmapped_area. + * + * Return: aligned user-space address. + */ +unsigned long drm_get_unmapped_area(struct file *file, + unsigned long uaddr, unsigned long len, + unsigned long pgoff, unsigned long flags, + struct drm_vma_offset_manager *mgr) +{ + unsigned long addr; + unsigned long inflated_addr; + struct drm_vma_offset_node *node; + + if (len > TASK_SIZE) + return -ENOMEM; + + /* + * @pgoff is the file page-offset the huge page boundaries of + * which typically aligns to physical address huge page boundaries. + * That's not true for DRM, however, where physical address huge + * page boundaries instead are aligned with the offset from + * buffer object start. So adjust @pgoff to be the offset from + * buffer object start. + */ + drm_vma_offset_lock_lookup(mgr); + node = drm_vma_offset_lookup_locked(mgr, pgoff, 1); + if (node) + pgoff -= node->vm_node.start; + drm_vma_offset_unlock_lookup(mgr); + + addr = current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags); + if (IS_ERR_VALUE(addr)) + return addr; + if (addr & ~PAGE_MASK) + return addr; + if (addr > TASK_SIZE - len) + return addr; + + if (len < HPAGE_PMD_SIZE) + return addr; + if (flags & MAP_FIXED) + return addr; + /* + * Our priority is to support MAP_SHARED mapped hugely; + * and support MAP_PRIVATE mapped hugely too, until it is COWed. + * But if caller specified an address hint, respect that as before. + */ + if (uaddr) + return addr; + + inflated_addr = drm_addr_inflate(addr, len, pgoff, flags, + HPAGE_PMD_SIZE); + + if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD) && + len >= HPAGE_PUD_SIZE) + inflated_addr = drm_addr_inflate(inflated_addr, len, pgoff, + flags, HPAGE_PUD_SIZE); + return inflated_addr; +} +#else /* CONFIG_TRANSPARENT_HUGEPAGE */ +unsigned long drm_get_unmapped_area(struct file *file, + unsigned long uaddr, unsigned long len, + unsigned long pgoff, unsigned long flags, + struct drm_vma_offset_manager *mgr) +{ + return current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags); +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_MMU */ diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 19df8028a6c4..5aaf1c4593a9 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -391,4 +391,13 @@ void drm_send_event(struct drm_device *dev, struct drm_pending_event *e); struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags); +#ifdef CONFIG_MMU +struct drm_vma_offset_manager; +unsigned long drm_get_unmapped_area(struct file *file, + unsigned long uaddr, unsigned long len, + unsigned long pgoff, unsigned long flags, + struct drm_vma_offset_manager *mgr); +#endif /* CONFIG_MMU */ + + #endif /* _DRM_FILE_H_ */ From 7546f7ffdb5cbe12689d94fe657608364d2f7773 Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:50:12 +0100 Subject: [PATCH 521/809] drm/vmwgfx: Introduce a huge page aligning TTM range manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using huge page-table entries requires that the physical address of the start of a buffer object is huge page size aligned. Make a special version of the TTM range manager that accomplishes this, but falls back to a smaller page size alignment (PUD->PMD, PMD->NORMAL) to avoid eviction. If other drivers want to use it in the future, it can be made a TTM generic helper. Note that drivers can force eviction for a certain alignment by assigning the TTM GPU alignment correspondingly. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Acked-by: Christian König --- drivers/gpu/drm/vmwgfx/Makefile | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 7 ++ drivers/gpu/drm/vmwgfx/vmwgfx_thp.c | 166 ++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_thp.c diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index c877a21a0739..421dd2a497a5 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -11,4 +11,5 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_validation.o vmwgfx_page_dirty.o \ ttm_object.o ttm_lock.o +vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 6fc8d5c171c6..d19d28c13671 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1407,6 +1407,13 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf, enum page_entry_size pe_size); #endif +/* Transparent hugepage support - vmwgfx_thp.c */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +extern const struct ttm_mem_type_manager_func vmw_thp_func; +#else +#define vmw_thp_func ttm_bo_manager_func +#endif + /** * VMW_DEBUG_KMS - Debug output for kernel mode-setting * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c new file mode 100644 index 000000000000..b7c816ba7166 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Huge page-table-entry support for IO memory. + * + * Copyright (C) 2007-2019 Vmware, Inc. All rights reservedd. + */ +#include "vmwgfx_drv.h" +#include +#include +#include + +/** + * struct vmw_thp_manager - Range manager implementing huge page alignment + * + * @mm: The underlying range manager. Protected by @lock. + * @lock: Manager lock. + */ +struct vmw_thp_manager { + struct drm_mm mm; + spinlock_t lock; +}; + +static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long align_pages, + const struct ttm_place *place, + struct ttm_mem_reg *mem, + unsigned long lpfn, + enum drm_mm_insert_mode mode) +{ + if (align_pages >= mem->page_alignment && + (!mem->page_alignment || align_pages % mem->page_alignment == 0)) { + return drm_mm_insert_node_in_range(mm, node, + mem->num_pages, + align_pages, 0, + place->fpfn, lpfn, mode); + } + + return -ENOSPC; +} + +static int vmw_thp_get_node(struct ttm_mem_type_manager *man, + struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_mem_reg *mem) +{ + struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct drm_mm *mm = &rman->mm; + struct drm_mm_node *node; + unsigned long align_pages; + unsigned long lpfn; + enum drm_mm_insert_mode mode = DRM_MM_INSERT_BEST; + int ret; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + lpfn = place->lpfn; + if (!lpfn) + lpfn = man->size; + + mode = DRM_MM_INSERT_BEST; + if (place->flags & TTM_PL_FLAG_TOPDOWN) + mode = DRM_MM_INSERT_HIGH; + + spin_lock(&rman->lock); + if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) { + align_pages = (HPAGE_PUD_SIZE >> PAGE_SHIFT); + if (mem->num_pages >= align_pages) { + ret = vmw_thp_insert_aligned(mm, node, align_pages, + place, mem, lpfn, mode); + if (!ret) + goto found_unlock; + } + } + + align_pages = (HPAGE_PMD_SIZE >> PAGE_SHIFT); + if (mem->num_pages >= align_pages) { + ret = vmw_thp_insert_aligned(mm, node, align_pages, place, mem, + lpfn, mode); + if (!ret) + goto found_unlock; + } + + ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages, + mem->page_alignment, 0, + place->fpfn, lpfn, mode); +found_unlock: + spin_unlock(&rman->lock); + + if (unlikely(ret)) { + kfree(node); + } else { + mem->mm_node = node; + mem->start = node->start; + } + + return 0; +} + + + +static void vmw_thp_put_node(struct ttm_mem_type_manager *man, + struct ttm_mem_reg *mem) +{ + struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + + if (mem->mm_node) { + spin_lock(&rman->lock); + drm_mm_remove_node(mem->mm_node); + spin_unlock(&rman->lock); + + kfree(mem->mm_node); + mem->mm_node = NULL; + } +} + +static int vmw_thp_init(struct ttm_mem_type_manager *man, + unsigned long p_size) +{ + struct vmw_thp_manager *rman; + + rman = kzalloc(sizeof(*rman), GFP_KERNEL); + if (!rman) + return -ENOMEM; + + drm_mm_init(&rman->mm, 0, p_size); + spin_lock_init(&rman->lock); + man->priv = rman; + return 0; +} + +static int vmw_thp_takedown(struct ttm_mem_type_manager *man) +{ + struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct drm_mm *mm = &rman->mm; + + spin_lock(&rman->lock); + if (drm_mm_clean(mm)) { + drm_mm_takedown(mm); + spin_unlock(&rman->lock); + kfree(rman); + man->priv = NULL; + return 0; + } + spin_unlock(&rman->lock); + return -EBUSY; +} + +static void vmw_thp_debug(struct ttm_mem_type_manager *man, + struct drm_printer *printer) +{ + struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + + spin_lock(&rman->lock); + drm_mm_print(&rman->mm, printer); + spin_unlock(&rman->lock); +} + +const struct ttm_mem_type_manager_func vmw_thp_func = { + .init = vmw_thp_init, + .takedown = vmw_thp_takedown, + .get_node = vmw_thp_get_node, + .put_node = vmw_thp_put_node, + .debug = vmw_thp_debug +}; From 9431042dbc8ce490d49c7f9d5142805b6249208b Mon Sep 17 00:00:00 2001 From: "Thomas Hellstrom (VMware)" Date: Tue, 24 Mar 2020 18:50:35 +0100 Subject: [PATCH 522/809] drm/vmwgfx: Hook up the helpers to align buffer objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start using the helpers that align buffer object user-space addresses and buffer object vram addresses to huge page boundaries. This is to improve the chances of allowing huge page-table entries. Cc: Andrew Morton Cc: Michal Hocko Cc: "Matthew Wilcox (Oracle)" Cc: "Kirill A. Shutemov" Cc: Ralph Campbell Cc: "Jérôme Glisse" Cc: "Christian König" Cc: Dan Williams Signed-off-by: Thomas Hellstrom (VMware) Reviewed-by: Roland Scheidegger Acked-by: Christian König --- drivers/gpu/drm/drm_file.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 13 +++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | 2 +- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index d1fcb0c61622..eb009d3ab48f 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -1011,4 +1011,5 @@ unsigned long drm_get_unmapped_area(struct file *file, return current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags); } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +EXPORT_SYMBOL_GPL(drm_get_unmapped_area); #endif /* CONFIG_MMU */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4f58364421ce..f0b7a891cbad 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1230,6 +1230,18 @@ static void vmw_remove(struct pci_dev *pdev) pci_disable_device(pdev); } +static unsigned long +vmw_get_unmapped_area(struct file *file, unsigned long uaddr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + struct drm_file *file_priv = file->private_data; + struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev); + + return drm_get_unmapped_area(file, uaddr, len, pgoff, flags, + &dev_priv->vma_manager); +} + static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr) { @@ -1401,6 +1413,7 @@ static const struct file_operations vmwgfx_driver_fops = { .compat_ioctl = vmw_compat_ioctl, #endif .llseek = noop_llseek, + .get_unmapped_area = vmw_get_unmapped_area, }; static struct drm_driver driver = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d19d28c13671..fc98622caf87 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -915,6 +915,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma); extern void vmw_validation_mem_init_ttm(struct vmw_private *dev_priv, size_t gran); + /** * TTM buffer object driver - vmwgfx_ttm_buffer.c */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 3f3b2c7a208a..bf0bc4697959 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -749,7 +749,7 @@ static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, break; case TTM_PL_VRAM: /* "On-card" video ram */ - man->func = &ttm_bo_manager_func; + man->func = &vmw_thp_func; man->gpu_offset = 0; man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_CACHED; From 5614a4a3ca0e8806e144419536f52df419caa14f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Mar 2020 22:30:39 +0100 Subject: [PATCH 523/809] rtc: class: avoid unnecessary lookup in hctosys rtc_hctosys is only called when the relevant RTC is found, avoid looking it up while we already have a pinter to the proper struct rtc_device. Link: https://lore.kernel.org/r/20200323213039.297458-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 8793b2b8cf9d..03d6516941a8 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -46,20 +46,13 @@ int rtc_hctosys_ret = -ENODEV; * the best guess is to add 0.5s. */ -static int rtc_hctosys(void) +static void rtc_hctosys(struct rtc_device *rtc) { int err = -ENODEV; struct rtc_time tm; struct timespec64 tv64 = { .tv_nsec = NSEC_PER_SEC >> 1, }; - struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - - if (!rtc) { - pr_info("unable to open rtc device (%s)\n", - CONFIG_RTC_HCTOSYS_DEVICE); - goto err_open; - } err = rtc_read_time(rtc, &tm); if (err) { @@ -83,12 +76,7 @@ static int rtc_hctosys(void) &tm, (long long)tv64.tv_sec); err_read: - rtc_class_close(rtc); - -err_open: rtc_hctosys_ret = err; - - return err; } #endif @@ -433,7 +421,7 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) #ifdef CONFIG_RTC_HCTOSYS_DEVICE if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE)) - rtc_hctosys(); + rtc_hctosys(rtc); #endif return 0; From 0f8f554e5244f56f496b4ce30ada1126fe290345 Mon Sep 17 00:00:00 2001 From: Gustavo Luiz Duarte Date: Tue, 11 Feb 2020 00:38:31 -0300 Subject: [PATCH 524/809] selftests/powerpc: Don't rely on segfault to rerun the test The test case tm-signal-context-force-tm expects a segfault to happen on returning from signal handler, and then does a setcontext() to run the test again. However, the test doesn't always segfault, causing the test to run a single time. This patch fixes the test by putting it within a loop and jumping, via setcontext, just prior to the loop in case it segfaults. This way we get the desired behavior (run the test COUNT_MAX times) regardless if it segfaults or not. This also reduces the use of setcontext for control flow logic, keeping it only in the segfault handler. Also, since 'count' is changed within the signal handler, it is declared as volatile to prevent any compiler optimization getting confused with asynchronous changes. Signed-off-by: Gustavo Luiz Duarte Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200211033831.11165-3-gustavold@linux.ibm.com --- .../powerpc/tm/tm-signal-context-force-tm.c | 78 +++++++++---------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-force-tm.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-force-tm.c index 31717625f318..421cb082f6be 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-context-force-tm.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-force-tm.c @@ -42,9 +42,10 @@ #endif /* Setting contexts because the test will crash and we want to recover */ -ucontext_t init_context, main_context; +ucontext_t init_context; -static int count, first_time; +/* count is changed in the signal handler, so it must be volatile */ +static volatile int count; void usr_signal_handler(int signo, siginfo_t *si, void *uc) { @@ -98,11 +99,6 @@ void usr_signal_handler(int signo, siginfo_t *si, void *uc) void seg_signal_handler(int signo, siginfo_t *si, void *uc) { - if (count == COUNT_MAX) { - /* Return to tm_signal_force_msr() and exit */ - setcontext(&main_context); - } - count++; /* Reexecute the test */ @@ -126,37 +122,41 @@ void tm_trap_test(void) */ getcontext(&init_context); - /* Allocated an alternative signal stack area */ - ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - ss.ss_size = SIGSTKSZ; - ss.ss_flags = 0; + while (count < COUNT_MAX) { + /* Allocated an alternative signal stack area */ + ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; - if (ss.ss_sp == (void *)-1) { - perror("mmap error\n"); - exit(-1); + if (ss.ss_sp == (void *)-1) { + perror("mmap error\n"); + exit(-1); + } + + /* Force the allocation through a page fault */ + if (madvise(ss.ss_sp, SIGSTKSZ, MADV_DONTNEED)) { + perror("madvise\n"); + exit(-1); + } + + /* + * Setting an alternative stack to generate a page fault when + * the signal is raised. + */ + if (sigaltstack(&ss, NULL)) { + perror("sigaltstack\n"); + exit(-1); + } + + /* The signal handler will enable MSR_TS */ + sigaction(SIGUSR1, &usr_sa, NULL); + /* If it does not crash, it might segfault, avoid it to retest */ + sigaction(SIGSEGV, &seg_sa, NULL); + + raise(SIGUSR1); + count++; } - - /* Force the allocation through a page fault */ - if (madvise(ss.ss_sp, SIGSTKSZ, MADV_DONTNEED)) { - perror("madvise\n"); - exit(-1); - } - - /* Setting an alternative stack to generate a page fault when - * the signal is raised. - */ - if (sigaltstack(&ss, NULL)) { - perror("sigaltstack\n"); - exit(-1); - } - - /* The signal handler will enable MSR_TS */ - sigaction(SIGUSR1, &usr_sa, NULL); - /* If it does not crash, it will segfault, avoid it to retest */ - sigaction(SIGSEGV, &seg_sa, NULL); - - raise(SIGUSR1); } int tm_signal_context_force_tm(void) @@ -169,11 +169,7 @@ int tm_signal_context_force_tm(void) */ SKIP_IF(!is_ppc64le()); - /* Will get back here after COUNT_MAX interactions */ - getcontext(&main_context); - - if (!first_time++) - tm_trap_test(); + tm_trap_test(); return EXIT_SUCCESS; } From c5e76fa05b2df519b9f08571cc57e623c1569faa Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Fri, 6 Mar 2020 20:45:47 -0600 Subject: [PATCH 525/809] powerpc/pseries: Fix of_read_drc_info_cell() to point at next record The expectation is that when calling of_read_drc_info_cell() repeatedly to parse multiple drc-info records that the in/out curval parameter points at the start of the next record on return. However, the current behavior has curval still pointing at the final value of the record just parsed. The result of which is that if the ibm,drc-info property contains multiple properties the parsed value of the drc_type for any record after the first has the power_domain value of the previous record appended to the type string. eg: observed the following 0xffffffff prepended to PHB drc-info: type: \xff\xff\xff\xffPHB, prefix: PHB , index_start: 0x20000001 drc-info: suffix_start: 1, sequential_elems: 3072, sequential_inc: 1 drc-info: power-domain: 0xffffffff, last_index: 0x20000c00 In practice PHBs are the only type of connector in the ibm,drc-info property that has multiple records. So, it breaks PHB hotplug, but by chance not PCI, CPU, slot, or memory because they happen to only ever be a single record. Fix by incrementing curval past the power_domain value to point at drc_type string of next record. Fixes: e83636ac3334 ("pseries/drc-info: Search DRC properties for CPU indexes") Signed-off-by: Tyrel Datwyler Acked-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200307024547.5748-1-tyreld@linux.ibm.com --- arch/powerpc/platforms/pseries/of_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/of_helpers.c b/arch/powerpc/platforms/pseries/of_helpers.c index 66dfd8256712..23241c71ef37 100644 --- a/arch/powerpc/platforms/pseries/of_helpers.c +++ b/arch/powerpc/platforms/pseries/of_helpers.c @@ -88,7 +88,7 @@ int of_read_drc_info_cell(struct property **prop, const __be32 **curval, return -EINVAL; /* Should now know end of current entry */ - (*curval) = (void *)p2; + (*curval) = (void *)(++p2); data->last_drc_index = data->drc_index_start + ((data->num_sequential_elems - 1) * data->sequential_inc); From 3e74a0e16342626511c43937c120beb990539307 Mon Sep 17 00:00:00 2001 From: Balamuruhan S Date: Wed, 11 Mar 2020 15:54:05 +0530 Subject: [PATCH 526/809] powerpc/sstep: Fix DS operand in ld encoding to appropriate value ld instruction should have 14 bit immediate field (DS) concatenated with 0b00 on the right, encode it accordingly. Introduce macro `IMM_DS()` to encode DS form instructions with 14 bit immediate field. Fixes: 4ceae137bdab ("powerpc: emulate_step() tests for load/store instructions") Reviewed-by: Sandipan Das Signed-off-by: Balamuruhan S Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200311102405.392263-1-bala24@linux.ibm.com --- arch/powerpc/lib/test_emulate_step.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c index 00d70253cb5b..53df4146dd32 100644 --- a/arch/powerpc/lib/test_emulate_step.c +++ b/arch/powerpc/lib/test_emulate_step.c @@ -13,19 +13,20 @@ #include #define IMM_L(i) ((uintptr_t)(i) & 0xffff) +#define IMM_DS(i) ((uintptr_t)(i) & 0xfffc) /* * Defined with TEST_ prefix so it does not conflict with other * definitions. */ #define TEST_LD(r, base, i) (PPC_INST_LD | ___PPC_RT(r) | \ - ___PPC_RA(base) | IMM_L(i)) + ___PPC_RA(base) | IMM_DS(i)) #define TEST_LWZ(r, base, i) (PPC_INST_LWZ | ___PPC_RT(r) | \ ___PPC_RA(base) | IMM_L(i)) #define TEST_LWZX(t, a, b) (PPC_INST_LWZX | ___PPC_RT(t) | \ ___PPC_RA(a) | ___PPC_RB(b)) #define TEST_STD(r, base, i) (PPC_INST_STD | ___PPC_RS(r) | \ - ___PPC_RA(base) | ((i) & 0xfffc)) + ___PPC_RA(base) | IMM_DS(i)) #define TEST_LDARX(t, a, b, eh) (PPC_INST_LDARX | ___PPC_RT(t) | \ ___PPC_RA(a) | ___PPC_RB(b) | \ __PPC_EH(eh)) From addf3727ad28bd159ae2da433b48daf2ffb339f7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Mar 2020 21:51:31 -0700 Subject: [PATCH 527/809] powerpc/cell: Use fallthrough; Convert the various uses of fallthrough comments to fallthrough; Signed-off-by: Joe Perches Acked-by: Arnd Bergmann Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/03073a9a269010ca439e9e658629c44602b0cc9f.1583896348.git.joe@perches.com --- arch/powerpc/platforms/cell/spufs/switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 5c3f5d088c3b..d56b4e3241cd 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -177,7 +177,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu) POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == MFC_CNTL_SUSPEND_COMPLETE); - /* fall through */ + fallthrough; case MFC_CNTL_SUSPEND_COMPLETE: if (csa) csa->priv2.mfc_control_RW = From b4f00d5b2098320a0d4c4a6d31099bc0c9a85b02 Mon Sep 17 00:00:00 2001 From: afzal mohammed Date: Thu, 12 Mar 2020 12:12:55 +0530 Subject: [PATCH 528/809] powerpc: Replace setup_irq() by request_irq() request_irq() is preferred over setup_irq(). Invocations of setup_irq() occur after memory allocators are ready. Per tglx[1], setup_irq() existed in olden days when allocators were not ready by the time early interrupts were initialized. Hence replace setup_irq() by request_irq(). [1] https://lkml.kernel.org/r/alpine.DEB.2.20.1710191609480.1971@nanos Signed-off-by: afzal mohammed Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200312064256.18735-1-afzal.mohd.ma@gmail.com --- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 11 ++++----- arch/powerpc/platforms/8xx/cpm1.c | 9 ++----- arch/powerpc/platforms/8xx/m8xx_setup.c | 9 ++----- arch/powerpc/platforms/chrp/setup.c | 14 ++++------- arch/powerpc/platforms/powermac/pic.c | 29 +++++++++-------------- arch/powerpc/platforms/powermac/smp.c | 12 ++++------ 6 files changed, 29 insertions(+), 55 deletions(-) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 6b1436abe9b1..915ab6710b93 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -218,12 +218,6 @@ static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id) { return IRQ_HANDLED; } - -static struct irqaction mpc85xxcds_8259_irqaction = { - .handler = mpc85xx_8259_cascade_action, - .flags = IRQF_SHARED | IRQF_NO_THREAD, - .name = "8259 cascade", -}; #endif /* PPC_I8259 */ #endif /* CONFIG_PCI */ @@ -271,7 +265,10 @@ static int mpc85xx_cds_8259_attach(void) * disabled when the last user of the shared IRQ line frees their * interrupt. */ - if ((ret = setup_irq(cascade_irq, &mpc85xxcds_8259_irqaction))) { + ret = request_irq(cascade_irq, mpc85xx_8259_cascade_action, + IRQF_SHARED | IRQF_NO_THREAD, "8259 cascade", + cascade_node); + if (ret) { printk(KERN_ERR "Failed to setup cascade interrupt\n"); return ret; } diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c index a43ee7d1ff85..4db4ca2e1222 100644 --- a/arch/powerpc/platforms/8xx/cpm1.c +++ b/arch/powerpc/platforms/8xx/cpm1.c @@ -120,12 +120,6 @@ static irqreturn_t cpm_error_interrupt(int irq, void *dev) return IRQ_HANDLED; } -static struct irqaction cpm_error_irqaction = { - .handler = cpm_error_interrupt, - .flags = IRQF_NO_THREAD, - .name = "error", -}; - static const struct irq_domain_ops cpm_pic_host_ops = { .map = cpm_pic_host_map, }; @@ -187,7 +181,8 @@ unsigned int __init cpm_pic_init(void) if (!eirq) goto end; - if (setup_irq(eirq, &cpm_error_irqaction)) + if (request_irq(eirq, cpm_error_interrupt, IRQF_NO_THREAD, "error", + NULL)) printk(KERN_ERR "Could not allocate CPM error IRQ!"); setbits32(&cpic_reg->cpic_cicr, CICR_IEN); diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index f1c805c8adbc..df4d57d07f9a 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -39,12 +39,6 @@ static irqreturn_t timebase_interrupt(int irq, void *dev) return IRQ_HANDLED; } -static struct irqaction tbint_irqaction = { - .handler = timebase_interrupt, - .flags = IRQF_NO_THREAD, - .name = "tbint", -}; - /* per-board overridable init_internal_rtc() function. */ void __init __attribute__ ((weak)) init_internal_rtc(void) @@ -157,7 +151,8 @@ void __init mpc8xx_calibrate_decr(void) (TBSCR_TBF | TBSCR_TBE)); immr_unmap(sys_tmr2); - if (setup_irq(virq, &tbint_irqaction)) + if (request_irq(virq, timebase_interrupt, IRQF_NO_THREAD, "tbint", + NULL)) panic("Could not allocate timer IRQ!"); } diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index fcf6f2342ef4..8328cd5817b0 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -451,13 +451,6 @@ static void __init chrp_find_openpic(void) of_node_put(np); } -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) -static struct irqaction xmon_irqaction = { - .handler = xmon_irq, - .name = "XMON break", -}; -#endif - static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -541,8 +534,11 @@ static void __init chrp_init_IRQ(void) if (of_node_is_type(kbd->parent, "adb")) break; of_node_put(kbd); - if (kbd) - setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction); + if (kbd) { + if (request_irq(HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", + NULL)) + pr_err("Failed to register XMON break interrupt\n"); + } #endif } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 2e969073473d..4921bccf0376 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -250,20 +250,6 @@ static unsigned int pmac_pic_get_irq(void) return irq_linear_revmap(pmac_pic_host, irq); } -#ifdef CONFIG_XMON -static struct irqaction xmon_action = { - .handler = xmon_irq, - .flags = IRQF_NO_THREAD, - .name = "NMI - XMON" -}; -#endif - -static struct irqaction gatwick_cascade_action = { - .handler = gatwick_action, - .flags = IRQF_NO_THREAD, - .name = "cascade", -}; - static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { @@ -384,12 +370,17 @@ static void __init pmac_pic_probe_oldstyle(void) out_le32(&pmac_irq_hw[i]->enable, 0); /* Hookup cascade irq */ - if (slave && pmac_irq_cascade) - setup_irq(pmac_irq_cascade, &gatwick_cascade_action); + if (slave && pmac_irq_cascade) { + if (request_irq(pmac_irq_cascade, gatwick_action, + IRQF_NO_THREAD, "cascade", NULL)) + pr_err("Failed to register cascade interrupt\n"); + } printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); #ifdef CONFIG_XMON - setup_irq(irq_create_mapping(NULL, 20), &xmon_action); + i = irq_create_mapping(NULL, 20); + if (request_irq(i, xmon_irq, IRQF_NO_THREAD, "NMI - XMON", NULL)) + pr_err("Failed to register NMI-XMON interrupt\n"); #endif } @@ -441,7 +432,9 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) nmi_irq = irq_of_parse_and_map(pswitch, 0); if (nmi_irq) { mpic_irq_set_priority(nmi_irq, 9); - setup_irq(nmi_irq, &xmon_action); + if (request_irq(nmi_irq, xmon_irq, IRQF_NO_THREAD, + "NMI - XMON", NULL)) + pr_err("Failed to register NMI-XMON interrupt\n"); } of_node_put(pswitch); } diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index d2900689d642..be2ab5b11e57 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -399,21 +399,19 @@ static int __init smp_psurge_kick_cpu(int nr) return 0; } -static struct irqaction psurge_irqaction = { - .handler = psurge_ipi_intr, - .flags = IRQF_PERCPU | IRQF_NO_THREAD, - .name = "primary IPI", -}; - static void __init smp_psurge_setup_cpu(int cpu_nr) { + unsigned long flags = IRQF_PERCPU | IRQF_NO_THREAD; + int irq; + if (cpu_nr != 0 || !psurge_start) return; /* reset the entry point so if we get another intr we won't * try to startup again */ out_be32(psurge_start, 0x100); - if (setup_irq(irq_create_mapping(NULL, 30), &psurge_irqaction)) + irq = irq_create_mapping(NULL, 30); + if (request_irq(irq, psurge_ipi_intr, flags, "primary IPI", NULL)) printk(KERN_ERR "Couldn't get primary IPI interrupt"); } From 74bb84e5117146fa73eb9d01305975c53022b3c3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 12 Mar 2020 18:44:04 +1100 Subject: [PATCH 529/809] powerpc/prom_init: Pass the "os-term" message to hypervisor The "os-term" RTAS calls has one argument with a message address of OS termination cause. rtas_os_term() already passes it but the recently added prom_init's version of that missed it; it also does not fill args correctly. This passes the message address and initializes the number of arguments. Fixes: 6a9c930bd775 ("powerpc/prom_init: Add the ESM call to prom_init") Signed-off-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200312074404.87293-1-aik@ozlabs.ru --- arch/powerpc/kernel/prom_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 577345382b23..673f13b87db1 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1773,6 +1773,9 @@ static void __init prom_rtas_os_term(char *str) if (token == 0) prom_panic("Could not get token for ibm,os-term\n"); os_term_args.token = cpu_to_be32(token); + os_term_args.nargs = cpu_to_be32(1); + os_term_args.nret = cpu_to_be32(1); + os_term_args.args[0] = cpu_to_be32(__pa(str)); prom_rtas_hcall((uint64_t)&os_term_args); } #endif /* CONFIG_PPC_SVM */ From d64c7dbb4d98306b794401ca924ad053f84b59f8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Feb 2020 22:00:07 +1100 Subject: [PATCH 530/809] powerpc/xmon: Lower limits on nidump and ndump In xmon we have two variables that are used by the dump commands. There's ndump which is the number of bytes to dump using 'd', and nidump which is the number of instructions to dump using 'di'. ndump starts as 64 and nidump starts as 16, but both can be set by the user. It's fairly common to be pasting addresses into xmon when trying to debug something, and if you inadvertently double paste an address like so: 0:mon> di c000000002101f6c c000000002101f6c The second value is interpreted as the number of instructions to dump. Luckily it doesn't dump 13 quintrillion instructions, the value is limited to MAX_DUMP (128K). But as each instruction is dumped on a single line, that's still a lot of output. If you're on a slow console that can take multiple minutes to print. If you were "just popping in and out of xmon quickly before the RCU/hardlockup detector fires" you are now having a bad day. Things are not as bad with 'd' because we print 16 bytes per line, so it's fewer lines. But it's still quite a lot. So shrink the maximum for 'd' to 64K (one page), which is 4096 lines. For 'di' add a new limit which is the above / 4 - because instructions are 4 bytes, meaning again we can dump one page. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200219110007.31195-1-mpe@ellerman.id.au --- arch/powerpc/xmon/xmon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 0ec9640335bb..ea303b7e4e29 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -81,8 +81,9 @@ static bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE); static unsigned long adrs; static int size = 1; -#define MAX_DUMP (128 * 1024) +#define MAX_DUMP (64 * 1024) static unsigned long ndump = 64; +#define MAX_IDUMP (MAX_DUMP >> 2) static unsigned long nidump = 16; static unsigned long ncsum = 4096; static int termch; @@ -2756,8 +2757,8 @@ dump(void) scanhex(&nidump); if (nidump == 0) nidump = 16; - else if (nidump > MAX_DUMP) - nidump = MAX_DUMP; + else if (nidump > MAX_IDUMP) + nidump = MAX_IDUMP; adrs += ppc_inst_dump(adrs, nidump, 1); last_cmd = "di\n"; } else if (c == 'l') { From 6eeb9b3b9ce588f14a697737a30d0702b5a20293 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 14:13:28 +1100 Subject: [PATCH 531/809] powerpc/64s: Fix section mismatch warnings from boot code We currently have two section mismatch warnings: The function __boot_from_prom() references the function __init prom_init(). The function start_here_common() references the function __init start_kernel(). The warnings are correct, we do have branches from non-init code into init code, which is freed after boot. But we don't expect to ever execute any of that early boot code after boot, if we did that would be a bug. In particular calling into OF after boot would be fatal because OF is no longer resident. So for now fix the warnings by marking the relevant functions as __REF, which puts them in the ".ref.text" section. This causes some reordering of the functions in the final link: @@ -217,10 +217,9 @@ c00000000000b088 t generic_secondary_common_init c00000000000b124 t __mmu_off c00000000000b14c t __start_initialization_multiplatform -c00000000000b1ac t __boot_from_prom -c00000000000b1ec t __after_prom_start -c00000000000b260 t p_end -c00000000000b27c T copy_and_flush +c00000000000b1ac t __after_prom_start +c00000000000b220 t p_end +c00000000000b23c T copy_and_flush c00000000000b300 T __secondary_start c00000000000b300 t copy_to_here c00000000000b344 t start_secondary_prolog @@ -228,8 +227,9 @@ c00000000000b36c t enable_64b_mode c00000000000b388 T relative_toc c00000000000b3a8 t p_toc -c00000000000b3b0 t start_here_common -c00000000000b3d0 t start_here_multiplatform +c00000000000b3b0 t __boot_from_prom +c00000000000b3f0 t start_here_multiplatform +c00000000000b480 t start_here_common c00000000000b880 T system_call_common c00000000000b974 t system_call c00000000000b9dc t system_call_exit In particular __boot_from_prom moves after copy_to_here, which means it's not copied to zero in the first stage of copy of the kernel to zero. But that's OK, because we only call __boot_from_prom before we do the copy, so it makes no difference when it's copied. The call sequence is: __start -> __start_initialization_multiplatform -> __boot_from_prom -> __start -> __start_initialization_multiplatform -> __after_prom_start -> copy_and_flush -> copy_and_flush (relocated to 0) -> start_here_multiplatform -> early_setup Reported-by: Mauricio Faria de Oliveira Reported-by: Roman Bolshakov Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200225031328.14676-1-mpe@ellerman.id.au --- arch/powerpc/kernel/head_64.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index ad79fddb974d..ddfbd02140d9 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -537,6 +537,7 @@ __start_initialization_multiplatform: b __after_prom_start #endif /* CONFIG_PPC_BOOK3E */ +__REF __boot_from_prom: #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE /* Save parameters */ @@ -574,6 +575,7 @@ __boot_from_prom: /* We never return. We also hit that trap if trying to boot * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */ trap + .previous __after_prom_start: #ifdef CONFIG_RELOCATABLE @@ -977,7 +979,6 @@ start_here_multiplatform: RFI b . /* prevent speculative execution */ - .previous /* This is where all platforms converge execution */ start_here_common: @@ -1001,6 +1002,7 @@ start_here_common: /* Not reached */ trap EMIT_BUG_ENTRY 0b, __FILE__, __LINE__, 0 + .previous /* * We put a few things here that have to be page-aligned. From eb4f8e259acc37b91b62ca57e0d3c8960c357843 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 19 Feb 2020 08:05:57 +0000 Subject: [PATCH 532/809] powerpc/kprobes: Remove redundant code At the time being we have something like if (something) { p = get(); if (p) { if (something_wrong) goto out; ... return; } else if (a != b) { if (some_error) goto out; ... } goto out; } p = get(); if (!p) { if (a != b) { if (some_error) goto out; ... } goto out; } This is similar to p = get(); if (!p) { if (a != b) { if (some_error) goto out; ... } goto out; } if (something) { if (something_wrong) goto out; ... return; } Signed-off-by: Christophe Leroy [mpe: Reflow the comment that was moved] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/07a17425743600460ce35fa9432d42487a825583.1582099499.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/kprobes.c | 81 ++++++++++++++--------------------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 2d27ec4feee4..3aaff3365134 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -271,54 +271,6 @@ int kprobe_handler(struct pt_regs *regs) preempt_disable(); kcb = get_kprobe_ctlblk(); - /* Check we're not actually recursing */ - if (kprobe_running()) { - p = get_kprobe(addr); - if (p) { - kprobe_opcode_t insn = *p->ainsn.insn; - if (kcb->kprobe_status == KPROBE_HIT_SS && - is_trap(insn)) { - /* Turn off 'trace' bits */ - regs->msr &= ~MSR_SINGLESTEP; - regs->msr |= kcb->kprobe_saved_msr; - goto no_kprobe; - } - /* We have reentered the kprobe_handler(), since - * another probe was hit while within the handler. - * We here save the original kprobes variables and - * just single step on the instruction of the new probe - * without calling any user handlers. - */ - save_previous_kprobe(kcb); - set_current_kprobe(p, regs, kcb); - kprobes_inc_nmissed_count(p); - kcb->kprobe_status = KPROBE_REENTER; - if (p->ainsn.boostable >= 0) { - ret = try_to_emulate(p, regs); - - if (ret > 0) { - restore_previous_kprobe(kcb); - preempt_enable_no_resched(); - return 1; - } - } - prepare_singlestep(p, regs); - return 1; - } else if (*addr != BREAKPOINT_INSTRUCTION) { - /* If trap variant, then it belongs not to us */ - kprobe_opcode_t cur_insn = *addr; - - if (is_trap(cur_insn)) - goto no_kprobe; - /* The breakpoint instruction was removed by - * another cpu right after we hit, no further - * handling of this interrupt is appropriate - */ - ret = 1; - } - goto no_kprobe; - } - p = get_kprobe(addr); if (!p) { if (*addr != BREAKPOINT_INSTRUCTION) { @@ -343,6 +295,39 @@ int kprobe_handler(struct pt_regs *regs) goto no_kprobe; } + /* Check we're not actually recursing */ + if (kprobe_running()) { + kprobe_opcode_t insn = *p->ainsn.insn; + if (kcb->kprobe_status == KPROBE_HIT_SS && is_trap(insn)) { + /* Turn off 'trace' bits */ + regs->msr &= ~MSR_SINGLESTEP; + regs->msr |= kcb->kprobe_saved_msr; + goto no_kprobe; + } + + /* + * We have reentered the kprobe_handler(), since another probe + * was hit while within the handler. We here save the original + * kprobes variables and just single step on the instruction of + * the new probe without calling any user handlers. + */ + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); + kprobes_inc_nmissed_count(p); + kcb->kprobe_status = KPROBE_REENTER; + if (p->ainsn.boostable >= 0) { + ret = try_to_emulate(p, regs); + + if (ret > 0) { + restore_previous_kprobe(kcb); + preempt_enable_no_resched(); + return 1; + } + } + prepare_singlestep(p, regs); + return 1; + } + kcb->kprobe_status = KPROBE_HIT_ACTIVE; set_current_kprobe(p, regs, kcb); if (p->pre_handler && p->pre_handler(p, regs)) { From af92bad615be75c6c0d1b1c5b48178360250a187 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 6 Mar 2020 15:09:40 +0000 Subject: [PATCH 533/809] powerpc/kasan: Fix kasan_remap_early_shadow_ro() At the moment kasan_remap_early_shadow_ro() does nothing, because k_end is 0 and k_cur < 0 is always true. Change the test to k_cur != k_end, as done in kasan_init_shadow_page_tables() Signed-off-by: Christophe Leroy Fixes: cbd18991e24f ("powerpc/mm: Fix an Oops in kasan_mmu_init()") Cc: stable@vger.kernel.org Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/4e7b56865e01569058914c991143f5961b5d4719.1583507333.git.christophe.leroy@c-s.fr --- arch/powerpc/mm/kasan/kasan_init_32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/kasan_init_32.c index f19526e7d3dc..1a29cf469903 100644 --- a/arch/powerpc/mm/kasan/kasan_init_32.c +++ b/arch/powerpc/mm/kasan/kasan_init_32.c @@ -101,7 +101,7 @@ static void __init kasan_remap_early_shadow_ro(void) kasan_populate_pte(kasan_early_shadow_pte, prot); - for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) { + for (k_cur = k_start & PAGE_MASK; k_cur != k_end; k_cur += PAGE_SIZE) { pmd_t *pmd = pmd_ptr_k(k_cur); pte_t *ptep = pte_offset_kernel(pmd, k_cur); From 697ece78f8f749aeea40f2711389901f0974017a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 10 Mar 2020 17:29:12 +0000 Subject: [PATCH 534/809] powerpc/32s: reorder Linux PTE bits to better match Hash PTE bits. Reorder Linux PTE bits to (almost) match Hash PTE bits. RW Kernel : PP = 00 RO Kernel : PP = 00 RW User : PP = 01 RO User : PP = 11 So naturally, we should have _PAGE_USER = 0x001 _PAGE_RW = 0x002 Today 0x001 and 0x002 and _PAGE_PRESENT and _PAGE_HASHPTE which both are software only bits. Switch _PAGE_USER and _PAGE_PRESET Switch _PAGE_RW and _PAGE_HASHPTE This allows to remove a few insns. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/c4d6c18a7f8d9d3b899bc492f55fbc40ef38896a.1583861325.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/book3s/32/hash.h | 8 ++++---- arch/powerpc/kernel/head_32.S | 9 +++------ arch/powerpc/mm/book3s32/hash_low.S | 14 ++++++-------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/hash.h b/arch/powerpc/include/asm/book3s/32/hash.h index 2a0a467d2985..34a7215ae81e 100644 --- a/arch/powerpc/include/asm/book3s/32/hash.h +++ b/arch/powerpc/include/asm/book3s/32/hash.h @@ -17,9 +17,9 @@ * updating the accessed and modified bits in the page table tree. */ -#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ -#define _PAGE_HASHPTE 0x002 /* hash_page has made an HPTE for this pte */ -#define _PAGE_USER 0x004 /* usermode access allowed */ +#define _PAGE_USER 0x001 /* usermode access allowed */ +#define _PAGE_RW 0x002 /* software: user write access allowed */ +#define _PAGE_PRESENT 0x004 /* software: pte contains a translation */ #define _PAGE_GUARDED 0x008 /* G: prohibit speculative access */ #define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ #define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */ @@ -27,7 +27,7 @@ #define _PAGE_DIRTY 0x080 /* C: page changed */ #define _PAGE_ACCESSED 0x100 /* R: page referenced */ #define _PAGE_EXEC 0x200 /* software: exec allowed */ -#define _PAGE_RW 0x400 /* software: user write access allowed */ +#define _PAGE_HASHPTE 0x400 /* hash_page has made an HPTE for this pte */ #define _PAGE_SPECIAL 0x800 /* software: Special page */ #ifdef CONFIG_PTE_64BIT diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 97c887950c3c..daaa153950c2 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -348,7 +348,7 @@ BEGIN_MMU_FTR_SECTION andis. r0, r5, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h #endif bne handle_page_fault_tramp_2 /* if not, try to put a PTE */ - rlwinm r3, r5, 32 - 15, 21, 21 /* DSISR_STORE -> _PAGE_RW */ + rlwinm r3, r5, 32 - 24, 30, 30 /* DSISR_STORE -> _PAGE_RW */ bl hash_page b handle_page_fault_tramp_1 FTR_SECTION_ELSE @@ -497,7 +497,6 @@ InstructionTLBMiss: andc. r1,r1,r0 /* check access & ~permission */ bne- InstructionAddressInvalid /* return if access not permitted */ /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */ ori r1, r1, 0xe06 /* clear out reserved bits */ andc r1, r0, r1 /* PP = user? 1 : 0 */ BEGIN_FTR_SECTION @@ -565,9 +564,8 @@ DataLoadTLBMiss: * we would need to update the pte atomically with lwarx/stwcx. */ /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwinm r1,r0,32-9,30,30 /* _PAGE_RW -> PP msb */ - rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */ - rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */ + rlwinm r1,r0,0,30,30 /* _PAGE_RW -> PP msb */ + rlwimi r0,r0,1,30,30 /* _PAGE_USER -> PP msb */ ori r1,r1,0xe04 /* clear out reserved bits */ andc r1,r0,r1 /* PP = user? rw? 1: 3: 0 */ BEGIN_FTR_SECTION @@ -645,7 +643,6 @@ DataStoreTLBMiss: * we would need to update the pte atomically with lwarx/stwcx. */ /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */ li r1,0xe06 /* clear out reserved bits & PP msb */ andc r1,r0,r1 /* PP = user? 1: 0 */ BEGIN_FTR_SECTION diff --git a/arch/powerpc/mm/book3s32/hash_low.S b/arch/powerpc/mm/book3s32/hash_low.S index 877d880890fe..6d236080cb1a 100644 --- a/arch/powerpc/mm/book3s32/hash_low.S +++ b/arch/powerpc/mm/book3s32/hash_low.S @@ -35,7 +35,7 @@ mmu_hash_lock: /* * Load a PTE into the hash table, if possible. * The address is in r4, and r3 contains an access flag: - * _PAGE_RW (0x400) if a write. + * _PAGE_RW (0x002) if a write. * r9 contains the SRR1 value, from which we use the MSR_PR bit. * SPRG_THREAD contains the physical address of the current task's thread. * @@ -69,7 +69,7 @@ _GLOBAL(hash_page) blt+ 112f /* assume user more likely */ lis r5, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */ addi r5 ,r5 ,(swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */ - rlwimi r3,r9,32-12,29,29 /* MSR_PR -> _PAGE_USER */ + rlwimi r3,r9,32-14,31,31 /* MSR_PR -> _PAGE_USER */ 112: #ifndef CONFIG_PTE_64BIT rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */ @@ -94,7 +94,7 @@ _GLOBAL(hash_page) #else rlwimi r8,r4,23,20,28 /* compute pte address */ #endif - rlwinm r0,r3,32-3,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ + rlwinm r0,r3,6,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ ori r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE /* @@ -310,11 +310,9 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64) _GLOBAL(create_hpte) /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */ - rlwinm r8,r5,32-9,30,30 /* _PAGE_RW -> PP msb */ rlwinm r0,r5,32-6,30,30 /* _PAGE_DIRTY -> PP msb */ - and r8,r8,r0 /* writable if _RW & _DIRTY */ - rlwimi r5,r5,32-1,30,30 /* _PAGE_USER -> PP msb */ - rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */ + and r8,r5,r0 /* writable if _RW & _DIRTY */ + rlwimi r5,r5,1,30,30 /* _PAGE_USER -> PP msb */ ori r8,r8,0xe04 /* clear out reserved bits */ andc r8,r5,r8 /* PP = user? (rw&dirty? 1: 3): 0 */ BEGIN_FTR_SECTION @@ -566,7 +564,7 @@ _GLOBAL(flush_hash_pages) 33: lwarx r8,0,r5 /* fetch the pte flags word */ andi. r0,r8,_PAGE_HASHPTE beq 8f /* done if HASHPTE is already clear */ - rlwinm r8,r8,0,31,29 /* clear HASHPTE bit */ + rlwinm r8,r8,0,~_PAGE_HASHPTE /* clear HASHPTE bit */ stwcx. r8,0,r5 /* update the pte */ bne- 33b From 9475af081ec1fb6cc794a17ae90f2c01aa8a7993 Mon Sep 17 00:00:00 2001 From: Chen Zhou Date: Thu, 12 Mar 2020 22:04:12 +0800 Subject: [PATCH 535/809] PCI: rpaphp: Remove unused variable 'value' Fixes gcc '-Wunused-but-set-variable' warning: drivers/pci/hotplug/rpaphp_core.c: In function is_php_type: drivers/pci/hotplug/rpaphp_core.c:291:16: warning: variable value set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: Chen Zhou Acked-by: Bjorn Helgaas Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200312140412.32373-1-chenzhou10@huawei.com --- drivers/pci/hotplug/rpaphp_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index e408e4021cee..5d871ef231fd 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -288,11 +288,10 @@ EXPORT_SYMBOL_GPL(rpaphp_check_drc_props); static int is_php_type(char *drc_type) { - unsigned long value; char *endptr; /* PCI Hotplug nodes have an integer for drc_type */ - value = simple_strtoul(drc_type, &endptr, 10); + simple_strtoul(drc_type, &endptr, 10); if (endptr == drc_type) return 0; From 36b78402d97a3b9aeab136feb9b00d8647ec2c20 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Fri, 13 Mar 2020 15:18:42 +0530 Subject: [PATCH 536/809] powerpc/hash64/devmap: Use H_PAGE_THP_HUGE when setting up huge devmap PTE entries H_PAGE_THP_HUGE is used to differentiate between a THP hugepage and hugetlb hugepage entries. The difference is WRT how we handle hash fault on these address. THP address enables MPSS in segments. We want to manage devmap hugepage entries similar to THP pt entries. Hence use H_PAGE_THP_HUGE for devmap huge PTE entries. With current code while handling hash PTE fault, we do set is_thp = true when finding devmap PTE huge PTE entries. Current code also does the below sequence we setting up huge devmap entries. entry = pmd_mkhuge(pfn_t_pmd(pfn, prot)); if (pfn_t_devmap(pfn)) entry = pmd_mkdevmap(entry); In that case we would find both H_PAGE_THP_HUGE and PAGE_DEVMAP set for huge devmap PTE entries. This results in false positive error like below. kernel BUG at /home/kvaneesh/src/linux/mm/memory.c:4321! Oops: Exception in kernel mode, sig: 5 [#1] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries Modules linked in: CPU: 56 PID: 67996 Comm: t_mmap_dio Not tainted 5.6.0-rc4-59640-g371c804dedbc #128 .... NIP [c00000000044c9e4] __follow_pte_pmd+0x264/0x900 LR [c0000000005d45f8] dax_writeback_one+0x1a8/0x740 Call Trace: str_spec.74809+0x22ffb4/0x2d116c (unreliable) dax_writeback_one+0x1a8/0x740 dax_writeback_mapping_range+0x26c/0x700 ext4_dax_writepages+0x150/0x5a0 do_writepages+0x68/0x180 __filemap_fdatawrite_range+0x138/0x180 file_write_and_wait_range+0xa4/0x110 ext4_sync_file+0x370/0x6e0 vfs_fsync_range+0x70/0xf0 sys_msync+0x220/0x2e0 system_call+0x5c/0x68 This is because our pmd_trans_huge check doesn't exclude _PAGE_DEVMAP. To make this all consistent, update pmd_mkdevmap to set H_PAGE_THP_HUGE and pmd_trans_huge check now excludes _PAGE_DEVMAP correctly. Fixes: ebd31197931d ("powerpc/mm: Add devmap support for ppc64") Cc: stable@vger.kernel.org # v4.13+ Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200313094842.351830-1-aneesh.kumar@linux.ibm.com --- arch/powerpc/include/asm/book3s/64/hash-4k.h | 6 ++++++ arch/powerpc/include/asm/book3s/64/hash-64k.h | 8 +++++++- arch/powerpc/include/asm/book3s/64/pgtable.h | 4 +++- arch/powerpc/include/asm/book3s/64/radix.h | 5 +++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h index 8fd8599c9395..3f9ae3585ab9 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-4k.h +++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h @@ -156,6 +156,12 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm, extern int hash__has_transparent_hugepage(void); #endif +static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd) +{ + BUG(); + return pmd; +} + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */ diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h index d1d9177d9ebd..0729c034e56f 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-64k.h +++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h @@ -246,7 +246,7 @@ static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array, */ static inline int hash__pmd_trans_huge(pmd_t pmd) { - return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE)) == + return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP)) == (_PAGE_PTE | H_PAGE_THP_HUGE)); } @@ -272,6 +272,12 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp); extern int hash__has_transparent_hugepage(void); #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd) +{ + return __pmd(pmd_val(pmd) | (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP)); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */ diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 201a69e6a355..368b136517e0 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1303,7 +1303,9 @@ extern void serialize_against_pte_lookup(struct mm_struct *mm); static inline pmd_t pmd_mkdevmap(pmd_t pmd) { - return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP)); + if (radix_enabled()) + return radix__pmd_mkdevmap(pmd); + return hash__pmd_mkdevmap(pmd); } static inline int pmd_devmap(pmd_t pmd) diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index d97db3ad9aae..a1c60d5b50af 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -263,6 +263,11 @@ static inline int radix__has_transparent_hugepage(void) } #endif +static inline pmd_t radix__pmd_mkdevmap(pmd_t pmd) +{ + return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP)); +} + extern int __meminit radix__vmemmap_create_mapping(unsigned long start, unsigned long page_size, unsigned long phys); From 850507f30c38dff21ed557cb98ab16db26c32bbc Mon Sep 17 00:00:00 2001 From: Po-Hsu Lin Date: Wed, 18 Mar 2020 14:00:04 +0800 Subject: [PATCH 537/809] selftests/powerpc: Turn off timeout setting for benchmarks, dscr, signal, tm Some specific tests in powerpc can take longer than the default 45 seconds that added in commit 852c8cbf34d3 ("selftests/kselftest/runner.sh: Add 45 second timeout per test") to run, the following test result was collected across 2 Power8 nodes and 1 Power9 node in our pool: powerpc/benchmarks/futex_bench - 52s powerpc/dscr/dscr_sysfs_test - 116s powerpc/signal/signal_fuzzer - 88s powerpc/tm/tm_unavailable_test - 168s powerpc/tm/tm-poison - 240s Thus they will fail with TIMEOUT error. Disable the timeout setting for these sub-tests to allow them finish properly. https://bugs.launchpad.net/bugs/1864642 Fixes: 852c8cbf34d3 ("selftests/kselftest/runner.sh: Add 45 second timeout per test") Signed-off-by: Po-Hsu Lin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200318060004.10685-1-po-hsu.lin@canonical.com --- tools/testing/selftests/powerpc/benchmarks/Makefile | 2 ++ tools/testing/selftests/powerpc/benchmarks/settings | 1 + tools/testing/selftests/powerpc/dscr/Makefile | 2 ++ tools/testing/selftests/powerpc/dscr/settings | 1 + tools/testing/selftests/powerpc/signal/Makefile | 2 ++ tools/testing/selftests/powerpc/signal/settings | 1 + tools/testing/selftests/powerpc/tm/Makefile | 2 ++ tools/testing/selftests/powerpc/tm/settings | 1 + 8 files changed, 12 insertions(+) create mode 100644 tools/testing/selftests/powerpc/benchmarks/settings create mode 100644 tools/testing/selftests/powerpc/dscr/settings create mode 100644 tools/testing/selftests/powerpc/signal/settings create mode 100644 tools/testing/selftests/powerpc/tm/settings diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index d40300a65b42..a32a6ab89914 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile @@ -2,6 +2,8 @@ TEST_GEN_PROGS := gettimeofday context_switch fork mmap_bench futex_bench null_syscall TEST_GEN_FILES := exec_target +TEST_FILES := settings + CFLAGS += -O2 top_srcdir = ../../../../.. diff --git a/tools/testing/selftests/powerpc/benchmarks/settings b/tools/testing/selftests/powerpc/benchmarks/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/settings @@ -0,0 +1 @@ +timeout=0 diff --git a/tools/testing/selftests/powerpc/dscr/Makefile b/tools/testing/selftests/powerpc/dscr/Makefile index 5df476364b4d..cfa6eedcb66c 100644 --- a/tools/testing/selftests/powerpc/dscr/Makefile +++ b/tools/testing/selftests/powerpc/dscr/Makefile @@ -3,6 +3,8 @@ TEST_GEN_PROGS := dscr_default_test dscr_explicit_test dscr_user_test \ dscr_inherit_test dscr_inherit_exec_test dscr_sysfs_test \ dscr_sysfs_thread_test +TEST_FILES := settings + top_srcdir = ../../../../.. include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/dscr/settings b/tools/testing/selftests/powerpc/dscr/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/powerpc/dscr/settings @@ -0,0 +1 @@ +timeout=0 diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile index 63b57583e07d..932a032bf036 100644 --- a/tools/testing/selftests/powerpc/signal/Makefile +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -5,6 +5,8 @@ CFLAGS += -maltivec $(OUTPUT)/signal_tm: CFLAGS += -mhtm $(OUTPUT)/sigfuz: CFLAGS += -pthread -m64 +TEST_FILES := settings + top_srcdir = ../../../../.. include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/signal/settings b/tools/testing/selftests/powerpc/signal/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/settings @@ -0,0 +1 @@ +timeout=0 diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index b1d99736f8b8..0b0db8d3857c 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -7,6 +7,8 @@ TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack $(SIGNAL_CONTEXT_CHK_TESTS) tm-sigreturn tm-signal-sigreturn-nt \ tm-signal-context-force-tm tm-poison tm-signal-pagefault +TEST_FILES := settings + top_srcdir = ../../../../.. include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/tm/settings b/tools/testing/selftests/powerpc/tm/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/settings @@ -0,0 +1 @@ +timeout=0 From d95fe371ecd28901f11256c610b988ed44e36ee2 Mon Sep 17 00:00:00 2001 From: Pratik Rajesh Sampat Date: Mon, 16 Mar 2020 19:27:43 +0530 Subject: [PATCH 538/809] cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_work_fn The patch avoids allocating cpufreq_policy on stack hence fixing frame size overflow in 'powernv_cpufreq_work_fn' Fixes: 227942809b52 ("cpufreq: powernv: Restore cpu frequency to policy->cur on unthrottling") Signed-off-by: Pratik Rajesh Sampat Reviewed-by: Daniel Axtens Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200316135743.57735-1-psampat@linux.ibm.com --- drivers/cpufreq/powernv-cpufreq.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 03798c4326c6..8646eb197cd9 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -902,6 +902,7 @@ static struct notifier_block powernv_cpufreq_reboot_nb = { void powernv_cpufreq_work_fn(struct work_struct *work) { struct chip *chip = container_of(work, struct chip, throttle); + struct cpufreq_policy *policy; unsigned int cpu; cpumask_t mask; @@ -916,12 +917,14 @@ void powernv_cpufreq_work_fn(struct work_struct *work) chip->restore = false; for_each_cpu(cpu, &mask) { int index; - struct cpufreq_policy policy; - cpufreq_get_policy(&policy, cpu); - index = cpufreq_table_find_index_c(&policy, policy.cur); - powernv_cpufreq_target_index(&policy, index); - cpumask_andnot(&mask, &mask, policy.cpus); + policy = cpufreq_cpu_get(cpu); + if (!policy) + continue; + index = cpufreq_table_find_index_c(policy, policy->cur); + powernv_cpufreq_target_index(policy, index); + cpumask_andnot(&mask, &mask, policy->cpus); + cpufreq_cpu_put(policy); } out: put_online_cpus(); From d4a8e98621543d5798421eed177978bf2b3cdd11 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Fri, 20 Mar 2020 14:21:15 +1100 Subject: [PATCH 539/809] powerpc/64: Setup a paca before parsing device tree etc. Currently we set up the paca after parsing the device tree for CPU features. Prior to that, r13 contains random data, which means there is random data in r13 while we're running the generic dt parsing code. This random data varies depending on whether we boot through a vmlinux or a zImage: for the vmlinux case it's usually around zero, but for zImages we see random values like 912a72603d420015. This is poor practice, and can also lead to difficult-to-debug crashes. For example, when kcov is enabled, the kcov instrumentation attempts to read preempt_count out of the current task, which goes via the paca. This then crashes in the zImage case. Similarly stack protector can cause crashes if r13 is bogus, by reading from the stack canary in the paca. To resolve this: - move the paca setup to before the CPU feature parsing. - because we no longer have access to CPU feature flags in paca setup, change the HV feature test in the paca setup path to consider the actual value of the MSR rather than the CPU feature. Translations get switched on once we leave early_setup, so I think we'd already catch any other cases where the paca or task aren't set up. Boot tested on a P9 guest and host. Fixes: fb0b0a73b223 ("powerpc: Enable kcov") Fixes: 06ec27aea9fc ("powerpc/64: add stack protector support") Cc: stable@vger.kernel.org # v4.20+ Reviewed-by: Andrew Donnellan Suggested-by: Michael Ellerman Signed-off-by: Daniel Axtens [mpe: Reword comments & change log a bit to mention stack protector] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200320032116.1024773-1-mpe@ellerman.id.au --- arch/powerpc/kernel/dt_cpu_ftrs.c | 1 - arch/powerpc/kernel/paca.c | 10 +++++++--- arch/powerpc/kernel/setup_64.c | 30 ++++++++++++++++++++++++------ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 182b4047c1ef..36bc0d5c4f3a 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -139,7 +139,6 @@ static void __init cpufeatures_setup_cpu(void) /* Initialize the base environment -- clear FSCR/HFSCR. */ hv_mode = !!(mfmsr() & MSR_HV); if (hv_mode) { - /* CPU_FTR_HVMODE is used early in PACA setup */ cur_cpu_spec->cpu_features |= CPU_FTR_HVMODE; mtspr(SPRN_HFSCR, 0); } diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 949eceb254d8..0ee6308541b1 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -214,11 +214,15 @@ void setup_paca(struct paca_struct *new_paca) /* On Book3E, initialize the TLB miss exception frames */ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); #else - /* In HV mode, we setup both HPACA and PACA to avoid problems + /* + * In HV mode, we setup both HPACA and PACA to avoid problems * if we do a GET_PACA() before the feature fixups have been - * applied + * applied. + * + * Normally you should test against CPU_FTR_HVMODE, but CPU features + * are not yet set up when we first reach here. */ - if (early_cpu_has_feature(CPU_FTR_HVMODE)) + if (mfmsr() & MSR_HV) mtspr(SPRN_SPRG_HPACA, local_paca); #endif mtspr(SPRN_SPRG_PACA, local_paca); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e05e6dd67ae6..17886d147dd0 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -285,18 +285,36 @@ void __init early_setup(unsigned long dt_ptr) /* -------- printk is _NOT_ safe to use here ! ------- */ - /* Try new device tree based feature discovery ... */ - if (!dt_cpu_ftrs_init(__va(dt_ptr))) - /* Otherwise use the old style CPU table */ - identify_cpu(0, mfspr(SPRN_PVR)); - - /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ + /* + * Assume we're on cpu 0 for now. + * + * We need to load a PACA very early for a few reasons. + * + * The stack protector canary is stored in the paca, so as soon as we + * call any stack protected code we need r13 pointing somewhere valid. + * + * If we are using kcov it will call in_task() in its instrumentation, + * which relies on the current task from the PACA. + * + * dt_cpu_ftrs_init() calls into generic OF/fdt code, as well as + * printk(), which can trigger both stack protector and kcov. + * + * percpu variables and spin locks also use the paca. + * + * So set up a temporary paca. It will be replaced below once we know + * what CPU we are on. + */ initialise_paca(&boot_paca, 0); setup_paca(&boot_paca); fixup_boot_paca(); /* -------- printk is now safe to use ------- */ + /* Try new device tree based feature discovery ... */ + if (!dt_cpu_ftrs_init(__va(dt_ptr))) + /* Otherwise use the old style CPU table */ + identify_cpu(0, mfspr(SPRN_PVR)); + /* Enable early debugging if any specified (see udbg.h) */ udbg_early_init(); From 7053f80d96967d8e72e9f2a724bbfc3906ce2b07 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 20 Mar 2020 14:21:16 +1100 Subject: [PATCH 540/809] powerpc/64: Prevent stack protection in early boot The previous commit reduced the amount of code that is run before we setup a paca. However there are still a few remaining functions that run with no paca, or worse, with an arbitrary value in r13 that will be used as a paca pointer. In particular the stack protector canary is stored in the paca, so if stack protector is activated for any of these functions we will read the stack canary from wherever r13 points. If r13 happens to point outside of memory we will get a machine check / checkstop. For example if we modify initialise_paca() to trigger stack protection, and then boot in the mambo simulator with r13 poisoned in skiboot before calling the kernel: DEBUG: 19952232: (19952232): INSTRUCTION: PC=0xC0000000191FC1E8: [0x3C4C006D]: addis r2,r12,0x6D [fetch] DEBUG: 19952236: (19952236): INSTRUCTION: PC=0xC00000001807EAD8: [0x7D8802A6]: mflr r12 [fetch] FATAL ERROR: 19952276: (19952276): Check Stop for 0:0: Machine Check with ME bit of MSR off DEBUG: 19952276: (19952276): INSTRUCTION: PC=0xC0000000191FCA7C: [0xE90D0CF8]: ld r8,0xCF8(r13) [Instruction Failed] INFO: 19952276: (19952277): ** Execution stopped: Mambo Error, Machine Check Stop, ** systemsim % bt pc: 0xC0000000191FCA7C initialise_paca+0x54 lr: 0xC0000000191FC22C early_setup+0x44 stack:0x00000000198CBED0 0x0 +0x0 stack:0x00000000198CBF00 0xC0000000191FC22C early_setup+0x44 stack:0x00000000198CBF90 0x1801C968 +0x1801C968 So annotate the relevant functions to ensure stack protection is never enabled for them. Fixes: 06ec27aea9fc ("powerpc/64: add stack protector support") Cc: stable@vger.kernel.org # v4.20+ Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200320032116.1024773-2-mpe@ellerman.id.au --- arch/powerpc/kernel/paca.c | 4 ++-- arch/powerpc/kernel/setup.h | 6 ++++++ arch/powerpc/kernel/setup_64.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0ee6308541b1..3f91ccaa9c74 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -176,7 +176,7 @@ static struct slb_shadow * __init new_slb_shadow(int cpu, unsigned long limit) struct paca_struct **paca_ptrs __read_mostly; EXPORT_SYMBOL(paca_ptrs); -void __init initialise_paca(struct paca_struct *new_paca, int cpu) +void __init __nostackprotector initialise_paca(struct paca_struct *new_paca, int cpu) { #ifdef CONFIG_PPC_PSERIES new_paca->lppaca_ptr = NULL; @@ -205,7 +205,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) } /* Put the paca pointer into r13 and SPRG_PACA */ -void setup_paca(struct paca_struct *new_paca) +void __nostackprotector setup_paca(struct paca_struct *new_paca) { /* Setup r13 */ local_paca = new_paca; diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h index 2dd0d9cb5a20..2ec835574cc9 100644 --- a/arch/powerpc/kernel/setup.h +++ b/arch/powerpc/kernel/setup.h @@ -8,6 +8,12 @@ #ifndef __ARCH_POWERPC_KERNEL_SETUP_H #define __ARCH_POWERPC_KERNEL_SETUP_H +#ifdef CONFIG_CC_IS_CLANG +#define __nostackprotector +#else +#define __nostackprotector __attribute__((__optimize__("no-stack-protector"))) +#endif + void initialize_cache_info(void); void irqstack_early_init(void); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 17886d147dd0..438a9befce41 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -279,7 +279,7 @@ void __init record_spr_defaults(void) * device-tree is not accessible via normal means at this point. */ -void __init early_setup(unsigned long dt_ptr) +void __init __nostackprotector early_setup(unsigned long dt_ptr) { static __initdata struct paca_struct boot_paca; From 8645aaa87963439007773ed8862ae6a29ea15eae Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:38:59 +1100 Subject: [PATCH 541/809] powerpc/eeh: Add sysfs files in late probe Move creating the EEH specific sysfs files into eeh_add_device_late() rather than being open-coded all over the place. Calling the function is generally done immediately after calling eeh_add_device_late() anyway. This is also a correctness fix since currently the sysfs files will be added even if the EEH probe happens to fail. Similarly, on pseries we currently add the sysfs files before calling eeh_add_device_late(). This is flat-out broken since the sysfs files require the pci_dev->dev.archdata.edev pointer to be set, and that is done in eeh_add_device_late(). Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-1-oohall@gmail.com --- arch/powerpc/include/asm/eeh.h | 3 --- arch/powerpc/kernel/eeh.c | 24 +------------------- arch/powerpc/kernel/of_platform.c | 3 --- arch/powerpc/kernel/pci-common.c | 3 --- arch/powerpc/platforms/powernv/eeh-powernv.c | 1 - arch/powerpc/platforms/pseries/eeh_pseries.c | 3 +-- 6 files changed, 2 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 6f9b2a12540a..5a349079057d 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -305,7 +305,6 @@ void eeh_add_device_early(struct pci_dn *); void eeh_add_device_tree_early(struct pci_dn *); void eeh_add_device_late(struct pci_dev *); void eeh_add_device_tree_late(struct pci_bus *); -void eeh_add_sysfs_files(struct pci_bus *); void eeh_remove_device(struct pci_dev *); int eeh_unfreeze_pe(struct eeh_pe *pe); int eeh_pe_reset_and_recover(struct eeh_pe *pe); @@ -368,8 +367,6 @@ static inline void eeh_add_device_late(struct pci_dev *dev) { } static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } -static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } - static inline void eeh_remove_device(struct pci_dev *dev) { } #define EEH_POSSIBLE_ERROR(val, type) (0) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 17cb3e9b5697..087891214739 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1210,6 +1210,7 @@ void eeh_add_device_late(struct pci_dev *dev) dev->dev.archdata.edev = edev; eeh_addr_cache_insert_dev(dev); + eeh_sysfs_add_device(dev); } /** @@ -1237,29 +1238,6 @@ void eeh_add_device_tree_late(struct pci_bus *bus) } EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); -/** - * eeh_add_sysfs_files - Add EEH sysfs files for the indicated PCI bus - * @bus: PCI bus - * - * This routine must be used to add EEH sysfs files for PCI - * devices which are attached to the indicated PCI bus. The PCI bus - * is added after system boot through hotplug or dlpar. - */ -void eeh_add_sysfs_files(struct pci_bus *bus) -{ - struct pci_dev *dev; - - list_for_each_entry(dev, &bus->devices, bus_list) { - eeh_sysfs_add_device(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *subbus = dev->subordinate; - if (subbus) - eeh_add_sysfs_files(subbus); - } - } -} -EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); - /** * eeh_remove_device - Undo EEH setup for the indicated pci device * @dev: pci device to be removed diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 427fc22f72b6..cb6880092dd7 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -86,9 +86,6 @@ static int of_pci_phb_probe(struct platform_device *dev) /* Add probed PCI devices to the device model */ pci_bus_add_devices(phb->bus); - /* sysfs files should only be added after devices are added */ - eeh_add_sysfs_files(phb->bus); - return 0; } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index c6c03416a151..3d2b1cf30b80 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1404,9 +1404,6 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus) /* Add new devices to global lists. Register in proc, sysfs. */ pci_bus_add_devices(bus); - - /* sysfs files should only be added after devices are added */ - eeh_add_sysfs_files(bus); } EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus); diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 6f300ab7f0e9..ef727ecd99cd 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -48,7 +48,6 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev) dev_dbg(&pdev->dev, "EEH: Setting up device\n"); eeh_add_device_early(pdn); eeh_add_device_late(pdev); - eeh_sysfs_add_device(pdev); } static int pnv_eeh_init(void) diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 893ba3f562c4..95bbf9102584 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -68,7 +68,6 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev) } #endif eeh_add_device_early(pdn); - eeh_add_device_late(pdev); #ifdef CONFIG_PCI_IOV if (pdev->is_virtfn) { struct eeh_dev *edev = pdn_to_eeh_dev(pdn); @@ -78,7 +77,7 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev) eeh_add_to_parent_pe(edev); /* Add as VF PE type */ } #endif - eeh_sysfs_add_device(pdev); + eeh_add_device_late(pdev); } /* From 2d0953f7d5acc53a97d0dbfab8b1827e9897a7e6 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:39:00 +1100 Subject: [PATCH 542/809] powerpc/eeh: Remove eeh_add_device_tree_late() On pseries and PowerNV pcibios_bus_add_device() calls eeh_add_device_late() so there's no need to do a separate tree traversal to bind the eeh_dev and pci_dev together setting up the PHB at boot. As a result we can remove eeh_add_device_tree_late(). Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-2-oohall@gmail.com --- arch/powerpc/include/asm/eeh.h | 3 --- arch/powerpc/kernel/eeh.c | 25 ------------------------- arch/powerpc/kernel/of_platform.c | 3 --- arch/powerpc/kernel/pci-common.c | 3 --- 4 files changed, 34 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 5a349079057d..5d1078166417 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -304,7 +304,6 @@ void eeh_addr_cache_init(void); void eeh_add_device_early(struct pci_dn *); void eeh_add_device_tree_early(struct pci_dn *); void eeh_add_device_late(struct pci_dev *); -void eeh_add_device_tree_late(struct pci_bus *); void eeh_remove_device(struct pci_dev *); int eeh_unfreeze_pe(struct eeh_pe *pe); int eeh_pe_reset_and_recover(struct eeh_pe *pe); @@ -365,8 +364,6 @@ static inline void eeh_add_device_tree_early(struct pci_dn *pdn) { } static inline void eeh_add_device_late(struct pci_dev *dev) { } -static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } - static inline void eeh_remove_device(struct pci_dev *dev) { } #define EEH_POSSIBLE_ERROR(val, type) (0) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 087891214739..9cb33706ef80 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1213,31 +1213,6 @@ void eeh_add_device_late(struct pci_dev *dev) eeh_sysfs_add_device(dev); } -/** - * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus - * @bus: PCI bus - * - * This routine must be used to perform EEH initialization for PCI - * devices which are attached to the indicated PCI bus. The PCI bus - * is added after system boot through hotplug or dlpar. - */ -void eeh_add_device_tree_late(struct pci_bus *bus) -{ - struct pci_dev *dev; - - if (eeh_has_flag(EEH_FORCE_DISABLED)) - return; - list_for_each_entry(dev, &bus->devices, bus_list) { - eeh_add_device_late(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *subbus = dev->subordinate; - if (subbus) - eeh_add_device_tree_late(subbus); - } - } -} -EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); - /** * eeh_remove_device - Undo EEH setup for the indicated pci device * @dev: pci device to be removed diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index cb6880092dd7..64edac81c633 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -80,9 +80,6 @@ static int of_pci_phb_probe(struct platform_device *dev) */ pcibios_claim_one_bus(phb->bus); - /* Finish EEH setup */ - eeh_add_device_tree_late(phb->bus); - /* Add probed PCI devices to the device model */ pci_bus_add_devices(phb->bus); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 3d2b1cf30b80..8983afa6d62a 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1399,9 +1399,6 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus) pci_assign_unassigned_bus_resources(bus); } - /* Fixup EEH */ - eeh_add_device_tree_late(bus); - /* Add new devices to global lists. Register in proc, sysfs. */ pci_bus_add_devices(bus); } From a4b4f61db8ccbd2744fc00bed3bdd912278f4595 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:39:01 +1100 Subject: [PATCH 543/809] powerpc/eeh: Do early EEH init only when required The pci hotplug helper (pci_hp_add_devices()) calls eeh_add_device_tree_early() to scan the device-tree for new PCI devices and do the early EEH probe before the device is scanned. This early probe is a no-op in a lot of cases because: a) The early init is only required to satisfy a PAPR requirement that EEH be configured before we start doing config accesses. On PowerNV it is a no-op. b) It's a no-op for devices that have already had their eeh_dev initialised. There are four callers of pci_hp_add_devices(): 1. arch/powerpc/kernel/eeh_driver.c Here the hotplug helper is called when re-scanning pci_devs that were removed during an EEH recovery pass. The EEH stat for each removed device (the eeh_dev) is retained across a recovery pass so the early init is a no-op in this case. 2. drivers/pci/hotplug/pnv_php.c This is also a no-op since the PowerNV hotplug driver is, suprisingly, PowerNV specific. 3. drivers/pci/hotplug/rpaphp_core.c 4. drivers/pci/hotplug/rpaphp_pci.c In these two cases new devices have been hotplugged and FW has provided new DT nodes for each. These are the only two cases where the EEH we might have new PCI device nodes in the DT so these are the only two cases where the early EEH probe needs to be done. We can move the calls to eeh_add_device_tree_early() to the locations where it's needed and remove it from the generic path. This is preparation for making the early EEH probe pseries specific. Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-3-oohall@gmail.com --- arch/powerpc/kernel/pci-hotplug.c | 2 -- drivers/pci/hotplug/rpaphp_core.c | 2 ++ drivers/pci/hotplug/rpaphp_pci.c | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index d6a67f814983..bf83f76563a3 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c @@ -112,8 +112,6 @@ void pci_hp_add_devices(struct pci_bus *bus) struct pci_controller *phb; struct device_node *dn = pci_bus_to_OF_node(bus); - eeh_add_device_tree_early(PCI_DN(dn)); - phb = pci_bus_to_host(bus); mode = PCI_PROBE_NORMAL; diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 5d871ef231fd..392a936c17de 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -493,6 +493,8 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) return retval; if (state == PRESENT) { + eeh_add_device_tree_early(PCI_DN(slot->dn)); + pci_lock_rescan_remove(); pci_hp_add_devices(slot->bus); pci_unlock_rescan_remove(); diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index beca61badeea..61ebbd832afb 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -95,8 +95,10 @@ int rpaphp_enable_slot(struct slot *slot) return -EINVAL; } - if (list_empty(&bus->devices)) + if (list_empty(&bus->devices)) { + eeh_add_device_tree_early(PCI_DN(slot->dn)); pci_hp_add_devices(bus); + } if (!list_empty(&bus->devices)) { slot->state = CONFIGURED; From 3ff32efb62b624e4c07d002ffb294d209689bedd Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:39:02 +1100 Subject: [PATCH 544/809] powerpc/eeh: Remove PHB check in probe This check for a missing PHB has existing in various forms since the initial PPC64 port was upstreamed in 2002. The idea seems to be that we need to guard against creating pci-specific data structures for the non-pci children of a PCI device tree node (e.g. USB devices). However, we only create pci_dn structures for DT nodes that correspond to PCI devices so there's not much point in doing this check in the eeh_probe path. Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-4-oohall@gmail.com --- arch/powerpc/kernel/eeh.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 9cb33706ef80..a9e4ca7b5e09 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1120,7 +1120,6 @@ core_initcall_sync(eeh_init); */ void eeh_add_device_early(struct pci_dn *pdn) { - struct pci_controller *phb = pdn ? pdn->phb : NULL; struct eeh_dev *edev = pdn_to_eeh_dev(pdn); if (!edev) @@ -1129,11 +1128,6 @@ void eeh_add_device_early(struct pci_dn *pdn) if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE)) return; - /* USB Bus children of PCI devices will not have BUID's */ - if (NULL == phb || - (eeh_has_flag(EEH_PROBE_MODE_DEVTREE) && 0 == phb->buid)) - return; - eeh_ops->probe(pdn, NULL); } From b6eebb093cad0feb56c717611ee0d2d7c66b4ec7 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:39:03 +1100 Subject: [PATCH 545/809] powerpc/eeh: Make early EEH init pseries specific The eeh_ops->probe() function is called from two different contexts: 1. On pseries, where we set EEH_PROBE_MODE_DEVTREE, it's called in eeh_add_device_early() which is supposed to run before we create a pci_dev. 2. On PowerNV, where we set EEH_PROBE_MODE_DEV, it's called in eeh_device_add_late() which is supposed to run *after* the pci_dev is created. The "early" probe is required because PAPR requires that we perform an RTAS call to enable EEH support on a device before we start interacting with it via config space or MMIO. This requirement doesn't exist on PowerNV and shoehorning two completely separate initialisation paths into a common interface just results in a convoluted code everywhere. Additionally the early probe requires the probe function to take an pci_dn rather than a pci_dev argument. We'd like to make pci_dn a pseries specific data structure since there's no real requirement for them on PowerNV. To help both goals move the early probe into the pseries containment zone so the platform depedence is more explicit. Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-5-oohall@gmail.com --- arch/powerpc/include/asm/eeh.h | 14 ++-- arch/powerpc/kernel/eeh.c | 46 ------------- arch/powerpc/kernel/of_platform.c | 6 +- arch/powerpc/platforms/powernv/eeh-powernv.c | 6 -- arch/powerpc/platforms/pseries/eeh_pseries.c | 69 +++++++++++++++----- arch/powerpc/platforms/pseries/pci_dlpar.c | 2 +- drivers/pci/hotplug/rpadlpar_core.c | 2 +- drivers/pci/hotplug/rpaphp_core.c | 2 +- drivers/pci/hotplug/rpaphp_pci.c | 2 +- 9 files changed, 66 insertions(+), 83 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 5d1078166417..8580238e4852 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -301,8 +301,6 @@ int __exit eeh_ops_unregister(const char *name); int eeh_check_failure(const volatile void __iomem *token); int eeh_dev_check_failure(struct eeh_dev *edev); void eeh_addr_cache_init(void); -void eeh_add_device_early(struct pci_dn *); -void eeh_add_device_tree_early(struct pci_dn *); void eeh_add_device_late(struct pci_dev *); void eeh_remove_device(struct pci_dev *); int eeh_unfreeze_pe(struct eeh_pe *pe); @@ -358,10 +356,6 @@ static inline int eeh_check_failure(const volatile void __iomem *token) static inline void eeh_addr_cache_init(void) { } -static inline void eeh_add_device_early(struct pci_dn *pdn) { } - -static inline void eeh_add_device_tree_early(struct pci_dn *pdn) { } - static inline void eeh_add_device_late(struct pci_dev *dev) { } static inline void eeh_remove_device(struct pci_dev *dev) { } @@ -370,6 +364,14 @@ static inline void eeh_remove_device(struct pci_dev *dev) { } #define EEH_IO_ERROR_VALUE(size) (-1UL) #endif /* CONFIG_EEH */ +#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_EEH) +void pseries_eeh_init_edev(struct pci_dn *pdn); +void pseries_eeh_init_edev_recursive(struct pci_dn *pdn); +#else +static inline void pseries_eeh_add_device_early(struct pci_dn *pdn) { } +static inline void pseries_eeh_add_device_tree_early(struct pci_dn *pdn) { } +#endif + #ifdef CONFIG_PPC64 /* * MMIO read/write operations with EEH support. diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index a9e4ca7b5e09..55d3ef6e5b9c 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1106,52 +1106,6 @@ static int eeh_init(void) core_initcall_sync(eeh_init); -/** - * eeh_add_device_early - Enable EEH for the indicated device node - * @pdn: PCI device node for which to set up EEH - * - * This routine must be used to perform EEH initialization for PCI - * devices that were added after system boot (e.g. hotplug, dlpar). - * This routine must be called before any i/o is performed to the - * adapter (inluding any config-space i/o). - * Whether this actually enables EEH or not for this device depends - * on the CEC architecture, type of the device, on earlier boot - * command-line arguments & etc. - */ -void eeh_add_device_early(struct pci_dn *pdn) -{ - struct eeh_dev *edev = pdn_to_eeh_dev(pdn); - - if (!edev) - return; - - if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE)) - return; - - eeh_ops->probe(pdn, NULL); -} - -/** - * eeh_add_device_tree_early - Enable EEH for the indicated device - * @pdn: PCI device node - * - * This routine must be used to perform EEH initialization for the - * indicated PCI device that was added after system boot (e.g. - * hotplug, dlpar). - */ -void eeh_add_device_tree_early(struct pci_dn *pdn) -{ - struct pci_dn *n; - - if (!pdn) - return; - - list_for_each_entry(n, &pdn->child_list, list) - eeh_add_device_tree_early(n); - eeh_add_device_early(pdn); -} -EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); - /** * eeh_add_device_late - Perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 64edac81c633..71a3f97dc988 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -62,13 +62,9 @@ static int of_pci_phb_probe(struct platform_device *dev) /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); - /* Create EEH devices for the PHB */ + /* Create EEH PEs for the PHB */ eeh_dev_phb_init_dynamic(phb); - /* Register devices with EEH */ - if (dev->dev.of_node->child) - eeh_add_device_tree_early(PCI_DN(dev->dev.of_node)); - /* Scan the bus */ pcibios_scan_phb(phb); if (phb->bus == NULL) diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index ef727ecd99cd..eaa8dfefa124 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -40,13 +40,7 @@ static int eeh_event_irq = -EINVAL; void pnv_pcibios_bus_add_device(struct pci_dev *pdev) { - struct pci_dn *pdn = pci_get_pdn(pdev); - - if (!pdn || eeh_has_flag(EEH_FORCE_DISABLED)) - return; - dev_dbg(&pdev->dev, "EEH: Setting up device\n"); - eeh_add_device_early(pdn); eeh_add_device_late(pdev); } diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 95bbf9102584..1ca7cf0fc0d8 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -67,7 +67,7 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev) pdn->pe_number = physfn_pdn->pe_num_map[pdn->vf_index]; } #endif - eeh_add_device_early(pdn); + pseries_eeh_init_edev(pdn); #ifdef CONFIG_PCI_IOV if (pdev->is_virtfn) { struct eeh_dev *edev = pdn_to_eeh_dev(pdn); @@ -221,15 +221,16 @@ static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap) } /** - * pseries_eeh_probe - EEH probe on the given device - * @pdn: PCI device node - * @data: Unused + * pseries_eeh_init_edev - initialise the eeh_dev and eeh_pe for a pci_dn * - * When EEH module is installed during system boot, all PCI devices - * are checked one by one to see if it supports EEH. The function - * is introduced for the purpose. + * @pdn: PCI device node + * + * When we discover a new PCI device via the device-tree we create a + * corresponding pci_dn and we allocate, but don't initialise, an eeh_dev. + * This function takes care of the initialisation and inserts the eeh_dev + * into the correct eeh_pe. If no eeh_pe exists we'll allocate one. */ -static void *pseries_eeh_probe(struct pci_dn *pdn, void *data) +void pseries_eeh_init_edev(struct pci_dn *pdn) { struct eeh_dev *edev; struct eeh_pe pe; @@ -237,18 +238,35 @@ static void *pseries_eeh_probe(struct pci_dn *pdn, void *data) int enable = 0; int ret; - /* Retrieve OF node and eeh device */ + if (WARN_ON_ONCE(!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))) + return; + + /* + * Find the eeh_dev for this pdn. The storage for the eeh_dev was + * allocated at the same time as the pci_dn. + * + * XXX: We should probably re-visit that. + */ edev = pdn_to_eeh_dev(pdn); - if (!edev || edev->pe) - return NULL; + if (!edev) + return; + + /* + * If ->pe is set then we've already probed this device. We hit + * this path when a pci_dev is removed and rescanned while recovering + * a PE (i.e. for devices where the driver doesn't support error + * recovery). + */ + if (edev->pe) + return; /* Check class/vendor/device IDs */ if (!pdn->vendor_id || !pdn->device_id || !pdn->class_code) - return NULL; + return; /* Skip for PCI-ISA bridge */ if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) - return NULL; + return; eeh_edev_dbg(edev, "Probing device\n"); @@ -315,10 +333,30 @@ static void *pseries_eeh_probe(struct pci_dn *pdn, void *data) /* Save memory bars */ eeh_save_bars(edev); - - return NULL; } +/** + * pseries_eeh_init_edev_recursive - Enable EEH for the indicated device + * @pdn: PCI device node + * + * This routine must be used to perform EEH initialization for the + * indicated PCI device that was added after system boot (e.g. + * hotplug, dlpar). + */ +void pseries_eeh_init_edev_recursive(struct pci_dn *pdn) +{ + struct pci_dn *n; + + if (!pdn) + return; + + list_for_each_entry(n, &pdn->child_list, list) + pseries_eeh_init_edev_recursive(n); + + pseries_eeh_init_edev(pdn); +} +EXPORT_SYMBOL_GPL(pseries_eeh_init_edev_recursive); + /** * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable * @pe: EEH PE @@ -775,7 +813,6 @@ static int pseries_notify_resume(struct pci_dn *pdn) static struct eeh_ops pseries_eeh_ops = { .name = "pseries", .init = pseries_eeh_init, - .probe = pseries_eeh_probe, .set_option = pseries_eeh_set_option, .get_pe_addr = pseries_eeh_get_pe_addr, .get_state = pseries_eeh_get_state, diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 361986e4354e..b3a38f5a6b68 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -37,7 +37,7 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn) eeh_dev_phb_init_dynamic(phb); if (dn->child) - eeh_add_device_tree_early(PCI_DN(dn)); + pseries_eeh_init_edev_recursive(PCI_DN(dn)); pcibios_scan_phb(phb); pcibios_finish_adding_to_bus(phb->bus); diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 977946e4e613..c5eb509c72f0 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -140,7 +140,7 @@ static void dlpar_pci_add_bus(struct device_node *dn) struct pci_controller *phb = pdn->phb; struct pci_dev *dev = NULL; - eeh_add_device_tree_early(pdn); + pseries_eeh_init_edev_recursive(pdn); /* Add EADS device to PHB bus, adding new entry to bus->devices */ dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 392a936c17de..6504869efabc 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -493,7 +493,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) return retval; if (state == PRESENT) { - eeh_add_device_tree_early(PCI_DN(slot->dn)); + pseries_eeh_init_edev_recursive(PCI_DN(slot->dn)); pci_lock_rescan_remove(); pci_hp_add_devices(slot->bus); diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 61ebbd832afb..c380bdacd146 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -96,7 +96,7 @@ int rpaphp_enable_slot(struct slot *slot) } if (list_empty(&bus->devices)) { - eeh_add_device_tree_early(PCI_DN(slot->dn)); + pseries_eeh_init_edev_recursive(PCI_DN(slot->dn)); pci_hp_add_devices(bus); } From e86350f70a02e5b4e26b0eccedb575a7490bc834 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Mar 2020 18:39:04 +1100 Subject: [PATCH 546/809] powerpc/eeh: Rework eeh_ops->probe() With the EEH early probe now being pseries specific there's no need for eeh_ops->probe() to take a pci_dn. Instead, we can make it take a pci_dev and use the probe function to map a pci_dev to an eeh_dev. This allows the platform to implement it's own method for finding (or creating) an eeh_dev for a given pci_dev which also removes a use of pci_dn in generic EEH code. This patch also renames eeh_device_add_late() to eeh_device_probe(). This better reflects what it does does and removes the last vestiges of the early/late EEH probe split. Reviewed-by: Sam Bobroff Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306073904.4737-6-oohall@gmail.com --- arch/powerpc/include/asm/eeh.h | 6 +-- arch/powerpc/kernel/eeh.c | 46 ++++++++++---------- arch/powerpc/platforms/powernv/eeh-powernv.c | 30 ++++++------- arch/powerpc/platforms/pseries/eeh_pseries.c | 23 +++++++++- 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 8580238e4852..964a54292b36 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -215,7 +215,7 @@ enum { struct eeh_ops { char *name; int (*init)(void); - void* (*probe)(struct pci_dn *pdn, void *data); + struct eeh_dev *(*probe)(struct pci_dev *pdev); int (*set_option)(struct eeh_pe *pe, int option); int (*get_pe_addr)(struct eeh_pe *pe); int (*get_state)(struct eeh_pe *pe, int *delay); @@ -301,7 +301,7 @@ int __exit eeh_ops_unregister(const char *name); int eeh_check_failure(const volatile void __iomem *token); int eeh_dev_check_failure(struct eeh_dev *edev); void eeh_addr_cache_init(void); -void eeh_add_device_late(struct pci_dev *); +void eeh_probe_device(struct pci_dev *pdev); void eeh_remove_device(struct pci_dev *); int eeh_unfreeze_pe(struct eeh_pe *pe); int eeh_pe_reset_and_recover(struct eeh_pe *pe); @@ -356,7 +356,7 @@ static inline int eeh_check_failure(const volatile void __iomem *token) static inline void eeh_addr_cache_init(void) { } -static inline void eeh_add_device_late(struct pci_dev *dev) { } +static inline void eeh_probe_device(struct pci_dev *dev) { } static inline void eeh_remove_device(struct pci_dev *dev) { } diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 55d3ef6e5b9c..7cdcb413bb44 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1107,35 +1107,43 @@ static int eeh_init(void) core_initcall_sync(eeh_init); /** - * eeh_add_device_late - Perform EEH initialization for the indicated pci device + * eeh_probe_device() - Perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH * * This routine must be used to complete EEH initialization for PCI * devices that were added after system boot (e.g. hotplug, dlpar). */ -void eeh_add_device_late(struct pci_dev *dev) +void eeh_probe_device(struct pci_dev *dev) { - struct pci_dn *pdn; struct eeh_dev *edev; - if (!dev) - return; + pr_debug("EEH: Adding device %s\n", pci_name(dev)); - pdn = pci_get_pdn_by_devfn(dev->bus, dev->devfn); - edev = pdn_to_eeh_dev(pdn); - eeh_edev_dbg(edev, "Adding device\n"); - if (edev->pdev == dev) { - eeh_edev_dbg(edev, "Device already referenced!\n"); + /* + * pci_dev_to_eeh_dev() can only work if eeh_probe_dev() was + * already called for this device. + */ + if (WARN_ON_ONCE(pci_dev_to_eeh_dev(dev))) { + pci_dbg(dev, "Already bound to an eeh_dev!\n"); + return; + } + + edev = eeh_ops->probe(dev); + if (!edev) { + pr_debug("EEH: Adding device failed\n"); return; } /* - * The EEH cache might not be removed correctly because of - * unbalanced kref to the device during unplug time, which - * relies on pcibios_release_device(). So we have to remove - * that here explicitly. + * FIXME: We rely on pcibios_release_device() to remove the + * existing EEH state. The release function is only called if + * the pci_dev's refcount drops to zero so if something is + * keeping a ref to a device (e.g. a filesystem) we need to + * remove the old EEH state. + * + * FIXME: HEY MA, LOOK AT ME, NO LOCKING! */ - if (edev->pdev) { + if (edev->pdev && edev->pdev != dev) { eeh_rmv_from_parent_pe(edev); eeh_addr_cache_rmv_dev(edev->pdev); eeh_sysfs_remove_device(edev->pdev); @@ -1146,17 +1154,11 @@ void eeh_add_device_late(struct pci_dev *dev) * into error handler afterwards. */ edev->mode |= EEH_DEV_NO_HANDLER; - - edev->pdev = NULL; - dev->dev.archdata.edev = NULL; } - if (eeh_has_flag(EEH_PROBE_MODE_DEV)) - eeh_ops->probe(pdn, NULL); - + /* bind the pdev and the edev together */ edev->pdev = dev; dev->dev.archdata.edev = edev; - eeh_addr_cache_insert_dev(dev); eeh_sysfs_add_device(dev); } diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index eaa8dfefa124..79409e005fcd 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -41,7 +41,7 @@ static int eeh_event_irq = -EINVAL; void pnv_pcibios_bus_add_device(struct pci_dev *pdev) { dev_dbg(&pdev->dev, "EEH: Setting up device\n"); - eeh_add_device_late(pdev); + eeh_probe_device(pdev); } static int pnv_eeh_init(void) @@ -340,23 +340,13 @@ static int pnv_eeh_find_ecap(struct pci_dn *pdn, int cap) /** * pnv_eeh_probe - Do probe on PCI device - * @pdn: PCI device node - * @data: unused + * @pdev: pci_dev to probe * - * When EEH module is installed during system boot, all PCI devices - * are checked one by one to see if it supports EEH. The function - * is introduced for the purpose. By default, EEH has been enabled - * on all PCI devices. That's to say, we only need do necessary - * initialization on the corresponding eeh device and create PE - * accordingly. - * - * It's notable that's unsafe to retrieve the EEH device through - * the corresponding PCI device. During the PCI device hotplug, which - * was possiblly triggered by EEH core, the binding between EEH device - * and the PCI device isn't built yet. + * Create, or find the existing, eeh_dev for this pci_dev. */ -static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) +static struct eeh_dev *pnv_eeh_probe(struct pci_dev *pdev) { + struct pci_dn *pdn = pci_get_pdn(pdev); struct pci_controller *hose = pdn->phb; struct pnv_phb *phb = hose->private_data; struct eeh_dev *edev = pdn_to_eeh_dev(pdn); @@ -373,6 +363,14 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) if (!edev || edev->pe) return NULL; + /* already configured? */ + if (edev->pdev) { + pr_debug("%s: found existing edev for %04x:%02x:%02x.%01x\n", + __func__, hose->global_number, config_addr >> 8, + PCI_SLOT(config_addr), PCI_FUNC(config_addr)); + return edev; + } + /* Skip for PCI-ISA bridge */ if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) return NULL; @@ -464,7 +462,7 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) eeh_edev_dbg(edev, "EEH enabled on device\n"); - return NULL; + return edev; } /** diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 1ca7cf0fc0d8..845342814edc 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -77,7 +77,7 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev) eeh_add_to_parent_pe(edev); /* Add as VF PE type */ } #endif - eeh_add_device_late(pdev); + eeh_probe_device(pdev); } /* @@ -335,6 +335,26 @@ void pseries_eeh_init_edev(struct pci_dn *pdn) eeh_save_bars(edev); } +static struct eeh_dev *pseries_eeh_probe(struct pci_dev *pdev) +{ + struct eeh_dev *edev; + struct pci_dn *pdn; + + pdn = pci_get_pdn_by_devfn(pdev->bus, pdev->devfn); + if (!pdn) + return NULL; + + /* + * If the system supports EEH on this device then the eeh_dev was + * configured and inserted into a PE in pseries_eeh_init_edev() + */ + edev = pdn_to_eeh_dev(pdn); + if (!edev || !edev->pe) + return NULL; + + return edev; +} + /** * pseries_eeh_init_edev_recursive - Enable EEH for the indicated device * @pdn: PCI device node @@ -813,6 +833,7 @@ static int pseries_notify_resume(struct pci_dn *pdn) static struct eeh_ops pseries_eeh_ops = { .name = "pseries", .init = pseries_eeh_init, + .probe = pseries_eeh_probe, .set_option = pseries_eeh_set_option, .get_pe_addr = pseries_eeh_get_pe_addr, .get_state = pseries_eeh_get_state, From adde8715cf0571878d37fcb20595aad57b923bab Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 21 Mar 2020 01:24:36 +1000 Subject: [PATCH 547/809] powerpc/pseries: Avoid harmless preempt warning Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200320152436.1468651-1-npiggin@gmail.com --- arch/powerpc/platforms/pseries/lpar.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 3c3da25b445c..e4ed5317f117 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -636,8 +636,16 @@ static const struct proc_ops vcpudispatch_stats_freq_proc_ops = { static int __init vcpudispatch_stats_procfs_init(void) { - if (!lppaca_shared_proc(get_lppaca())) + /* + * Avoid smp_processor_id while preemptible. All CPUs should have + * the same value for lppaca_shared_proc. + */ + preempt_disable(); + if (!lppaca_shared_proc(get_lppaca())) { + preempt_enable(); return 0; + } + preempt_enable(); if (!proc_create("powerpc/vcpudispatch_stats", 0600, NULL, &vcpudispatch_stats_proc_ops)) From af6cf95c4d003fccd6c2ecc99a598fb854b537e7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 23 Mar 2020 15:27:29 -0700 Subject: [PATCH 548/809] powerpc/maple: Fix declaration made after definition When building ppc64 defconfig, Clang errors (trimmed for brevity): arch/powerpc/platforms/maple/setup.c:365:1: error: attribute declaration must precede definition [-Werror,-Wignored-attributes] machine_device_initcall(maple, maple_cpc925_edac_setup); ^ machine_device_initcall expands to __define_machine_initcall, which in turn has the macro machine_is used in it, which declares mach_##name with an __attribute__((weak)). define_machine actually defines mach_##name, which in this file happens before the declaration, hence the warning. To fix this, move define_machine after machine_device_initcall so that the declaration occurs before the definition, which matches how machine_device_initcall and define_machine work throughout arch/powerpc. While we're here, remove some spaces before tabs. Fixes: 8f101a051ef0 ("edac: cpc925 MC platform device setup") Reported-by: Nick Desaulniers Suggested-by: Ilie Halip Signed-off-by: Nathan Chancellor Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200323222729.15365-1-natechancellor@gmail.com --- arch/powerpc/platforms/maple/setup.c | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 6f019df37916..15b2c6eb506d 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -291,23 +291,6 @@ static int __init maple_probe(void) return 1; } -define_machine(maple) { - .name = "Maple", - .probe = maple_probe, - .setup_arch = maple_setup_arch, - .init_IRQ = maple_init_IRQ, - .pci_irq_fixup = maple_pci_irq_fixup, - .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, - .restart = maple_restart, - .halt = maple_halt, - .get_boot_time = maple_get_boot_time, - .set_rtc_time = maple_set_rtc_time, - .get_rtc_time = maple_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = maple_progress, - .power_save = power4_idle, -}; - #ifdef CONFIG_EDAC /* * Register a platform device for CPC925 memory controller on @@ -364,3 +347,20 @@ static int __init maple_cpc925_edac_setup(void) } machine_device_initcall(maple, maple_cpc925_edac_setup); #endif + +define_machine(maple) { + .name = "Maple", + .probe = maple_probe, + .setup_arch = maple_setup_arch, + .init_IRQ = maple_init_IRQ, + .pci_irq_fixup = maple_pci_irq_fixup, + .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, + .restart = maple_restart, + .halt = maple_halt, + .get_boot_time = maple_get_boot_time, + .set_rtc_time = maple_set_rtc_time, + .get_rtc_time = maple_get_rtc_time, + .calibrate_decr = generic_calibrate_decr, + .progress = maple_progress, + .power_save = power4_idle, +}; From 21f8b2fa3ca5b01f7a2b51b89ce97a3705a15aa0 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 18 Feb 2020 19:38:27 +0000 Subject: [PATCH 549/809] powerpc/kprobes: Ignore traps that happened in real mode When a program check exception happens while MMU translation is disabled, following Oops happens in kprobe_handler() in the following code: } else if (*addr != BREAKPOINT_INSTRUCTION) { BUG: Unable to handle kernel data access on read at 0x0000e268 Faulting instruction address: 0xc000ec34 Oops: Kernel access of bad area, sig: 11 [#1] BE PAGE_SIZE=16K PREEMPT CMPC885 Modules linked in: CPU: 0 PID: 429 Comm: cat Not tainted 5.6.0-rc1-s3k-dev-00824-g84195dc6c58a #3267 NIP: c000ec34 LR: c000ecd8 CTR: c019cab8 REGS: ca4d3b58 TRAP: 0300 Not tainted (5.6.0-rc1-s3k-dev-00824-g84195dc6c58a) MSR: 00001032 CR: 2a4d3c52 XER: 00000000 DAR: 0000e268 DSISR: c0000000 GPR00: c000b09c ca4d3c10 c66d0620 00000000 ca4d3c60 00000000 00009032 00000000 GPR08: 00020000 00000000 c087de44 c000afe0 c66d0ad0 100d3dd6 fffffff3 00000000 GPR16: 00000000 00000041 00000000 ca4d3d70 00000000 00000000 0000416d 00000000 GPR24: 00000004 c53b6128 00000000 0000e268 00000000 c07c0000 c07bb6fc ca4d3c60 NIP [c000ec34] kprobe_handler+0x128/0x290 LR [c000ecd8] kprobe_handler+0x1cc/0x290 Call Trace: [ca4d3c30] [c000b09c] program_check_exception+0xbc/0x6fc [ca4d3c50] [c000e43c] ret_from_except_full+0x0/0x4 --- interrupt: 700 at 0xe268 Instruction dump: 913e0008 81220000 38600001 3929ffff 91220000 80010024 bb410008 7c0803a6 38210020 4e800020 38600000 4e800020 <813b0000> 6d2a7fe0 2f8a0008 419e0154 ---[ end trace 5b9152d4cdadd06d ]--- kprobe is not prepared to handle events in real mode and functions running in real mode should have been blacklisted, so kprobe_handler() can safely bail out telling 'this trap is not mine' for any trap that happened while in real-mode. If the trap happened with MSR_IR or MSR_DR cleared, return 0 immediately. Reported-by: Larry Finger Fixes: 6cc89bad60a6 ("powerpc/kprobes: Invoke handlers directly") Cc: stable@vger.kernel.org # v4.10+ Signed-off-by: Christophe Leroy Reviewed-by: Masami Hiramatsu Reviewed-by: Naveen N. Rao Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/424331e2006e7291a1bfe40e7f3fa58825f565e1.1582054578.git.christophe.leroy@c-s.fr --- arch/powerpc/kernel/kprobes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 3aaff3365134..81efb605113e 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -264,6 +264,9 @@ int kprobe_handler(struct pt_regs *regs) if (user_mode(regs)) return 0; + if (!(regs->msr & MSR_IR) || !(regs->msr & MSR_DR)) + return 0; + /* * We don't want to be preempted for the entire * duration of kprobe processing From 7928f4f6a20c321ef5ec7f665b3a60dc17b18b69 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 23 Mar 2020 13:25:28 +0100 Subject: [PATCH 550/809] MAINTAINERS: dt: update reference for arm-integrator.txt This file was renamed. Update references accordingly. Fixes: 78c7d8f96b6f ("dt-bindings: clock: Create YAML schema for ICST clocks") Signed-off-by: Mauro Carvalho Chehab Link: https://lkml.kernel.org/r/491d2928a47f59da3636bc63103a5f63fec72b1a.1584966325.git.mchehab+huawei@kernel.org Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 38fe2f3f7b6f..04499e55218b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1280,7 +1280,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/arm-boards F: Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt -F: Documentation/devicetree/bindings/clock/arm-integrator.txt +F: Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml F: Documentation/devicetree/bindings/i2c/i2c-versatile.txt F: Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt F: Documentation/devicetree/bindings/mtd/arm-versatile.txt From 187e5cd2d133771e978e7e4ea6aa684dfd1ce6ab Mon Sep 17 00:00:00 2001 From: Xiaolong Zhang Date: Wed, 4 Mar 2020 15:27:24 +0800 Subject: [PATCH 551/809] clk: sprd: add gate for pll clocks Some sprd's gate clocks are used to the switch of pll, which need to wait a certain time for stable after being enabled. Signed-off-by: Xiaolong Zhang Signed-off-by: Chunyan Zhang Link: https://lkml.kernel.org/r/20200304072730.9193-2-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/sprd/gate.c | 17 +++++++++++++++++ drivers/clk/sprd/gate.h | 21 +++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sprd/gate.c b/drivers/clk/sprd/gate.c index f59d1936b412..574cfc116bbc 100644 --- a/drivers/clk/sprd/gate.c +++ b/drivers/clk/sprd/gate.c @@ -79,6 +79,17 @@ static int sprd_sc_gate_enable(struct clk_hw *hw) return 0; } + +static int sprd_pll_sc_gate_prepare(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + + clk_sc_gate_toggle(sg, true); + udelay(sg->udelay); + + return 0; +} + static int sprd_gate_is_enabled(struct clk_hw *hw) { struct sprd_gate *sg = hw_to_sprd_gate(hw); @@ -109,3 +120,9 @@ const struct clk_ops sprd_sc_gate_ops = { }; EXPORT_SYMBOL_GPL(sprd_sc_gate_ops); +const struct clk_ops sprd_pll_sc_gate_ops = { + .unprepare = sprd_sc_gate_disable, + .prepare = sprd_pll_sc_gate_prepare, + .is_enabled = sprd_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops); diff --git a/drivers/clk/sprd/gate.h b/drivers/clk/sprd/gate.h index dc352ea55e1f..d380d77b8dce 100644 --- a/drivers/clk/sprd/gate.h +++ b/drivers/clk/sprd/gate.h @@ -14,16 +14,19 @@ struct sprd_gate { u32 enable_mask; u16 flags; u16 sc_offset; + u16 udelay; struct sprd_clk_common common; }; -#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ - _enable_mask, _flags, _gate_flags, _ops) \ +#define SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, _ops) \ struct sprd_gate _struct = { \ .enable_mask = _enable_mask, \ .sc_offset = _sc_offset, \ .flags = _gate_flags, \ + .udelay = _udelay, \ .common = { \ .regmap = NULL, \ .reg = _reg, \ @@ -34,6 +37,12 @@ struct sprd_gate { } \ } +#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ + _enable_mask, _flags, _gate_flags, _ops) \ + SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, 0, _ops) + #define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \ _enable_mask, _flags, _gate_flags) \ SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \ @@ -46,6 +55,13 @@ struct sprd_gate { _enable_mask, _flags, _gate_flags, \ &sprd_sc_gate_ops) +#define SPRD_PLL_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \ + _enable_mask, _flags, _gate_flags, _udelay) \ + SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, \ + &sprd_pll_sc_gate_ops) + static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); @@ -55,5 +71,6 @@ static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw) extern const struct clk_ops sprd_gate_ops; extern const struct clk_ops sprd_sc_gate_ops; +extern const struct clk_ops sprd_pll_sc_gate_ops; #endif /* _SPRD_GATE_H_ */ From 2112d1ddb97a6fd0508412bbc31ba65cff44b07b Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:25 +0800 Subject: [PATCH 552/809] dt-bindings: clk: sprd: rename the common file name sprd.txt to SoC specific Only SC9860 clocks were described in sprd.txt, rename it with a SoC specific name, so that we can add more SoC support. Signed-off-by: Chunyan Zhang Acked-by: Rob Herring Link: https://lkml.kernel.org/r/20200304072730.9193-3-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/{sprd.txt => sprd,sc9860-clk.txt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Documentation/devicetree/bindings/clock/{sprd.txt => sprd,sc9860-clk.txt} (98%) diff --git a/Documentation/devicetree/bindings/clock/sprd.txt b/Documentation/devicetree/bindings/clock/sprd,sc9860-clk.txt similarity index 98% rename from Documentation/devicetree/bindings/clock/sprd.txt rename to Documentation/devicetree/bindings/clock/sprd,sc9860-clk.txt index e9d179e882d9..aaaf02ca2a6a 100644 --- a/Documentation/devicetree/bindings/clock/sprd.txt +++ b/Documentation/devicetree/bindings/clock/sprd,sc9860-clk.txt @@ -1,4 +1,4 @@ -Spreadtrum Clock Binding +Spreadtrum SC9860 Clock Binding ------------------------ Required properties: From eba8ba8adaf358ee7f9e6946dd5cfc7db629f67f Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:26 +0800 Subject: [PATCH 553/809] dt-bindings: clk: sprd: add bindings for sc9863a clock controller add a new bindings to describe sc9863a clock compatible string. Signed-off-by: Chunyan Zhang Link: https://lkml.kernel.org/r/20200304072730.9193-4-zhang.lyra@gmail.com Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/sprd,sc9863a-clk.yaml | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/sprd,sc9863a-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/sprd,sc9863a-clk.yaml b/Documentation/devicetree/bindings/clock/sprd,sc9863a-clk.yaml new file mode 100644 index 000000000000..bb3a78d8105e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sprd,sc9863a-clk.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2019 Unisoc Inc. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/clock/sprd,sc9863a-clk.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: SC9863A Clock Control Unit Device Tree Bindings + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + "#clock-cells": + const: 1 + + compatible : + enum: + - sprd,sc9863a-ap-clk + - sprd,sc9863a-aon-clk + - sprd,sc9863a-apahb-gate + - sprd,sc9863a-pmu-gate + - sprd,sc9863a-aonapb-gate + - sprd,sc9863a-pll + - sprd,sc9863a-mpll + - sprd,sc9863a-rpll + - sprd,sc9863a-dpll + - sprd,sc9863a-mm-gate + - sprd,sc9863a-apapb-gate + + clocks: + minItems: 1 + maxItems: 4 + description: | + The input parent clock(s) phandle for this clock, only list fixed + clocks which are declared in devicetree. + + clock-names: + minItems: 1 + maxItems: 4 + items: + - const: ext-26m + - const: ext-32k + - const: ext-4m + - const: rco-100m + + reg: + maxItems: 1 + +required: + - compatible + - '#clock-cells' + +if: + properties: + compatible: + enum: + - sprd,sc9863a-ap-clk + - sprd,sc9863a-aon-clk +then: + required: + - reg + +else: + description: | + Other SC9863a clock nodes should be the child of a syscon node in + which compatible string shoule be: + "sprd,sc9863a-glbregs", "syscon", "simple-mfd" + + The 'reg' property for the clock node is also required if there is a sub + range of registers for the clocks. + +examples: + - | + ap_clk: clock-controller@21500000 { + compatible = "sprd,sc9863a-ap-clk"; + reg = <0 0x21500000 0 0x1000>; + clocks = <&ext_26m>, <&ext_32k>; + clock-names = "ext-26m", "ext-32k"; + #clock-cells = <1>; + }; + + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + ap_ahb_regs: syscon@20e00000 { + compatible = "sprd,sc9863a-glbregs", "syscon", "simple-mfd"; + reg = <0 0x20e00000 0 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x20e00000 0x4000>; + + apahb_gate: apahb-gate@0 { + compatible = "sprd,sc9863a-apahb-gate"; + reg = <0x0 0x1020>; + #clock-cells = <1>; + }; + }; + }; + +... From be7ef655be9387113b50ded49dbdd1a97a6d7e85 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:27 +0800 Subject: [PATCH 554/809] clk: sprd: Add dt-bindings include file for SC9863A This file defines all SC9863A clock indexes, it should be included in the device tree in which there's device using the clocks. Signed-off-by: Chunyan Zhang Reviewed-by: Rob Herring Link: https://lkml.kernel.org/r/20200304072730.9193-5-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/sprd,sc9863a-clk.h | 334 +++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 include/dt-bindings/clock/sprd,sc9863a-clk.h diff --git a/include/dt-bindings/clock/sprd,sc9863a-clk.h b/include/dt-bindings/clock/sprd,sc9863a-clk.h new file mode 100644 index 000000000000..901ba59676c2 --- /dev/null +++ b/include/dt-bindings/clock/sprd,sc9863a-clk.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Unisoc SC9863A platform clocks + * + * Copyright (C) 2019, Unisoc Communications Inc. + */ + +#ifndef _DT_BINDINGS_CLK_SC9863A_H_ +#define _DT_BINDINGS_CLK_SC9863A_H_ + +#define CLK_MPLL0_GATE 0 +#define CLK_DPLL0_GATE 1 +#define CLK_LPLL_GATE 2 +#define CLK_GPLL_GATE 3 +#define CLK_DPLL1_GATE 4 +#define CLK_MPLL1_GATE 5 +#define CLK_MPLL2_GATE 6 +#define CLK_ISPPLL_GATE 7 +#define CLK_PMU_APB_NUM (CLK_ISPPLL_GATE + 1) + +#define CLK_AUDIO_GATE 0 +#define CLK_RPLL 1 +#define CLK_RPLL_390M 2 +#define CLK_RPLL_260M 3 +#define CLK_RPLL_195M 4 +#define CLK_RPLL_26M 5 +#define CLK_ANLG_PHY_G5_NUM (CLK_RPLL_26M + 1) + +#define CLK_TWPLL 0 +#define CLK_TWPLL_768M 1 +#define CLK_TWPLL_384M 2 +#define CLK_TWPLL_192M 3 +#define CLK_TWPLL_96M 4 +#define CLK_TWPLL_48M 5 +#define CLK_TWPLL_24M 6 +#define CLK_TWPLL_12M 7 +#define CLK_TWPLL_512M 8 +#define CLK_TWPLL_256M 9 +#define CLK_TWPLL_128M 10 +#define CLK_TWPLL_64M 11 +#define CLK_TWPLL_307M2 12 +#define CLK_TWPLL_219M4 13 +#define CLK_TWPLL_170M6 14 +#define CLK_TWPLL_153M6 15 +#define CLK_TWPLL_76M8 16 +#define CLK_TWPLL_51M2 17 +#define CLK_TWPLL_38M4 18 +#define CLK_TWPLL_19M2 19 +#define CLK_LPLL 20 +#define CLK_LPLL_409M6 21 +#define CLK_LPLL_245M76 22 +#define CLK_GPLL 23 +#define CLK_ISPPLL 24 +#define CLK_ISPPLL_468M 25 +#define CLK_ANLG_PHY_G1_NUM (CLK_ISPPLL_468M + 1) + +#define CLK_DPLL0 0 +#define CLK_DPLL1 1 +#define CLK_DPLL0_933M 2 +#define CLK_DPLL0_622M3 3 +#define CLK_DPLL0_400M 4 +#define CLK_DPLL0_266M7 5 +#define CLK_DPLL0_123M1 6 +#define CLK_DPLL0_50M 7 +#define CLK_ANLG_PHY_G7_NUM (CLK_DPLL0_50M + 1) + +#define CLK_MPLL0 0 +#define CLK_MPLL1 1 +#define CLK_MPLL2 2 +#define CLK_MPLL2_675M 3 +#define CLK_ANLG_PHY_G4_NUM (CLK_MPLL2_675M + 1) + +#define CLK_AP_APB 0 +#define CLK_AP_CE 1 +#define CLK_NANDC_ECC 2 +#define CLK_NANDC_26M 3 +#define CLK_EMMC_32K 4 +#define CLK_SDIO0_32K 5 +#define CLK_SDIO1_32K 6 +#define CLK_SDIO2_32K 7 +#define CLK_OTG_UTMI 8 +#define CLK_AP_UART0 9 +#define CLK_AP_UART1 10 +#define CLK_AP_UART2 11 +#define CLK_AP_UART3 12 +#define CLK_AP_UART4 13 +#define CLK_AP_I2C0 14 +#define CLK_AP_I2C1 15 +#define CLK_AP_I2C2 16 +#define CLK_AP_I2C3 17 +#define CLK_AP_I2C4 18 +#define CLK_AP_I2C5 19 +#define CLK_AP_I2C6 20 +#define CLK_AP_SPI0 21 +#define CLK_AP_SPI1 22 +#define CLK_AP_SPI2 23 +#define CLK_AP_SPI3 24 +#define CLK_AP_IIS0 25 +#define CLK_AP_IIS1 26 +#define CLK_AP_IIS2 27 +#define CLK_SIM0 28 +#define CLK_SIM0_32K 29 +#define CLK_AP_CLK_NUM (CLK_SIM0_32K + 1) + +#define CLK_13M 0 +#define CLK_6M5 1 +#define CLK_4M3 2 +#define CLK_2M 3 +#define CLK_250K 4 +#define CLK_RCO_25M 5 +#define CLK_RCO_4M 6 +#define CLK_RCO_2M 7 +#define CLK_EMC 8 +#define CLK_AON_APB 9 +#define CLK_ADI 10 +#define CLK_AUX0 11 +#define CLK_AUX1 12 +#define CLK_AUX2 13 +#define CLK_PROBE 14 +#define CLK_PWM0 15 +#define CLK_PWM1 16 +#define CLK_PWM2 17 +#define CLK_AON_THM 18 +#define CLK_AUDIF 19 +#define CLK_CPU_DAP 20 +#define CLK_CPU_TS 21 +#define CLK_DJTAG_TCK 22 +#define CLK_EMC_REF 23 +#define CLK_CSSYS 24 +#define CLK_AON_PMU 25 +#define CLK_PMU_26M 26 +#define CLK_AON_TMR 27 +#define CLK_POWER_CPU 28 +#define CLK_AP_AXI 29 +#define CLK_SDIO0_2X 30 +#define CLK_SDIO1_2X 31 +#define CLK_SDIO2_2X 32 +#define CLK_EMMC_2X 33 +#define CLK_DPU 34 +#define CLK_DPU_DPI 35 +#define CLK_OTG_REF 36 +#define CLK_SDPHY_APB 37 +#define CLK_ALG_IO_APB 38 +#define CLK_GPU_CORE 39 +#define CLK_GPU_SOC 40 +#define CLK_MM_EMC 41 +#define CLK_MM_AHB 42 +#define CLK_BPC 43 +#define CLK_DCAM_IF 44 +#define CLK_ISP 45 +#define CLK_JPG 46 +#define CLK_CPP 47 +#define CLK_SENSOR0 48 +#define CLK_SENSOR1 49 +#define CLK_SENSOR2 50 +#define CLK_MM_VEMC 51 +#define CLK_MM_VAHB 52 +#define CLK_VSP 53 +#define CLK_CORE0 54 +#define CLK_CORE1 55 +#define CLK_CORE2 56 +#define CLK_CORE3 57 +#define CLK_CORE4 58 +#define CLK_CORE5 59 +#define CLK_CORE6 60 +#define CLK_CORE7 61 +#define CLK_SCU 62 +#define CLK_ACE 63 +#define CLK_AXI_PERIPH 64 +#define CLK_AXI_ACP 65 +#define CLK_ATB 66 +#define CLK_DEBUG_APB 67 +#define CLK_GIC 68 +#define CLK_PERIPH 69 +#define CLK_AON_CLK_NUM (CLK_VSP + 1) + +#define CLK_OTG_EB 0 +#define CLK_DMA_EB 1 +#define CLK_CE_EB 2 +#define CLK_NANDC_EB 3 +#define CLK_SDIO0_EB 4 +#define CLK_SDIO1_EB 5 +#define CLK_SDIO2_EB 6 +#define CLK_EMMC_EB 7 +#define CLK_EMMC_32K_EB 8 +#define CLK_SDIO0_32K_EB 9 +#define CLK_SDIO1_32K_EB 10 +#define CLK_SDIO2_32K_EB 11 +#define CLK_NANDC_26M_EB 12 +#define CLK_DMA_EB2 13 +#define CLK_CE_EB2 14 +#define CLK_AP_AHB_GATE_NUM (CLK_CE_EB2 + 1) + +#define CLK_GPIO_EB 0 +#define CLK_PWM0_EB 1 +#define CLK_PWM1_EB 2 +#define CLK_PWM2_EB 3 +#define CLK_PWM3_EB 4 +#define CLK_KPD_EB 5 +#define CLK_AON_SYST_EB 6 +#define CLK_AP_SYST_EB 7 +#define CLK_AON_TMR_EB 8 +#define CLK_EFUSE_EB 9 +#define CLK_EIC_EB 10 +#define CLK_INTC_EB 11 +#define CLK_ADI_EB 12 +#define CLK_AUDIF_EB 13 +#define CLK_AUD_EB 14 +#define CLK_VBC_EB 15 +#define CLK_PIN_EB 16 +#define CLK_AP_WDG_EB 17 +#define CLK_MM_EB 18 +#define CLK_AON_APB_CKG_EB 19 +#define CLK_CA53_TS0_EB 20 +#define CLK_CA53_TS1_EB 21 +#define CLK_CS53_DAP_EB 22 +#define CLK_PMU_EB 23 +#define CLK_THM_EB 24 +#define CLK_AUX0_EB 25 +#define CLK_AUX1_EB 26 +#define CLK_AUX2_EB 27 +#define CLK_PROBE_EB 28 +#define CLK_EMC_REF_EB 29 +#define CLK_CA53_WDG_EB 30 +#define CLK_AP_TMR1_EB 31 +#define CLK_AP_TMR2_EB 32 +#define CLK_DISP_EMC_EB 33 +#define CLK_ZIP_EMC_EB 34 +#define CLK_GSP_EMC_EB 35 +#define CLK_MM_VSP_EB 36 +#define CLK_MDAR_EB 37 +#define CLK_RTC4M0_CAL_EB 38 +#define CLK_RTC4M1_CAL_EB 39 +#define CLK_DJTAG_EB 40 +#define CLK_MBOX_EB 41 +#define CLK_AON_DMA_EB 42 +#define CLK_AON_APB_DEF_EB 43 +#define CLK_CA5_TS0_EB 44 +#define CLK_DBG_EB 45 +#define CLK_DBG_EMC_EB 46 +#define CLK_CROSS_TRIG_EB 47 +#define CLK_SERDES_DPHY_EB 48 +#define CLK_ARCH_RTC_EB 49 +#define CLK_KPD_RTC_EB 50 +#define CLK_AON_SYST_RTC_EB 51 +#define CLK_AP_SYST_RTC_EB 52 +#define CLK_AON_TMR_RTC_EB 53 +#define CLK_AP_TMR0_RTC_EB 54 +#define CLK_EIC_RTC_EB 55 +#define CLK_EIC_RTCDV5_EB 56 +#define CLK_AP_WDG_RTC_EB 57 +#define CLK_CA53_WDG_RTC_EB 58 +#define CLK_THM_RTC_EB 59 +#define CLK_ATHMA_RTC_EB 60 +#define CLK_GTHMA_RTC_EB 61 +#define CLK_ATHMA_RTC_A_EB 62 +#define CLK_GTHMA_RTC_A_EB 63 +#define CLK_AP_TMR1_RTC_EB 64 +#define CLK_AP_TMR2_RTC_EB 65 +#define CLK_DXCO_LC_RTC_EB 66 +#define CLK_BB_CAL_RTC_EB 67 +#define CLK_GNU_EB 68 +#define CLK_DISP_EB 69 +#define CLK_MM_EMC_EB 70 +#define CLK_POWER_CPU_EB 71 +#define CLK_HW_I2C_EB 72 +#define CLK_MM_VSP_EMC_EB 73 +#define CLK_VSP_EB 74 +#define CLK_CSSYS_EB 75 +#define CLK_DMC_EB 76 +#define CLK_ROSC_EB 77 +#define CLK_S_D_CFG_EB 78 +#define CLK_S_D_REF_EB 79 +#define CLK_B_DMA_EB 80 +#define CLK_ANLG_EB 81 +#define CLK_ANLG_APB_EB 82 +#define CLK_BSMTMR_EB 83 +#define CLK_AP_AXI_EB 84 +#define CLK_AP_INTC0_EB 85 +#define CLK_AP_INTC1_EB 86 +#define CLK_AP_INTC2_EB 87 +#define CLK_AP_INTC3_EB 88 +#define CLK_AP_INTC4_EB 89 +#define CLK_AP_INTC5_EB 90 +#define CLK_SCC_EB 91 +#define CLK_DPHY_CFG_EB 92 +#define CLK_DPHY_REF_EB 93 +#define CLK_CPHY_CFG_EB 94 +#define CLK_OTG_REF_EB 95 +#define CLK_SERDES_EB 96 +#define CLK_AON_AP_EMC_EB 97 +#define CLK_AON_APB_GATE_NUM (CLK_AON_AP_EMC_EB + 1) + +#define CLK_MAHB_CKG_EB 0 +#define CLK_MDCAM_EB 1 +#define CLK_MISP_EB 2 +#define CLK_MAHBCSI_EB 3 +#define CLK_MCSI_S_EB 4 +#define CLK_MCSI_T_EB 5 +#define CLK_DCAM_AXI_EB 6 +#define CLK_ISP_AXI_EB 7 +#define CLK_MCSI_EB 8 +#define CLK_MCSI_S_CKG_EB 9 +#define CLK_MCSI_T_CKG_EB 10 +#define CLK_SENSOR0_EB 11 +#define CLK_SENSOR1_EB 12 +#define CLK_SENSOR2_EB 13 +#define CLK_MCPHY_CFG_EB 14 +#define CLK_MM_GATE_NUM (CLK_MCPHY_CFG_EB + 1) + +#define CLK_SIM0_EB 0 +#define CLK_IIS0_EB 1 +#define CLK_IIS1_EB 2 +#define CLK_IIS2_EB 3 +#define CLK_SPI0_EB 4 +#define CLK_SPI1_EB 5 +#define CLK_SPI2_EB 6 +#define CLK_I2C0_EB 7 +#define CLK_I2C1_EB 8 +#define CLK_I2C2_EB 9 +#define CLK_I2C3_EB 10 +#define CLK_I2C4_EB 11 +#define CLK_UART0_EB 12 +#define CLK_UART1_EB 13 +#define CLK_UART2_EB 14 +#define CLK_UART3_EB 15 +#define CLK_UART4_EB 16 +#define CLK_SIM0_32K_EB 17 +#define CLK_SPI3_EB 18 +#define CLK_I2C5_EB 19 +#define CLK_I2C6_EB 20 +#define CLK_AP_APB_GATE_NUM (CLK_I2C6_EB + 1) + +#endif /* _DT_BINDINGS_CLK_SC9863A_H_ */ From ea8ca3109dd4dc14c4a8813b8c4a6d8d011836c4 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:28 +0800 Subject: [PATCH 555/809] clk: sprd: Add macros for referencing parents without strings With the new clk parenting code, clk_init_data was expanded to include .parent_hws and .parent_data, for clk drivers to specify parents without name strings of clocks. Also some macros were added for using these two items to reference clock parents. Based on that to expand macros for sprd clocks: - SPRD_*_DATA, take an array of struct clk_parent_data * as its parents which should be a combination of .fw_name (devicetree clock-names), .hw (pointers to a local struct clk_hw). - SPRD_*_HW, take a local struct clk_hw pointer, instead of a string, as its parent. - SPRD_*_FW_NAME, take a string of clock-names decleared in the device tree as the clock parent. Signed-off-by: Chunyan Zhang Link: https://lkml.kernel.org/r/20200304072730.9193-6-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/sprd/composite.h | 39 +++++++++---- drivers/clk/sprd/div.h | 20 +++++-- drivers/clk/sprd/gate.h | 109 ++++++++++++++++++++++++++++++----- drivers/clk/sprd/mux.h | 28 ++++++--- drivers/clk/sprd/pll.h | 55 ++++++++++++------ 5 files changed, 196 insertions(+), 55 deletions(-) diff --git a/drivers/clk/sprd/composite.h b/drivers/clk/sprd/composite.h index 04ab3f587ee2..adbabbe596b7 100644 --- a/drivers/clk/sprd/composite.h +++ b/drivers/clk/sprd/composite.h @@ -18,26 +18,43 @@ struct sprd_comp { struct sprd_clk_common common; }; -#define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \ - _mshift, _mwidth, _dshift, _dwidth, _flags) \ +#define SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, _dwidth, \ + _flags, _fn) \ struct sprd_comp _struct = { \ .mux = _SPRD_MUX_CLK(_mshift, _mwidth, _table), \ .div = _SPRD_DIV_CLK(_dshift, _dwidth), \ .common = { \ .regmap = NULL, \ .reg = _reg, \ - .hw.init = CLK_HW_INIT_PARENTS(_name, \ - _parent, \ - &sprd_comp_ops, \ - _flags), \ + .hw.init = _fn(_name, _parent, \ + &sprd_comp_ops, _flags), \ } \ } -#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \ - _mwidth, _dshift, _dwidth, _flags) \ - SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, \ - NULL, _mshift, _mwidth, \ - _dshift, _dwidth, _flags) +#define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, _dwidth, _flags) \ + SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, _dwidth, \ + _flags, CLK_HW_INIT_PARENTS) + +#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \ + _mwidth, _dshift, _dwidth, _flags) \ + SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, NULL, \ + _mshift, _mwidth, _dshift, _dwidth, _flags) + +#define SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, \ + _dwidth, _flags) \ + SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, _dwidth, \ + _flags, CLK_HW_INIT_PARENTS_DATA) + +#define SPRD_COMP_CLK_DATA(_struct, _name, _parent, _reg, _mshift, \ + _mwidth, _dshift, _dwidth, _flags) \ + SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, NULL, \ + _mshift, _mwidth, _dshift, _dwidth, \ + _flags) static inline struct sprd_comp *hw_to_sprd_comp(const struct clk_hw *hw) { diff --git a/drivers/clk/sprd/div.h b/drivers/clk/sprd/div.h index 87510e3d0e14..6acfe6b179fc 100644 --- a/drivers/clk/sprd/div.h +++ b/drivers/clk/sprd/div.h @@ -35,20 +35,28 @@ struct sprd_div { struct sprd_clk_common common; }; -#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ - _shift, _width, _flags) \ +#define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _shift, _width, _flags, _fn) \ struct sprd_div _struct = { \ .div = _SPRD_DIV_CLK(_shift, _width), \ .common = { \ .regmap = NULL, \ .reg = _reg, \ - .hw.init = CLK_HW_INIT(_name, \ - _parent, \ - &sprd_div_ops, \ - _flags), \ + .hw.init = _fn(_name, _parent, \ + &sprd_div_ops, _flags), \ } \ } +#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ + _shift, _width, _flags) \ + SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _shift, _width, _flags, CLK_HW_INIT) + +#define SPRD_DIV_CLK_HW(_struct, _name, _parent, _reg, \ + _shift, _width, _flags) \ + SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _shift, _width, _flags, CLK_HW_INIT_HW) + static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); diff --git a/drivers/clk/sprd/gate.h b/drivers/clk/sprd/gate.h index d380d77b8dce..b55817869367 100644 --- a/drivers/clk/sprd/gate.h +++ b/drivers/clk/sprd/gate.h @@ -19,9 +19,9 @@ struct sprd_gate { struct sprd_clk_common common; }; -#define SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ +#define SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ _sc_offset, _enable_mask, _flags, \ - _gate_flags, _udelay, _ops) \ + _gate_flags, _udelay, _ops, _fn) \ struct sprd_gate _struct = { \ .enable_mask = _enable_mask, \ .sc_offset = _sc_offset, \ @@ -30,38 +30,121 @@ struct sprd_gate { .common = { \ .regmap = NULL, \ .reg = _reg, \ - .hw.init = CLK_HW_INIT(_name, \ - _parent, \ - _ops, \ - _flags), \ + .hw.init = _fn(_name, _parent, \ + _ops, _flags), \ } \ } +#define SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, _ops) \ + SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, _ops, CLK_HW_INIT) + #define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ _enable_mask, _flags, _gate_flags, _ops) \ SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ _sc_offset, _enable_mask, _flags, \ _gate_flags, 0, _ops) -#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \ - _enable_mask, _flags, _gate_flags) \ - SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \ - _enable_mask, _flags, _gate_flags, \ - &sprd_gate_ops) - #define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \ _enable_mask, _flags, _gate_flags) \ SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ _enable_mask, _flags, _gate_flags, \ &sprd_sc_gate_ops) +#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \ + _enable_mask, _flags, _gate_flags) \ + SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \ + _enable_mask, _flags, _gate_flags, \ + &sprd_gate_ops) + #define SPRD_PLL_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \ - _enable_mask, _flags, _gate_flags, _udelay) \ + _enable_mask, _flags, _gate_flags, \ + _udelay) \ SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \ _sc_offset, _enable_mask, _flags, \ _gate_flags, _udelay, \ &sprd_pll_sc_gate_ops) + +#define SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, \ + _flags, _gate_flags, \ + _udelay, _ops) \ + SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, _ops, \ + CLK_HW_INIT_HW) + +#define SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _ops) \ + SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, \ + _flags, _gate_flags, 0, _ops) + +#define SPRD_SC_GATE_CLK_HW(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags) \ + SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, &sprd_sc_gate_ops) + +#define SPRD_GATE_CLK_HW(_struct, _name, _parent, _reg, \ + _enable_mask, _flags, _gate_flags) \ + SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, 0, \ + _enable_mask, _flags, _gate_flags, \ + &sprd_gate_ops) + +#define SPRD_PLL_SC_GATE_CLK_HW(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay) \ + SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, \ + _flags, _gate_flags, _udelay, \ + &sprd_pll_sc_gate_ops) + +#define SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \ + _reg, _sc_offset, \ + _enable_mask, _flags, \ + _gate_flags, _udelay, _ops) \ + SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay, _ops, \ + CLK_HW_INIT_FW_NAME) + +#define SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _ops) \ + SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \ + _reg, _sc_offset, \ + _enable_mask, _flags, \ + _gate_flags, 0, _ops) + +#define SPRD_SC_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags) \ + SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, &sprd_sc_gate_ops) + +#define SPRD_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \ + _enable_mask, _flags, _gate_flags) \ + SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, 0, \ + _enable_mask, _flags, _gate_flags, \ + &sprd_gate_ops) + +#define SPRD_PLL_SC_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \ + _sc_offset, _enable_mask, _flags, \ + _gate_flags, _udelay) \ + SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \ + _reg, _sc_offset, \ + _enable_mask, _flags, \ + _gate_flags, _udelay, \ + &sprd_pll_sc_gate_ops) + static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); diff --git a/drivers/clk/sprd/mux.h b/drivers/clk/sprd/mux.h index 892e4191cc7f..f3cc31dae06f 100644 --- a/drivers/clk/sprd/mux.h +++ b/drivers/clk/sprd/mux.h @@ -36,26 +36,40 @@ struct sprd_mux { .table = _table, \ } -#define SPRD_MUX_CLK_TABLE(_struct, _name, _parents, _table, \ - _reg, _shift, _width, \ - _flags) \ +#define SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _flags, _fn) \ struct sprd_mux _struct = { \ .mux = _SPRD_MUX_CLK(_shift, _width, _table), \ .common = { \ .regmap = NULL, \ .reg = _reg, \ - .hw.init = CLK_HW_INIT_PARENTS(_name, \ - _parents, \ - &sprd_mux_ops, \ - _flags), \ + .hw.init = _fn(_name, _parents, \ + &sprd_mux_ops, _flags), \ } \ } +#define SPRD_MUX_CLK_TABLE(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _flags) \ + SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _flags, \ + CLK_HW_INIT_PARENTS) + #define SPRD_MUX_CLK(_struct, _name, _parents, _reg, \ _shift, _width, _flags) \ SPRD_MUX_CLK_TABLE(_struct, _name, _parents, NULL, \ _reg, _shift, _width, _flags) +#define SPRD_MUX_CLK_DATA_TABLE(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _flags) \ + SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _flags, \ + CLK_HW_INIT_PARENTS_DATA) + +#define SPRD_MUX_CLK_DATA(_struct, _name, _parents, _reg, \ + _shift, _width, _flags) \ + SPRD_MUX_CLK_DATA_TABLE(_struct, _name, _parents, NULL, \ + _reg, _shift, _width, _flags) + static inline struct sprd_mux *hw_to_sprd_mux(const struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); diff --git a/drivers/clk/sprd/pll.h b/drivers/clk/sprd/pll.h index e95f11e91ffe..6558f50d0296 100644 --- a/drivers/clk/sprd/pll.h +++ b/drivers/clk/sprd/pll.h @@ -61,27 +61,33 @@ struct sprd_pll { struct sprd_clk_common common; }; +#define SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, \ + _udelay, _k1, _k2, _fflag, \ + _fvco, _fn) \ + struct sprd_pll _struct = { \ + .regs_num = _regs_num, \ + .itable = _itable, \ + .factors = _factors, \ + .udelay = _udelay, \ + .k1 = _k1, \ + .k2 = _k2, \ + .fflag = _fflag, \ + .fvco = _fvco, \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = _fn(_name, _parent, \ + &sprd_pll_ops, 0),\ + }, \ + } + #define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \ _regs_num, _itable, _factors, \ _udelay, _k1, _k2, _fflag, _fvco) \ - struct sprd_pll _struct = { \ - .regs_num = _regs_num, \ - .itable = _itable, \ - .factors = _factors, \ - .udelay = _udelay, \ - .k1 = _k1, \ - .k2 = _k2, \ - .fflag = _fflag, \ - .fvco = _fvco, \ - .common = { \ - .regmap = NULL, \ - .reg = _reg, \ - .hw.init = CLK_HW_INIT(_name, \ - _parent, \ - &sprd_pll_ops, \ - 0), \ - }, \ - } + SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \ + _itable, _factors, _udelay, _k1, _k2, \ + _fflag, _fvco, CLK_HW_INIT) #define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg, \ _regs_num, _itable, _factors, \ @@ -96,6 +102,19 @@ struct sprd_pll { _regs_num, _itable, _factors, \ _udelay, 1000, 1000, 0, 0) +#define SPRD_PLL_FW_NAME(_struct, _name, _parent, _reg, _regs_num, \ + _itable, _factors, _udelay, _k1, _k2, \ + _fflag, _fvco) \ + SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \ + _itable, _factors, _udelay, _k1, _k2, \ + _fflag, _fvco, CLK_HW_INIT_FW_NAME) + +#define SPRD_PLL_HW(_struct, _name, _parent, _reg, _regs_num, _itable, \ + _factors, _udelay, _k1, _k2, _fflag, _fvco) \ + SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \ + _itable, _factors, _udelay, _k1, _k2, \ + _fflag, _fvco, CLK_HW_INIT_HW) + static inline struct sprd_pll *hw_to_sprd_pll(struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); From f95e8c7923d1b65b892f7052f66f8588b08f65b3 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:29 +0800 Subject: [PATCH 556/809] clk: sprd: support to get regmap from parent node Some SC9863a clock nodes would be the child of a syscon node, clocks can use the regmap of syscon device directly for this kind of cases. Signed-off-by: Chunyan Zhang Link: https://lkml.kernel.org/r/20200304072730.9193-7-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/sprd/common.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c index c0af4779892b..d620bbbcdfc8 100644 --- a/drivers/clk/sprd/common.c +++ b/drivers/clk/sprd/common.c @@ -40,7 +40,8 @@ int sprd_clk_regmap_init(struct platform_device *pdev, const struct sprd_clk_desc *desc) { void __iomem *base; - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; struct regmap *regmap; if (of_find_property(node, "sprd,syscon", NULL)) { @@ -49,6 +50,13 @@ int sprd_clk_regmap_init(struct platform_device *pdev, pr_err("%s: failed to get syscon regmap\n", __func__); return PTR_ERR(regmap); } + } else if (of_device_is_compatible(of_get_parent(dev->of_node), + "syscon")) { + regmap = device_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to get regmap from its parent.\n"); + return PTR_ERR(regmap); + } } else { base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) From 0e4b8a2349f3aa9b54c217b338ee65d8b2b6b739 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 4 Mar 2020 15:27:30 +0800 Subject: [PATCH 557/809] clk: sprd: add clocks support for SC9863A Add the list of clocks for the Unisoc SC9863A, along with clock initialization. Signed-off-by: Chunyan Zhang Link: https://lkml.kernel.org/r/20200304072730.9193-8-zhang.lyra@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/sprd/Kconfig | 8 + drivers/clk/sprd/Makefile | 1 + drivers/clk/sprd/sc9863a-clk.c | 1772 ++++++++++++++++++++++++++++++++ 3 files changed, 1781 insertions(+) create mode 100644 drivers/clk/sprd/sc9863a-clk.c diff --git a/drivers/clk/sprd/Kconfig b/drivers/clk/sprd/Kconfig index 3c219af25100..e18c80fbe804 100644 --- a/drivers/clk/sprd/Kconfig +++ b/drivers/clk/sprd/Kconfig @@ -13,4 +13,12 @@ config SPRD_SC9860_CLK tristate "Support for the Spreadtrum SC9860 clocks" depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST default ARM64 && ARCH_SPRD + +config SPRD_SC9863A_CLK + tristate "Support for the Spreadtrum SC9863A clocks" + depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST + default ARM64 && ARCH_SPRD + help + Support for the global clock controller on sc9863a devices. + Say Y if you want to use peripheral devices on sc9863a SoC. endif diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile index d4c00788d53c..41d90e0d7863 100644 --- a/drivers/clk/sprd/Makefile +++ b/drivers/clk/sprd/Makefile @@ -10,3 +10,4 @@ clk-sprd-y += pll.o ## SoC support obj-$(CONFIG_SPRD_SC9860_CLK) += sc9860-clk.o +obj-$(CONFIG_SPRD_SC9863A_CLK) += sc9863a-clk.o diff --git a/drivers/clk/sprd/sc9863a-clk.c b/drivers/clk/sprd/sc9863a-clk.c new file mode 100644 index 000000000000..a0631f7756cf --- /dev/null +++ b/drivers/clk/sprd/sc9863a-clk.c @@ -0,0 +1,1772 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Unisoc SC9863A clock driver + * + * Copyright (C) 2019 Unisoc, Inc. + * Author: Chunyan Zhang + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "composite.h" +#include "div.h" +#include "gate.h" +#include "mux.h" +#include "pll.h" + +/* mpll*_gate clocks control cpu cores, they were enabled by default */ +SPRD_PLL_SC_GATE_CLK_FW_NAME(mpll0_gate, "mpll0-gate", "ext-26m", 0x94, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(dpll0_gate, "dpll0-gate", "ext-26m", 0x98, + 0x1000, BIT(0), 0, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(lpll_gate, "lpll-gate", "ext-26m", 0x9c, + 0x1000, BIT(0), 0, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(gpll_gate, "gpll-gate", "ext-26m", 0xa8, + 0x1000, BIT(0), 0, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(dpll1_gate, "dpll1-gate", "ext-26m", 0x1dc, + 0x1000, BIT(0), 0, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(mpll1_gate, "mpll1-gate", "ext-26m", 0x1e0, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(mpll2_gate, "mpll2-gate", "ext-26m", 0x1e4, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0, 240); +SPRD_PLL_SC_GATE_CLK_FW_NAME(isppll_gate, "isppll-gate", "ext-26m", 0x1e8, + 0x1000, BIT(0), 0, 0, 240); + +static struct sprd_clk_common *sc9863a_pmu_gate_clks[] = { + /* address base is 0x402b0000 */ + &mpll0_gate.common, + &dpll0_gate.common, + &lpll_gate.common, + &gpll_gate.common, + &dpll1_gate.common, + &mpll1_gate.common, + &mpll2_gate.common, + &isppll_gate.common, +}; + +static struct clk_hw_onecell_data sc9863a_pmu_gate_hws = { + .hws = { + [CLK_MPLL0_GATE] = &mpll0_gate.common.hw, + [CLK_DPLL0_GATE] = &dpll0_gate.common.hw, + [CLK_LPLL_GATE] = &lpll_gate.common.hw, + [CLK_GPLL_GATE] = &gpll_gate.common.hw, + [CLK_DPLL1_GATE] = &dpll1_gate.common.hw, + [CLK_MPLL1_GATE] = &mpll1_gate.common.hw, + [CLK_MPLL2_GATE] = &mpll2_gate.common.hw, + [CLK_ISPPLL_GATE] = &isppll_gate.common.hw, + }, + .num = CLK_PMU_APB_NUM, +}; + +static const struct sprd_clk_desc sc9863a_pmu_gate_desc = { + .clk_clks = sc9863a_pmu_gate_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_pmu_gate_clks), + .hw_clks = &sc9863a_pmu_gate_hws, +}; + +static const u64 itable[5] = {4, 1000000000, 1200000000, + 1400000000, 1600000000}; + +static const struct clk_bit_field f_twpll[PLL_FACT_MAX] = { + { .shift = 95, .width = 1 }, /* lock_done */ + { .shift = 0, .width = 1 }, /* div_s */ + { .shift = 1, .width = 1 }, /* mod_en */ + { .shift = 2, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 3, .width = 3 }, /* ibias */ + { .shift = 8, .width = 11 }, /* n */ + { .shift = 55, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_FW_NAME(twpll, "twpll", "ext-26m", 0x4, 3, itable, + f_twpll, 240, 1000, 1000, 0, 0); +static CLK_FIXED_FACTOR_HW(twpll_768m, "twpll-768m", &twpll.common.hw, 2, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_384m, "twpll-384m", &twpll.common.hw, 4, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_192m, "twpll-192m", &twpll.common.hw, 8, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_96m, "twpll-96m", &twpll.common.hw, 16, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_48m, "twpll-48m", &twpll.common.hw, 32, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_24m, "twpll-24m", &twpll.common.hw, 64, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_12m, "twpll-12m", &twpll.common.hw, 128, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_512m, "twpll-512m", &twpll.common.hw, 3, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_256m, "twpll-256m", &twpll.common.hw, 6, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_128m, "twpll-128m", &twpll.common.hw, 12, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_64m, "twpll-64m", &twpll.common.hw, 24, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_307m2, "twpll-307m2", &twpll.common.hw, 5, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_219m4, "twpll-219m4", &twpll.common.hw, 7, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_170m6, "twpll-170m6", &twpll.common.hw, 9, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_153m6, "twpll-153m6", &twpll.common.hw, 10, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_76m8, "twpll-76m8", &twpll.common.hw, 20, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_51m2, "twpll-51m2", &twpll.common.hw, 30, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_38m4, "twpll-38m4", &twpll.common.hw, 40, 1, 0); +static CLK_FIXED_FACTOR_HW(twpll_19m2, "twpll-19m2", &twpll.common.hw, 80, 1, 0); + +static const struct clk_bit_field f_lpll[PLL_FACT_MAX] = { + { .shift = 95, .width = 1 }, /* lock_done */ + { .shift = 0, .width = 1 }, /* div_s */ + { .shift = 1, .width = 1 }, /* mod_en */ + { .shift = 2, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 6, .width = 2 }, /* ibias */ + { .shift = 8, .width = 11 }, /* n */ + { .shift = 55, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_HW(lpll, "lpll", &lpll_gate.common.hw, 0x20, 3, itable, + f_lpll, 240, 1000, 1000, 0, 0); +static CLK_FIXED_FACTOR_HW(lpll_409m6, "lpll-409m6", &lpll.common.hw, 3, 1, 0); +static CLK_FIXED_FACTOR_HW(lpll_245m76, "lpll-245m76", &lpll.common.hw, 5, 1, 0); + +static const struct clk_bit_field f_gpll[PLL_FACT_MAX] = { + { .shift = 95, .width = 1 }, /* lock_done */ + { .shift = 0, .width = 1 }, /* div_s */ + { .shift = 1, .width = 1 }, /* mod_en */ + { .shift = 2, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 6, .width = 2 }, /* ibias */ + { .shift = 8, .width = 11 }, /* n */ + { .shift = 55, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 80, .width = 1 }, /* postdiv */ +}; +static SPRD_PLL_HW(gpll, "gpll", &gpll_gate.common.hw, 0x38, 3, itable, + f_gpll, 240, 1000, 1000, 1, 400000000); + +static SPRD_PLL_HW(isppll, "isppll", &isppll_gate.common.hw, 0x50, 3, itable, + f_gpll, 240, 1000, 1000, 0, 0); +static CLK_FIXED_FACTOR_HW(isppll_468m, "isppll-468m", &isppll.common.hw, 2, 1, 0); + +static struct sprd_clk_common *sc9863a_pll_clks[] = { + /* address base is 0x40353000 */ + &twpll.common, + &lpll.common, + &gpll.common, + &isppll.common, +}; + +static struct clk_hw_onecell_data sc9863a_pll_hws = { + .hws = { + [CLK_TWPLL] = &twpll.common.hw, + [CLK_TWPLL_768M] = &twpll_768m.hw, + [CLK_TWPLL_384M] = &twpll_384m.hw, + [CLK_TWPLL_192M] = &twpll_192m.hw, + [CLK_TWPLL_96M] = &twpll_96m.hw, + [CLK_TWPLL_48M] = &twpll_48m.hw, + [CLK_TWPLL_24M] = &twpll_24m.hw, + [CLK_TWPLL_12M] = &twpll_12m.hw, + [CLK_TWPLL_512M] = &twpll_512m.hw, + [CLK_TWPLL_256M] = &twpll_256m.hw, + [CLK_TWPLL_128M] = &twpll_128m.hw, + [CLK_TWPLL_64M] = &twpll_64m.hw, + [CLK_TWPLL_307M2] = &twpll_307m2.hw, + [CLK_TWPLL_219M4] = &twpll_219m4.hw, + [CLK_TWPLL_170M6] = &twpll_170m6.hw, + [CLK_TWPLL_153M6] = &twpll_153m6.hw, + [CLK_TWPLL_76M8] = &twpll_76m8.hw, + [CLK_TWPLL_51M2] = &twpll_51m2.hw, + [CLK_TWPLL_38M4] = &twpll_38m4.hw, + [CLK_TWPLL_19M2] = &twpll_19m2.hw, + [CLK_LPLL] = &lpll.common.hw, + [CLK_LPLL_409M6] = &lpll_409m6.hw, + [CLK_LPLL_245M76] = &lpll_245m76.hw, + [CLK_GPLL] = &gpll.common.hw, + [CLK_ISPPLL] = &isppll.common.hw, + [CLK_ISPPLL_468M] = &isppll_468m.hw, + + }, + .num = CLK_ANLG_PHY_G1_NUM, +}; + +static const struct sprd_clk_desc sc9863a_pll_desc = { + .clk_clks = sc9863a_pll_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_pll_clks), + .hw_clks = &sc9863a_pll_hws, +}; + +static const u64 itable_mpll[6] = {5, 1000000000, 1200000000, 1400000000, + 1600000000, 1800000000}; +static SPRD_PLL_HW(mpll0, "mpll0", &mpll0_gate.common.hw, 0x0, 3, itable_mpll, + f_gpll, 240, 1000, 1000, 1, 1000000000); +static SPRD_PLL_HW(mpll1, "mpll1", &mpll1_gate.common.hw, 0x18, 3, itable_mpll, + f_gpll, 240, 1000, 1000, 1, 1000000000); +static SPRD_PLL_HW(mpll2, "mpll2", &mpll2_gate.common.hw, 0x30, 3, itable_mpll, + f_gpll, 240, 1000, 1000, 1, 1000000000); +static CLK_FIXED_FACTOR_HW(mpll2_675m, "mpll2-675m", &mpll2.common.hw, 2, 1, 0); + +static struct sprd_clk_common *sc9863a_mpll_clks[] = { + /* address base is 0x40359000 */ + &mpll0.common, + &mpll1.common, + &mpll2.common, +}; + +static struct clk_hw_onecell_data sc9863a_mpll_hws = { + .hws = { + [CLK_MPLL0] = &mpll0.common.hw, + [CLK_MPLL1] = &mpll1.common.hw, + [CLK_MPLL2] = &mpll2.common.hw, + [CLK_MPLL2_675M] = &mpll2_675m.hw, + + }, + .num = CLK_ANLG_PHY_G4_NUM, +}; + +static const struct sprd_clk_desc sc9863a_mpll_desc = { + .clk_clks = sc9863a_mpll_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_mpll_clks), + .hw_clks = &sc9863a_mpll_hws, +}; + +static SPRD_SC_GATE_CLK_FW_NAME(audio_gate, "audio-gate", "ext-26m", + 0x4, 0x1000, BIT(8), 0, 0); + +static SPRD_PLL_FW_NAME(rpll, "rpll", "ext-26m", 0x10, + 3, itable, f_lpll, 240, 1000, 1000, 0, 0); + +static CLK_FIXED_FACTOR_HW(rpll_390m, "rpll-390m", &rpll.common.hw, 2, 1, 0); +static CLK_FIXED_FACTOR_HW(rpll_260m, "rpll-260m", &rpll.common.hw, 3, 1, 0); +static CLK_FIXED_FACTOR_HW(rpll_195m, "rpll-195m", &rpll.common.hw, 4, 1, 0); +static CLK_FIXED_FACTOR_HW(rpll_26m, "rpll-26m", &rpll.common.hw, 30, 1, 0); + +static struct sprd_clk_common *sc9863a_rpll_clks[] = { + /* address base is 0x4035c000 */ + &audio_gate.common, + &rpll.common, +}; + +static struct clk_hw_onecell_data sc9863a_rpll_hws = { + .hws = { + [CLK_AUDIO_GATE] = &audio_gate.common.hw, + [CLK_RPLL] = &rpll.common.hw, + [CLK_RPLL_390M] = &rpll_390m.hw, + [CLK_RPLL_260M] = &rpll_260m.hw, + [CLK_RPLL_195M] = &rpll_195m.hw, + [CLK_RPLL_26M] = &rpll_26m.hw, + }, + .num = CLK_ANLG_PHY_G5_NUM, +}; + +static const struct sprd_clk_desc sc9863a_rpll_desc = { + .clk_clks = sc9863a_rpll_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_rpll_clks), + .hw_clks = &sc9863a_rpll_hws, +}; + +static const u64 itable_dpll[5] = {4, 1211000000, 1320000000, 1570000000, + 1866000000}; +static SPRD_PLL_HW(dpll0, "dpll0", &dpll0_gate.common.hw, 0x0, 3, itable_dpll, + f_lpll, 240, 1000, 1000, 0, 0); +static SPRD_PLL_HW(dpll1, "dpll1", &dpll1_gate.common.hw, 0x18, 3, itable_dpll, + f_lpll, 240, 1000, 1000, 0, 0); + +static CLK_FIXED_FACTOR_HW(dpll0_933m, "dpll0-933m", &dpll0.common.hw, 2, 1, 0); +static CLK_FIXED_FACTOR_HW(dpll0_622m3, "dpll0-622m3", &dpll0.common.hw, 3, 1, 0); +static CLK_FIXED_FACTOR_HW(dpll1_400m, "dpll1-400m", &dpll0.common.hw, 4, 1, 0); +static CLK_FIXED_FACTOR_HW(dpll1_266m7, "dpll1-266m7", &dpll0.common.hw, 6, 1, 0); +static CLK_FIXED_FACTOR_HW(dpll1_123m1, "dpll1-123m1", &dpll0.common.hw, 13, 1, 0); +static CLK_FIXED_FACTOR_HW(dpll1_50m, "dpll1-50m", &dpll0.common.hw, 32, 1, 0); + +static struct sprd_clk_common *sc9863a_dpll_clks[] = { + /* address base is 0x40363000 */ + &dpll0.common, + &dpll1.common, +}; + +static struct clk_hw_onecell_data sc9863a_dpll_hws = { + .hws = { + [CLK_DPLL0] = &dpll0.common.hw, + [CLK_DPLL1] = &dpll1.common.hw, + [CLK_DPLL0_933M] = &dpll0_933m.hw, + [CLK_DPLL0_622M3] = &dpll0_622m3.hw, + [CLK_DPLL0_400M] = &dpll1_400m.hw, + [CLK_DPLL0_266M7] = &dpll1_266m7.hw, + [CLK_DPLL0_123M1] = &dpll1_123m1.hw, + [CLK_DPLL0_50M] = &dpll1_50m.hw, + + }, + .num = CLK_ANLG_PHY_G7_NUM, +}; + +static const struct sprd_clk_desc sc9863a_dpll_desc = { + .clk_clks = sc9863a_dpll_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_dpll_clks), + .hw_clks = &sc9863a_dpll_hws, +}; + +static CLK_FIXED_FACTOR_FW_NAME(clk_6m5, "clk-6m5", "ext-26m", 4, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(clk_4m3, "clk-4m3", "ext-26m", 6, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(clk_2m, "clk-2m", "ext-26m", 13, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(clk_250k, "clk-250k", "ext-26m", 104, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(rco_25m, "rco-25m", "rco-100m", 4, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(rco_4m, "rco-4m", "rco-100m", 25, 1, 0); +static CLK_FIXED_FACTOR_FW_NAME(rco_2m, "rco-2m", "rco-100m", 50, 1, 0); + +#define SC9863A_MUX_FLAG \ + (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_NO_REPARENT) + +static CLK_FIXED_FACTOR_FW_NAME(clk_13m, "clk-13m", "ext-26m", 2, 1, 0); +static const struct clk_parent_data emc_clk_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_384m.hw }, + { .hw = &twpll_512m.hw }, + { .hw = &twpll_768m.hw }, + { .hw = &twpll.common.hw }, +}; +static SPRD_MUX_CLK_DATA(emc_clk, "emc-clk", emc_clk_parents, 0x220, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data aon_apb_parents[] = { + { .hw = &rco_4m.hw }, + { .hw = &rco_25m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_96m.hw }, + { .fw_name = "rco-100m" }, + { .hw = &twpll_128m.hw }, +}; +static SPRD_COMP_CLK_DATA(aon_apb, "aon-apb", aon_apb_parents, 0x224, + 0, 3, 8, 2, 0); + +static const struct clk_parent_data adi_parents[] = { + { .hw = &rco_4m.hw }, + { .hw = &rco_25m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_38m4.hw }, + { .hw = &twpll_51m2.hw }, +}; +static SPRD_MUX_CLK_DATA(adi_clk, "adi-clk", adi_parents, 0x228, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data aux_parents[] = { + { .fw_name = "ext-32k" }, + { .hw = &rpll_26m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_COMP_CLK_DATA(aux0_clk, "aux0-clk", aux_parents, 0x22c, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK_DATA(aux1_clk, "aux1-clk", aux_parents, 0x230, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK_DATA(aux2_clk, "aux2-clk", aux_parents, 0x234, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK_DATA(probe_clk, "probe-clk", aux_parents, 0x238, + 0, 5, 8, 4, 0); + +static const struct clk_parent_data pwm_parents[] = { + { .fw_name = "ext-32k" }, + { .hw = &rpll_26m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, +}; +static SPRD_MUX_CLK_DATA(pwm0_clk, "pwm0-clk", pwm_parents, 0x23c, + 0, 2, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(pwm1_clk, "pwm1-clk", pwm_parents, 0x240, + 0, 2, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(pwm2_clk, "pwm2-clk", pwm_parents, 0x244, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data aon_thm_parents[] = { + { .fw_name = "ext-32k" }, + { .hw = &clk_250k.hw }, +}; +static SPRD_MUX_CLK_DATA(aon_thm_clk, "aon-thm-clk", aon_thm_parents, 0x25c, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data audif_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_38m4.hw }, + { .hw = &twpll_51m2.hw }, +}; +static SPRD_MUX_CLK_DATA(audif_clk, "audif-clk", audif_parents, 0x264, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data cpu_dap_parents[] = { + { .hw = &rco_4m.hw }, + { .hw = &rco_25m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_76m8.hw }, + { .fw_name = "rco-100m" }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, +}; +static SPRD_MUX_CLK_DATA(cpu_dap_clk, "cpu-dap-clk", cpu_dap_parents, 0x26c, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data cpu_ts_parents[] = { + { .fw_name = "ext-32k" }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, +}; +static SPRD_MUX_CLK_DATA(cpu_ts_clk, "cpu-ts-clk", cpu_ts_parents, 0x274, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data djtag_tck_parents[] = { + { .hw = &rco_4m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(djtag_tck_clk, "djtag-tck-clk", djtag_tck_parents, 0x28c, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data emc_ref_parents[] = { + { .hw = &clk_6m5.hw }, + { .hw = &clk_13m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(emc_ref_clk, "emc-ref-clk", emc_ref_parents, 0x29c, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data cssys_parents[] = { + { .hw = &rco_4m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_96m.hw }, + { .fw_name = "rco-100m" }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &twpll_512m.hw }, + { .hw = &mpll2_675m.hw }, +}; +static SPRD_COMP_CLK_DATA(cssys_clk, "cssys-clk", cssys_parents, 0x2a0, + 0, 4, 8, 2, 0); + +static const struct clk_parent_data aon_pmu_parents[] = { + { .fw_name = "ext-32k" }, + { .hw = &rco_4m.hw }, + { .fw_name = "ext-4m" }, +}; +static SPRD_MUX_CLK_DATA(aon_pmu_clk, "aon-pmu-clk", aon_pmu_parents, 0x2a8, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data pmu_26m_parents[] = { + { .hw = &rco_4m.hw }, + { .hw = &rco_25m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(pmu_26m_clk, "26m-pmu-clk", pmu_26m_parents, 0x2ac, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data aon_tmr_parents[] = { + { .hw = &rco_4m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(aon_tmr_clk, "aon-tmr-clk", aon_tmr_parents, 0x2b0, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data power_cpu_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &rco_25m.hw }, + { .fw_name = "rco-100m" }, + { .hw = &twpll_128m.hw }, +}; +static SPRD_MUX_CLK_DATA(power_cpu_clk, "power-cpu-clk", power_cpu_parents, 0x2c4, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data ap_axi_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_76m8.hw }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_256m.hw }, +}; +static SPRD_MUX_CLK_DATA(ap_axi, "ap-axi", ap_axi_parents, 0x2c8, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data sdio_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &rpll_390m.hw }, + { .hw = &dpll1_400m.hw }, + { .hw = &lpll_409m6.hw }, +}; +static SPRD_MUX_CLK_DATA(sdio0_2x, "sdio0-2x", sdio_parents, 0x2cc, + 0, 3, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(sdio1_2x, "sdio1-2x", sdio_parents, 0x2d4, + 0, 3, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(sdio2_2x, "sdio2-2x", sdio_parents, 0x2dc, + 0, 3, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(emmc_2x, "emmc-2x", sdio_parents, 0x2e4, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data dpu_parents[] = { + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_192m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_384m.hw }, +}; +static SPRD_MUX_CLK_DATA(dpu_clk, "dpu", dpu_parents, 0x2f4, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data dpu_dpi_parents[] = { + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_192m.hw }, +}; +static SPRD_COMP_CLK_DATA(dpu_dpi, "dpu-dpi", dpu_dpi_parents, 0x2f8, + 0, 2, 8, 4, 0); + +static const struct clk_parent_data otg_ref_parents[] = { + { .hw = &twpll_12m.hw }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(otg_ref_clk, "otg-ref-clk", otg_ref_parents, 0x308, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data sdphy_apb_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, +}; +static SPRD_MUX_CLK_DATA(sdphy_apb_clk, "sdphy-apb-clk", sdphy_apb_parents, 0x330, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data alg_io_apb_parents[] = { + { .hw = &rco_4m.hw }, + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, + { .hw = &twpll_96m.hw }, +}; +static SPRD_MUX_CLK_DATA(alg_io_apb_clk, "alg-io-apb-clk", alg_io_apb_parents, 0x33c, + 0, 1, SC9863A_MUX_FLAG); + +static const struct clk_parent_data gpu_parents[] = { + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_192m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &twpll_512m.hw }, + { .hw = &gpll.common.hw }, +}; +static SPRD_COMP_CLK_DATA(gpu_core, "gpu-core", gpu_parents, 0x344, + 0, 3, 8, 2, 0); +static SPRD_COMP_CLK_DATA(gpu_soc, "gpu-soc", gpu_parents, 0x348, + 0, 3, 8, 2, 0); + +static const struct clk_parent_data mm_emc_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_384m.hw }, + { .hw = &isppll_468m.hw }, + { .hw = &twpll_512m.hw }, +}; +static SPRD_MUX_CLK_DATA(mm_emc, "mm-emc", mm_emc_parents, 0x350, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data mm_ahb_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_96m.hw }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, +}; +static SPRD_MUX_CLK_DATA(mm_ahb, "mm-ahb", mm_ahb_parents, 0x354, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data bpc_clk_parents[] = { + { .hw = &twpll_192m.hw }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &isppll_468m.hw }, + { .hw = &dpll0_622m3.hw }, +}; +static SPRD_MUX_CLK_DATA(bpc_clk, "bpc-clk", bpc_clk_parents, 0x358, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data dcam_if_parents[] = { + { .hw = &twpll_192m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, +}; +static SPRD_MUX_CLK_DATA(dcam_if_clk, "dcam-if-clk", dcam_if_parents, 0x35c, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data isp_parents[] = { + { .hw = &twpll_128m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &isppll_468m.hw }, +}; +static SPRD_MUX_CLK_DATA(isp_clk, "isp-clk", isp_parents, 0x360, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data jpg_parents[] = { + { .hw = &twpll_76m8.hw }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, +}; +static SPRD_MUX_CLK_DATA(jpg_clk, "jpg-clk", jpg_parents, 0x364, + 0, 2, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(cpp_clk, "cpp-clk", jpg_parents, 0x368, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data sensor_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, + { .hw = &twpll_76m8.hw }, + { .hw = &twpll_96m.hw }, +}; +static SPRD_COMP_CLK_DATA(sensor0_clk, "sensor0-clk", sensor_parents, 0x36c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(sensor1_clk, "sensor1-clk", sensor_parents, 0x370, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(sensor2_clk, "sensor2-clk", sensor_parents, 0x374, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data mm_vemc_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &isppll_468m.hw }, +}; +static SPRD_MUX_CLK_DATA(mm_vemc, "mm-vemc", mm_vemc_parents, 0x378, + 0, 2, SC9863A_MUX_FLAG); + +static SPRD_MUX_CLK_DATA(mm_vahb, "mm-vahb", mm_ahb_parents, 0x37c, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data vsp_parents[] = { + { .hw = &twpll_76m8.hw }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, + { .hw = &twpll_384m.hw }, +}; +static SPRD_MUX_CLK_DATA(clk_vsp, "vsp-clk", vsp_parents, 0x380, + 0, 3, SC9863A_MUX_FLAG); + +static const struct clk_parent_data core_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_512m.hw }, + { .hw = &twpll_768m.hw }, + { .hw = &lpll.common.hw }, + { .hw = &dpll0.common.hw }, + { .hw = &mpll2.common.hw }, + { .hw = &mpll0.common.hw }, + { .hw = &mpll1.common.hw }, +}; +static SPRD_COMP_CLK_DATA(core0_clk, "core0-clk", core_parents, 0xa20, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core1_clk, "core1-clk", core_parents, 0xa24, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core2_clk, "core2-clk", core_parents, 0xa28, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core3_clk, "core3-clk", core_parents, 0xa2c, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core4_clk, "core4-clk", core_parents, 0xa30, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core5_clk, "core5-clk", core_parents, 0xa34, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core6_clk, "core6-clk", core_parents, 0xa38, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(core7_clk, "core7-clk", core_parents, 0xa3c, + 0, 3, 8, 3, 0); +static SPRD_COMP_CLK_DATA(scu_clk, "scu-clk", core_parents, 0xa40, + 0, 3, 8, 3, 0); + +static SPRD_DIV_CLK_HW(ace_clk, "ace-clk", &scu_clk.common.hw, 0xa44, + 8, 3, 0); +static SPRD_DIV_CLK_HW(axi_periph_clk, "axi-periph-clk", &scu_clk.common.hw, 0xa48, + 8, 3, 0); +static SPRD_DIV_CLK_HW(axi_acp_clk, "axi-acp-clk", &scu_clk.common.hw, 0xa4c, + 8, 3, 0); + +static const struct clk_parent_data atb_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_384m.hw }, + { .hw = &twpll_512m.hw }, + { .hw = &mpll2.common.hw }, +}; +static SPRD_COMP_CLK_DATA(atb_clk, "atb-clk", atb_parents, 0xa50, + 0, 2, 8, 3, 0); +static SPRD_DIV_CLK_HW(debug_apb_clk, "debug-apb-clk", &atb_clk.common.hw, 0xa54, + 8, 3, 0); + +static const struct clk_parent_data gic_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_384m.hw }, + { .hw = &twpll_512m.hw }, +}; +static SPRD_COMP_CLK_DATA(gic_clk, "gic-clk", gic_parents, 0xa58, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(periph_clk, "periph-clk", gic_parents, 0xa5c, + 0, 2, 8, 3, 0); + +static struct sprd_clk_common *sc9863a_aon_clks[] = { + /* address base is 0x402d0000 */ + &emc_clk.common, + &aon_apb.common, + &adi_clk.common, + &aux0_clk.common, + &aux1_clk.common, + &aux2_clk.common, + &probe_clk.common, + &pwm0_clk.common, + &pwm1_clk.common, + &pwm2_clk.common, + &aon_thm_clk.common, + &audif_clk.common, + &cpu_dap_clk.common, + &cpu_ts_clk.common, + &djtag_tck_clk.common, + &emc_ref_clk.common, + &cssys_clk.common, + &aon_pmu_clk.common, + &pmu_26m_clk.common, + &aon_tmr_clk.common, + &power_cpu_clk.common, + &ap_axi.common, + &sdio0_2x.common, + &sdio1_2x.common, + &sdio2_2x.common, + &emmc_2x.common, + &dpu_clk.common, + &dpu_dpi.common, + &otg_ref_clk.common, + &sdphy_apb_clk.common, + &alg_io_apb_clk.common, + &gpu_core.common, + &gpu_soc.common, + &mm_emc.common, + &mm_ahb.common, + &bpc_clk.common, + &dcam_if_clk.common, + &isp_clk.common, + &jpg_clk.common, + &cpp_clk.common, + &sensor0_clk.common, + &sensor1_clk.common, + &sensor2_clk.common, + &mm_vemc.common, + &mm_vahb.common, + &clk_vsp.common, + &core0_clk.common, + &core1_clk.common, + &core2_clk.common, + &core3_clk.common, + &core4_clk.common, + &core5_clk.common, + &core6_clk.common, + &core7_clk.common, + &scu_clk.common, + &ace_clk.common, + &axi_periph_clk.common, + &axi_acp_clk.common, + &atb_clk.common, + &debug_apb_clk.common, + &gic_clk.common, + &periph_clk.common, +}; + +static struct clk_hw_onecell_data sc9863a_aon_clk_hws = { + .hws = { + [CLK_13M] = &clk_13m.hw, + [CLK_6M5] = &clk_6m5.hw, + [CLK_4M3] = &clk_4m3.hw, + [CLK_2M] = &clk_2m.hw, + [CLK_250K] = &clk_250k.hw, + [CLK_RCO_25M] = &rco_25m.hw, + [CLK_RCO_4M] = &rco_4m.hw, + [CLK_RCO_2M] = &rco_2m.hw, + [CLK_EMC] = &emc_clk.common.hw, + [CLK_AON_APB] = &aon_apb.common.hw, + [CLK_ADI] = &adi_clk.common.hw, + [CLK_AUX0] = &aux0_clk.common.hw, + [CLK_AUX1] = &aux1_clk.common.hw, + [CLK_AUX2] = &aux2_clk.common.hw, + [CLK_PROBE] = &probe_clk.common.hw, + [CLK_PWM0] = &pwm0_clk.common.hw, + [CLK_PWM1] = &pwm1_clk.common.hw, + [CLK_PWM2] = &pwm2_clk.common.hw, + [CLK_AON_THM] = &aon_thm_clk.common.hw, + [CLK_AUDIF] = &audif_clk.common.hw, + [CLK_CPU_DAP] = &cpu_dap_clk.common.hw, + [CLK_CPU_TS] = &cpu_ts_clk.common.hw, + [CLK_DJTAG_TCK] = &djtag_tck_clk.common.hw, + [CLK_EMC_REF] = &emc_ref_clk.common.hw, + [CLK_CSSYS] = &cssys_clk.common.hw, + [CLK_AON_PMU] = &aon_pmu_clk.common.hw, + [CLK_PMU_26M] = &pmu_26m_clk.common.hw, + [CLK_AON_TMR] = &aon_tmr_clk.common.hw, + [CLK_POWER_CPU] = &power_cpu_clk.common.hw, + [CLK_AP_AXI] = &ap_axi.common.hw, + [CLK_SDIO0_2X] = &sdio0_2x.common.hw, + [CLK_SDIO1_2X] = &sdio1_2x.common.hw, + [CLK_SDIO2_2X] = &sdio2_2x.common.hw, + [CLK_EMMC_2X] = &emmc_2x.common.hw, + [CLK_DPU] = &dpu_clk.common.hw, + [CLK_DPU_DPI] = &dpu_dpi.common.hw, + [CLK_OTG_REF] = &otg_ref_clk.common.hw, + [CLK_SDPHY_APB] = &sdphy_apb_clk.common.hw, + [CLK_ALG_IO_APB] = &alg_io_apb_clk.common.hw, + [CLK_GPU_CORE] = &gpu_core.common.hw, + [CLK_GPU_SOC] = &gpu_soc.common.hw, + [CLK_MM_EMC] = &mm_emc.common.hw, + [CLK_MM_AHB] = &mm_ahb.common.hw, + [CLK_BPC] = &bpc_clk.common.hw, + [CLK_DCAM_IF] = &dcam_if_clk.common.hw, + [CLK_ISP] = &isp_clk.common.hw, + [CLK_JPG] = &jpg_clk.common.hw, + [CLK_CPP] = &cpp_clk.common.hw, + [CLK_SENSOR0] = &sensor0_clk.common.hw, + [CLK_SENSOR1] = &sensor1_clk.common.hw, + [CLK_SENSOR2] = &sensor2_clk.common.hw, + [CLK_MM_VEMC] = &mm_vemc.common.hw, + [CLK_MM_VAHB] = &mm_vahb.common.hw, + [CLK_VSP] = &clk_vsp.common.hw, + [CLK_CORE0] = &core0_clk.common.hw, + [CLK_CORE1] = &core1_clk.common.hw, + [CLK_CORE2] = &core2_clk.common.hw, + [CLK_CORE3] = &core3_clk.common.hw, + [CLK_CORE4] = &core4_clk.common.hw, + [CLK_CORE5] = &core5_clk.common.hw, + [CLK_CORE6] = &core6_clk.common.hw, + [CLK_CORE7] = &core7_clk.common.hw, + [CLK_SCU] = &scu_clk.common.hw, + [CLK_ACE] = &ace_clk.common.hw, + [CLK_AXI_PERIPH] = &axi_periph_clk.common.hw, + [CLK_AXI_ACP] = &axi_acp_clk.common.hw, + [CLK_ATB] = &atb_clk.common.hw, + [CLK_DEBUG_APB] = &debug_apb_clk.common.hw, + [CLK_GIC] = &gic_clk.common.hw, + [CLK_PERIPH] = &periph_clk.common.hw, + }, + .num = CLK_AON_CLK_NUM, +}; + +static const struct sprd_clk_desc sc9863a_aon_clk_desc = { + .clk_clks = sc9863a_aon_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_aon_clks), + .hw_clks = &sc9863a_aon_clk_hws, +}; + +static const struct clk_parent_data ap_apb_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_64m.hw }, + { .hw = &twpll_96m.hw }, + { .hw = &twpll_128m.hw }, +}; +static SPRD_MUX_CLK_DATA(ap_apb, "ap-apb", ap_apb_parents, 0x20, + 0, 2, SC9863A_MUX_FLAG); + +static const struct clk_parent_data ap_ce_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_256m.hw }, +}; +static SPRD_COMP_CLK_DATA(ap_ce, "ap-ce", ap_ce_parents, 0x24, + 0, 1, 8, 3, 0); + +static const struct clk_parent_data nandc_ecc_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_256m.hw }, + { .hw = &twpll_307m2.hw }, +}; +static SPRD_COMP_CLK_DATA(nandc_ecc, "nandc-ecc", nandc_ecc_parents, 0x28, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data nandc_26m_parents[] = { + { .fw_name = "ext-32k" }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(nandc_26m, "nandc-26m", nandc_26m_parents, 0x2c, + 0, 1, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(emmc_32k, "emmc-32k", nandc_26m_parents, 0x30, + 0, 1, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(sdio0_32k, "sdio0-32k", nandc_26m_parents, 0x34, + 0, 1, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(sdio1_32k, "sdio1-32k", nandc_26m_parents, 0x38, + 0, 1, SC9863A_MUX_FLAG); +static SPRD_MUX_CLK_DATA(sdio2_32k, "sdio2-32k", nandc_26m_parents, 0x3c, + 0, 1, SC9863A_MUX_FLAG); + +static SPRD_GATE_CLK_HW(otg_utmi, "otg-utmi", &aon_apb.common.hw, 0x40, + BIT(16), 0, 0); + +static const struct clk_parent_data ap_uart_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, + { .hw = &twpll_51m2.hw }, + { .hw = &twpll_96m.hw }, +}; +static SPRD_COMP_CLK_DATA(ap_uart0, "ap-uart0", ap_uart_parents, 0x44, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_uart1, "ap-uart1", ap_uart_parents, 0x48, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_uart2, "ap-uart2", ap_uart_parents, 0x4c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_uart3, "ap-uart3", ap_uart_parents, 0x50, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_uart4, "ap-uart4", ap_uart_parents, 0x54, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data i2c_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_48m.hw }, + { .hw = &twpll_51m2.hw }, + { .hw = &twpll_153m6.hw }, +}; +static SPRD_COMP_CLK_DATA(ap_i2c0, "ap-i2c0", i2c_parents, 0x58, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c1, "ap-i2c1", i2c_parents, 0x5c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c2, "ap-i2c2", i2c_parents, 0x60, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c3, "ap-i2c3", i2c_parents, 0x64, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c4, "ap-i2c4", i2c_parents, 0x68, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c5, "ap-i2c5", i2c_parents, 0x6c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_i2c6, "ap-i2c6", i2c_parents, 0x70, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data spi_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, + { .hw = &twpll_192m.hw }, +}; +static SPRD_COMP_CLK_DATA(ap_spi0, "ap-spi0", spi_parents, 0x74, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_spi1, "ap-spi1", spi_parents, 0x78, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_spi2, "ap-spi2", spi_parents, 0x7c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_spi3, "ap-spi3", spi_parents, 0x80, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data iis_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_128m.hw }, + { .hw = &twpll_153m6.hw }, +}; +static SPRD_COMP_CLK_DATA(ap_iis0, "ap-iis0", iis_parents, 0x84, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_iis1, "ap-iis1", iis_parents, 0x88, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK_DATA(ap_iis2, "ap-iis2", iis_parents, 0x8c, + 0, 2, 8, 3, 0); + +static const struct clk_parent_data sim0_parents[] = { + { .fw_name = "ext-26m" }, + { .hw = &twpll_51m2.hw }, + { .hw = &twpll_64m.hw }, + { .hw = &twpll_96m.hw }, + { .hw = &twpll_128m.hw }, +}; +static SPRD_COMP_CLK_DATA(sim0, "sim0", sim0_parents, 0x90, + 0, 3, 8, 3, 0); + +static const struct clk_parent_data sim0_32k_parents[] = { + { .fw_name = "ext-32k" }, + { .fw_name = "ext-26m" }, +}; +static SPRD_MUX_CLK_DATA(sim0_32k, "sim0-32k", sim0_32k_parents, 0x94, + 0, 1, SC9863A_MUX_FLAG); + +static struct sprd_clk_common *sc9863a_ap_clks[] = { + /* address base is 0x21500000 */ + &ap_apb.common, + &ap_ce.common, + &nandc_ecc.common, + &nandc_26m.common, + &emmc_32k.common, + &sdio0_32k.common, + &sdio1_32k.common, + &sdio2_32k.common, + &otg_utmi.common, + &ap_uart0.common, + &ap_uart1.common, + &ap_uart2.common, + &ap_uart3.common, + &ap_uart4.common, + &ap_i2c0.common, + &ap_i2c1.common, + &ap_i2c2.common, + &ap_i2c3.common, + &ap_i2c4.common, + &ap_i2c5.common, + &ap_i2c6.common, + &ap_spi0.common, + &ap_spi1.common, + &ap_spi2.common, + &ap_spi3.common, + &ap_iis0.common, + &ap_iis1.common, + &ap_iis2.common, + &sim0.common, + &sim0_32k.common, +}; + +static struct clk_hw_onecell_data sc9863a_ap_clk_hws = { + .hws = { + [CLK_AP_APB] = &ap_apb.common.hw, + [CLK_AP_CE] = &ap_ce.common.hw, + [CLK_NANDC_ECC] = &nandc_ecc.common.hw, + [CLK_NANDC_26M] = &nandc_26m.common.hw, + [CLK_EMMC_32K] = &emmc_32k.common.hw, + [CLK_SDIO0_32K] = &sdio0_32k.common.hw, + [CLK_SDIO1_32K] = &sdio1_32k.common.hw, + [CLK_SDIO2_32K] = &sdio2_32k.common.hw, + [CLK_OTG_UTMI] = &otg_utmi.common.hw, + [CLK_AP_UART0] = &ap_uart0.common.hw, + [CLK_AP_UART1] = &ap_uart1.common.hw, + [CLK_AP_UART2] = &ap_uart2.common.hw, + [CLK_AP_UART3] = &ap_uart3.common.hw, + [CLK_AP_UART4] = &ap_uart4.common.hw, + [CLK_AP_I2C0] = &ap_i2c0.common.hw, + [CLK_AP_I2C1] = &ap_i2c1.common.hw, + [CLK_AP_I2C2] = &ap_i2c2.common.hw, + [CLK_AP_I2C3] = &ap_i2c3.common.hw, + [CLK_AP_I2C4] = &ap_i2c4.common.hw, + [CLK_AP_I2C5] = &ap_i2c5.common.hw, + [CLK_AP_I2C6] = &ap_i2c6.common.hw, + [CLK_AP_SPI0] = &ap_spi0.common.hw, + [CLK_AP_SPI1] = &ap_spi1.common.hw, + [CLK_AP_SPI2] = &ap_spi2.common.hw, + [CLK_AP_SPI3] = &ap_spi3.common.hw, + [CLK_AP_IIS0] = &ap_iis0.common.hw, + [CLK_AP_IIS1] = &ap_iis1.common.hw, + [CLK_AP_IIS2] = &ap_iis2.common.hw, + [CLK_SIM0] = &sim0.common.hw, + [CLK_SIM0_32K] = &sim0_32k.common.hw, + }, + .num = CLK_AP_CLK_NUM, +}; + +static const struct sprd_clk_desc sc9863a_ap_clk_desc = { + .clk_clks = sc9863a_ap_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_ap_clks), + .hw_clks = &sc9863a_ap_clk_hws, +}; + +static SPRD_SC_GATE_CLK_HW(otg_eb, "otg-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(4), 0, 0); +static SPRD_SC_GATE_CLK_HW(dma_eb, "dma-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(5), 0, 0); +static SPRD_SC_GATE_CLK_HW(ce_eb, "ce-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(6), 0, 0); +static SPRD_SC_GATE_CLK_HW(nandc_eb, "nandc-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(7), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio0_eb, "sdio0-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(8), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio1_eb, "sdio1-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(9), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio2_eb, "sdio2-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(10), 0, 0); +static SPRD_SC_GATE_CLK_HW(emmc_eb, "emmc-eb", &ap_axi.common.hw, 0x0, 0x1000, + BIT(11), 0, 0); +static SPRD_SC_GATE_CLK_HW(emmc_32k_eb, "emmc-32k-eb", &ap_axi.common.hw, 0x0, + 0x1000, BIT(27), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio0_32k_eb, "sdio0-32k-eb", &ap_axi.common.hw, 0x0, + 0x1000, BIT(28), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio1_32k_eb, "sdio1-32k-eb", &ap_axi.common.hw, 0x0, + 0x1000, BIT(29), 0, 0); +static SPRD_SC_GATE_CLK_HW(sdio2_32k_eb, "sdio2-32k-eb", &ap_axi.common.hw, 0x0, + 0x1000, BIT(30), 0, 0); +static SPRD_SC_GATE_CLK_HW(nandc_26m_eb, "nandc-26m-eb", &ap_axi.common.hw, 0x0, + 0x1000, BIT(31), 0, 0); +static SPRD_SC_GATE_CLK_HW(dma_eb2, "dma-eb2", &ap_axi.common.hw, 0x18, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK_HW(ce_eb2, "ce-eb2", &ap_axi.common.hw, 0x18, + 0x1000, BIT(1), 0, 0); + +static struct sprd_clk_common *sc9863a_apahb_gate_clks[] = { + /* address base is 0x20e00000 */ + &otg_eb.common, + &dma_eb.common, + &ce_eb.common, + &nandc_eb.common, + &sdio0_eb.common, + &sdio1_eb.common, + &sdio2_eb.common, + &emmc_eb.common, + &emmc_32k_eb.common, + &sdio0_32k_eb.common, + &sdio1_32k_eb.common, + &sdio2_32k_eb.common, + &nandc_26m_eb.common, + &dma_eb2.common, + &ce_eb2.common, +}; + +static struct clk_hw_onecell_data sc9863a_apahb_gate_hws = { + .hws = { + [CLK_OTG_EB] = &otg_eb.common.hw, + [CLK_DMA_EB] = &dma_eb.common.hw, + [CLK_CE_EB] = &ce_eb.common.hw, + [CLK_NANDC_EB] = &nandc_eb.common.hw, + [CLK_SDIO0_EB] = &sdio0_eb.common.hw, + [CLK_SDIO1_EB] = &sdio1_eb.common.hw, + [CLK_SDIO2_EB] = &sdio2_eb.common.hw, + [CLK_EMMC_EB] = &emmc_eb.common.hw, + [CLK_EMMC_32K_EB] = &emmc_32k_eb.common.hw, + [CLK_SDIO0_32K_EB] = &sdio0_32k_eb.common.hw, + [CLK_SDIO1_32K_EB] = &sdio1_32k_eb.common.hw, + [CLK_SDIO2_32K_EB] = &sdio2_32k_eb.common.hw, + [CLK_NANDC_26M_EB] = &nandc_26m_eb.common.hw, + [CLK_DMA_EB2] = &dma_eb2.common.hw, + [CLK_CE_EB2] = &ce_eb2.common.hw, + }, + .num = CLK_AP_AHB_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9863a_apahb_gate_desc = { + .clk_clks = sc9863a_apahb_gate_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_apahb_gate_clks), + .hw_clks = &sc9863a_apahb_gate_hws, +}; + +/* aon gate clocks */ +static SPRD_SC_GATE_CLK_HW(gpio_eb, "gpio-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK_HW(pwm0_eb, "pwm0-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK_HW(pwm1_eb, "pwm1-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(pwm2_eb, "pwm2-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK_HW(pwm3_eb, "pwm3-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK_HW(kpd_eb, "kpd-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK_HW(aon_syst_eb, "aon-syst-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_syst_eb, "ap-syst-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(aon_tmr_eb, "aon-tmr-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(11), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(efuse_eb, "efuse-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(13), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(eic_eb, "eic-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(14), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(intc_eb, "intc-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(adi_eb, "adi-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(audif_eb, "audif-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK_HW(aud_eb, "aud-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK_HW(vbc_eb, "vbc-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(19), 0, 0); +static SPRD_SC_GATE_CLK_HW(pin_eb, "pin-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_wdg_eb, "ap-wdg-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(24), 0, 0); +static SPRD_SC_GATE_CLK_HW(mm_eb, "mm-eb", &aon_apb.common.hw, 0x0, + 0x1000, BIT(25), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(aon_apb_ckg_eb, "aon-apb-ckg-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(26), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ca53_ts0_eb, "ca53-ts0-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(28), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ca53_ts1_eb, "ca53-ts1-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(29), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ca53_dap_eb, "ca53-dap-eb", &aon_apb.common.hw, + 0x0, 0x1000, BIT(30), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(pmu_eb, "pmu-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(thm_eb, "thm-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(aux0_eb, "aux0-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(aux1_eb, "aux1-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK_HW(aux2_eb, "aux2-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(probe_eb, "probe-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK_HW(emc_ref_eb, "emc-ref-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ca53_wdg_eb, "ca53-wdg-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_tmr1_eb, "ap-tmr1-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK_HW(ap_tmr2_eb, "ap-tmr2-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK_HW(disp_emc_eb, "disp-emc-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK_HW(zip_emc_eb, "zip-emc-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(12), 0, 0); +static SPRD_SC_GATE_CLK_HW(gsp_emc_eb, "gsp-emc-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK_HW(mm_vsp_eb, "mm-vsp-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK_HW(mdar_eb, "mdar-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK_HW(rtc4m0_cal_eb, "rtc4m0-cal-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK_HW(rtc4m1_cal_eb, "rtc4m1-cal-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(19), 0, 0); +static SPRD_SC_GATE_CLK_HW(djtag_eb, "djtag-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(20), 0, 0); +static SPRD_SC_GATE_CLK_HW(mbox_eb, "mbox-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(21), 0, 0); +static SPRD_SC_GATE_CLK_HW(aon_dma_eb, "aon-dma-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(22), 0, 0); +static SPRD_SC_GATE_CLK_HW(aon_apb_def_eb, "aon-apb-def-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(25), 0, 0); +static SPRD_SC_GATE_CLK_HW(ca5_ts0_eb, "ca5-ts0-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(26), 0, 0); +static SPRD_SC_GATE_CLK_HW(dbg_eb, "dbg-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(28), 0, 0); +static SPRD_SC_GATE_CLK_HW(dbg_emc_eb, "dbg-emc-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(29), 0, 0); +static SPRD_SC_GATE_CLK_HW(cross_trig_eb, "cross-trig-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(30), 0, 0); +static SPRD_SC_GATE_CLK_HW(serdes_dphy_eb, "serdes-dphy-eb", &aon_apb.common.hw, + 0x4, 0x1000, BIT(31), 0, 0); +static SPRD_SC_GATE_CLK_HW(arch_rtc_eb, "arch-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(kpd_rtc_eb, "kpd-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK_HW(aon_syst_rtc_eb, "aon-syst-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_syst_rtc_eb, "ap-syst-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(aon_tmr_rtc_eb, "aon-tmr-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_tmr0_rtc_eb, "ap-tmr0-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK_HW(eic_rtc_eb, "eic-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(eic_rtcdv5_eb, "eic-rtcdv5-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_wdg_rtc_eb, "ap-wdg-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ca53_wdg_rtc_eb, "ca53-wdg-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(thm_rtc_eb, "thm-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK_HW(athma_rtc_eb, "athma-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK_HW(gthma_rtc_eb, "gthma-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(12), 0, 0); +static SPRD_SC_GATE_CLK_HW(athma_rtc_a_eb, "athma-rtc-a-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK_HW(gthma_rtc_a_eb, "gthma-rtc-a-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK_HW(ap_tmr1_rtc_eb, "ap-tmr1-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(15), 0, 0); +static SPRD_SC_GATE_CLK_HW(ap_tmr2_rtc_eb, "ap-tmr2-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(16), 0, 0); +static SPRD_SC_GATE_CLK_HW(dxco_lc_rtc_eb, "dxco-lc-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK_HW(bb_cal_rtc_eb, "bb-cal-rtc-eb", &aon_apb.common.hw, + 0x10, 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK_HW(gpu_eb, "gpu-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK_HW(disp_eb, "disp-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK_HW(mm_emc_eb, "mm-emc-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK_HW(power_cpu_eb, "power-cpu-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(hw_i2c_eb, "hw-i2c-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK_HW(mm_vsp_emc_eb, "mm-vsp-emc-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK_HW(vsp_eb, "vsp-eb", &aon_apb.common.hw, 0x50, + 0x1000, BIT(16), 0, 0); +static SPRD_SC_GATE_CLK_HW(cssys_eb, "cssys-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK_HW(dmc_eb, "dmc-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(rosc_eb, "rosc-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK_HW(s_d_cfg_eb, "s-d-cfg-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK_HW(s_d_ref_eb, "s-d-ref-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK_HW(b_dma_eb, "b-dma-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK_HW(anlg_eb, "anlg-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(11), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(anlg_apb_eb, "anlg-apb-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK_HW(bsmtmr_eb, "bsmtmr-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK_HW(ap_axi_eb, "ap-axi-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc0_eb, "ap-intc0-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc1_eb, "ap-intc1-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc2_eb, "ap-intc2-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc3_eb, "ap-intc3-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(19), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc4_eb, "ap-intc4-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(ap_intc5_eb, "ap-intc5-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(21), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK_HW(scc_eb, "scc-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(22), 0, 0); +static SPRD_SC_GATE_CLK_HW(dphy_cfg_eb, "dphy-cfg-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(23), 0, 0); +static SPRD_SC_GATE_CLK_HW(dphy_ref_eb, "dphy-ref-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(24), 0, 0); +static SPRD_SC_GATE_CLK_HW(cphy_cfg_eb, "cphy-cfg-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(25), 0, 0); +static SPRD_SC_GATE_CLK_HW(otg_ref_eb, "otg-ref-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(26), 0, 0); +static SPRD_SC_GATE_CLK_HW(serdes_eb, "serdes-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(27), 0, 0); +static SPRD_SC_GATE_CLK_HW(aon_ap_emc_eb, "aon-ap-emc-eb", &aon_apb.common.hw, 0xb0, + 0x1000, BIT(28), 0, 0); +static struct sprd_clk_common *sc9863a_aonapb_gate_clks[] = { + /* address base is 0x402e0000 */ + &gpio_eb.common, + &pwm0_eb.common, + &pwm1_eb.common, + &pwm2_eb.common, + &pwm3_eb.common, + &kpd_eb.common, + &aon_syst_eb.common, + &ap_syst_eb.common, + &aon_tmr_eb.common, + &efuse_eb.common, + &eic_eb.common, + &intc_eb.common, + &adi_eb.common, + &audif_eb.common, + &aud_eb.common, + &vbc_eb.common, + &pin_eb.common, + &ap_wdg_eb.common, + &mm_eb.common, + &aon_apb_ckg_eb.common, + &ca53_ts0_eb.common, + &ca53_ts1_eb.common, + &ca53_dap_eb.common, + &pmu_eb.common, + &thm_eb.common, + &aux0_eb.common, + &aux1_eb.common, + &aux2_eb.common, + &probe_eb.common, + &emc_ref_eb.common, + &ca53_wdg_eb.common, + &ap_tmr1_eb.common, + &ap_tmr2_eb.common, + &disp_emc_eb.common, + &zip_emc_eb.common, + &gsp_emc_eb.common, + &mm_vsp_eb.common, + &mdar_eb.common, + &rtc4m0_cal_eb.common, + &rtc4m1_cal_eb.common, + &djtag_eb.common, + &mbox_eb.common, + &aon_dma_eb.common, + &aon_apb_def_eb.common, + &ca5_ts0_eb.common, + &dbg_eb.common, + &dbg_emc_eb.common, + &cross_trig_eb.common, + &serdes_dphy_eb.common, + &arch_rtc_eb.common, + &kpd_rtc_eb.common, + &aon_syst_rtc_eb.common, + &ap_syst_rtc_eb.common, + &aon_tmr_rtc_eb.common, + &ap_tmr0_rtc_eb.common, + &eic_rtc_eb.common, + &eic_rtcdv5_eb.common, + &ap_wdg_rtc_eb.common, + &ca53_wdg_rtc_eb.common, + &thm_rtc_eb.common, + &athma_rtc_eb.common, + >hma_rtc_eb.common, + &athma_rtc_a_eb.common, + >hma_rtc_a_eb.common, + &ap_tmr1_rtc_eb.common, + &ap_tmr2_rtc_eb.common, + &dxco_lc_rtc_eb.common, + &bb_cal_rtc_eb.common, + &gpu_eb.common, + &disp_eb.common, + &mm_emc_eb.common, + &power_cpu_eb.common, + &hw_i2c_eb.common, + &mm_vsp_emc_eb.common, + &vsp_eb.common, + &cssys_eb.common, + &dmc_eb.common, + &rosc_eb.common, + &s_d_cfg_eb.common, + &s_d_ref_eb.common, + &b_dma_eb.common, + &anlg_eb.common, + &anlg_apb_eb.common, + &bsmtmr_eb.common, + &ap_axi_eb.common, + &ap_intc0_eb.common, + &ap_intc1_eb.common, + &ap_intc2_eb.common, + &ap_intc3_eb.common, + &ap_intc4_eb.common, + &ap_intc5_eb.common, + &scc_eb.common, + &dphy_cfg_eb.common, + &dphy_ref_eb.common, + &cphy_cfg_eb.common, + &otg_ref_eb.common, + &serdes_eb.common, + &aon_ap_emc_eb.common, +}; + +static struct clk_hw_onecell_data sc9863a_aonapb_gate_hws = { + .hws = { + [CLK_GPIO_EB] = &gpio_eb.common.hw, + [CLK_PWM0_EB] = &pwm0_eb.common.hw, + [CLK_PWM1_EB] = &pwm1_eb.common.hw, + [CLK_PWM2_EB] = &pwm2_eb.common.hw, + [CLK_PWM3_EB] = &pwm3_eb.common.hw, + [CLK_KPD_EB] = &kpd_eb.common.hw, + [CLK_AON_SYST_EB] = &aon_syst_eb.common.hw, + [CLK_AP_SYST_EB] = &ap_syst_eb.common.hw, + [CLK_AON_TMR_EB] = &aon_tmr_eb.common.hw, + [CLK_EFUSE_EB] = &efuse_eb.common.hw, + [CLK_EIC_EB] = &eic_eb.common.hw, + [CLK_INTC_EB] = &intc_eb.common.hw, + [CLK_ADI_EB] = &adi_eb.common.hw, + [CLK_AUDIF_EB] = &audif_eb.common.hw, + [CLK_AUD_EB] = &aud_eb.common.hw, + [CLK_VBC_EB] = &vbc_eb.common.hw, + [CLK_PIN_EB] = &pin_eb.common.hw, + [CLK_AP_WDG_EB] = &ap_wdg_eb.common.hw, + [CLK_MM_EB] = &mm_eb.common.hw, + [CLK_AON_APB_CKG_EB] = &aon_apb_ckg_eb.common.hw, + [CLK_CA53_TS0_EB] = &ca53_ts0_eb.common.hw, + [CLK_CA53_TS1_EB] = &ca53_ts1_eb.common.hw, + [CLK_CS53_DAP_EB] = &ca53_dap_eb.common.hw, + [CLK_PMU_EB] = &pmu_eb.common.hw, + [CLK_THM_EB] = &thm_eb.common.hw, + [CLK_AUX0_EB] = &aux0_eb.common.hw, + [CLK_AUX1_EB] = &aux1_eb.common.hw, + [CLK_AUX2_EB] = &aux2_eb.common.hw, + [CLK_PROBE_EB] = &probe_eb.common.hw, + [CLK_EMC_REF_EB] = &emc_ref_eb.common.hw, + [CLK_CA53_WDG_EB] = &ca53_wdg_eb.common.hw, + [CLK_AP_TMR1_EB] = &ap_tmr1_eb.common.hw, + [CLK_AP_TMR2_EB] = &ap_tmr2_eb.common.hw, + [CLK_DISP_EMC_EB] = &disp_emc_eb.common.hw, + [CLK_ZIP_EMC_EB] = &zip_emc_eb.common.hw, + [CLK_GSP_EMC_EB] = &gsp_emc_eb.common.hw, + [CLK_MM_VSP_EB] = &mm_vsp_eb.common.hw, + [CLK_MDAR_EB] = &mdar_eb.common.hw, + [CLK_RTC4M0_CAL_EB] = &rtc4m0_cal_eb.common.hw, + [CLK_RTC4M1_CAL_EB] = &rtc4m1_cal_eb.common.hw, + [CLK_DJTAG_EB] = &djtag_eb.common.hw, + [CLK_MBOX_EB] = &mbox_eb.common.hw, + [CLK_AON_DMA_EB] = &aon_dma_eb.common.hw, + [CLK_AON_APB_DEF_EB] = &aon_apb_def_eb.common.hw, + [CLK_CA5_TS0_EB] = &ca5_ts0_eb.common.hw, + [CLK_DBG_EB] = &dbg_eb.common.hw, + [CLK_DBG_EMC_EB] = &dbg_emc_eb.common.hw, + [CLK_CROSS_TRIG_EB] = &cross_trig_eb.common.hw, + [CLK_SERDES_DPHY_EB] = &serdes_dphy_eb.common.hw, + [CLK_ARCH_RTC_EB] = &arch_rtc_eb.common.hw, + [CLK_KPD_RTC_EB] = &kpd_rtc_eb.common.hw, + [CLK_AON_SYST_RTC_EB] = &aon_syst_rtc_eb.common.hw, + [CLK_AP_SYST_RTC_EB] = &ap_syst_rtc_eb.common.hw, + [CLK_AON_TMR_RTC_EB] = &aon_tmr_rtc_eb.common.hw, + [CLK_AP_TMR0_RTC_EB] = &ap_tmr0_rtc_eb.common.hw, + [CLK_EIC_RTC_EB] = &eic_rtc_eb.common.hw, + [CLK_EIC_RTCDV5_EB] = &eic_rtcdv5_eb.common.hw, + [CLK_AP_WDG_RTC_EB] = &ap_wdg_rtc_eb.common.hw, + [CLK_CA53_WDG_RTC_EB] = &ca53_wdg_rtc_eb.common.hw, + [CLK_THM_RTC_EB] = &thm_rtc_eb.common.hw, + [CLK_ATHMA_RTC_EB] = &athma_rtc_eb.common.hw, + [CLK_GTHMA_RTC_EB] = >hma_rtc_eb.common.hw, + [CLK_ATHMA_RTC_A_EB] = &athma_rtc_a_eb.common.hw, + [CLK_GTHMA_RTC_A_EB] = >hma_rtc_a_eb.common.hw, + [CLK_AP_TMR1_RTC_EB] = &ap_tmr1_rtc_eb.common.hw, + [CLK_AP_TMR2_RTC_EB] = &ap_tmr2_rtc_eb.common.hw, + [CLK_DXCO_LC_RTC_EB] = &dxco_lc_rtc_eb.common.hw, + [CLK_BB_CAL_RTC_EB] = &bb_cal_rtc_eb.common.hw, + [CLK_GNU_EB] = &gpu_eb.common.hw, + [CLK_DISP_EB] = &disp_eb.common.hw, + [CLK_MM_EMC_EB] = &mm_emc_eb.common.hw, + [CLK_POWER_CPU_EB] = &power_cpu_eb.common.hw, + [CLK_HW_I2C_EB] = &hw_i2c_eb.common.hw, + [CLK_MM_VSP_EMC_EB] = &mm_vsp_emc_eb.common.hw, + [CLK_VSP_EB] = &vsp_eb.common.hw, + [CLK_CSSYS_EB] = &cssys_eb.common.hw, + [CLK_DMC_EB] = &dmc_eb.common.hw, + [CLK_ROSC_EB] = &rosc_eb.common.hw, + [CLK_S_D_CFG_EB] = &s_d_cfg_eb.common.hw, + [CLK_S_D_REF_EB] = &s_d_ref_eb.common.hw, + [CLK_B_DMA_EB] = &b_dma_eb.common.hw, + [CLK_ANLG_EB] = &anlg_eb.common.hw, + [CLK_ANLG_APB_EB] = &anlg_apb_eb.common.hw, + [CLK_BSMTMR_EB] = &bsmtmr_eb.common.hw, + [CLK_AP_AXI_EB] = &ap_axi_eb.common.hw, + [CLK_AP_INTC0_EB] = &ap_intc0_eb.common.hw, + [CLK_AP_INTC1_EB] = &ap_intc1_eb.common.hw, + [CLK_AP_INTC2_EB] = &ap_intc2_eb.common.hw, + [CLK_AP_INTC3_EB] = &ap_intc3_eb.common.hw, + [CLK_AP_INTC4_EB] = &ap_intc4_eb.common.hw, + [CLK_AP_INTC5_EB] = &ap_intc5_eb.common.hw, + [CLK_SCC_EB] = &scc_eb.common.hw, + [CLK_DPHY_CFG_EB] = &dphy_cfg_eb.common.hw, + [CLK_DPHY_REF_EB] = &dphy_ref_eb.common.hw, + [CLK_CPHY_CFG_EB] = &cphy_cfg_eb.common.hw, + [CLK_OTG_REF_EB] = &otg_ref_eb.common.hw, + [CLK_SERDES_EB] = &serdes_eb.common.hw, + [CLK_AON_AP_EMC_EB] = &aon_ap_emc_eb.common.hw, + }, + .num = CLK_AON_APB_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9863a_aonapb_gate_desc = { + .clk_clks = sc9863a_aonapb_gate_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_aonapb_gate_clks), + .hw_clks = &sc9863a_aonapb_gate_hws, +}; + +/* mm gate clocks */ +static SPRD_SC_GATE_CLK_HW(mahb_ckg_eb, "mahb-ckg-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(0), 0, 0); +static SPRD_SC_GATE_CLK_HW(mdcam_eb, "mdcam-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(1), 0, 0); +static SPRD_SC_GATE_CLK_HW(misp_eb, "misp-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(2), 0, 0); +static SPRD_SC_GATE_CLK_HW(mahbcsi_eb, "mahbcsi-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(3), 0, 0); +static SPRD_SC_GATE_CLK_HW(mcsi_s_eb, "mcsi-s-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(4), 0, 0); +static SPRD_SC_GATE_CLK_HW(mcsi_t_eb, "mcsi-t-eb", &mm_ahb.common.hw, 0x0, 0x1000, + BIT(5), 0, 0); +static SPRD_GATE_CLK_HW(dcam_axi_eb, "dcam-axi-eb", &mm_ahb.common.hw, 0x8, + BIT(0), 0, 0); +static SPRD_GATE_CLK_HW(isp_axi_eb, "isp-axi-eb", &mm_ahb.common.hw, 0x8, + BIT(1), 0, 0); +static SPRD_GATE_CLK_HW(mcsi_eb, "mcsi-eb", &mm_ahb.common.hw, 0x8, + BIT(2), 0, 0); +static SPRD_GATE_CLK_HW(mcsi_s_ckg_eb, "mcsi-s-ckg-eb", &mm_ahb.common.hw, 0x8, + BIT(3), 0, 0); +static SPRD_GATE_CLK_HW(mcsi_t_ckg_eb, "mcsi-t-ckg-eb", &mm_ahb.common.hw, 0x8, + BIT(4), 0, 0); +static SPRD_GATE_CLK_HW(sensor0_eb, "sensor0-eb", &mm_ahb.common.hw, 0x8, + BIT(5), 0, 0); +static SPRD_GATE_CLK_HW(sensor1_eb, "sensor1-eb", &mm_ahb.common.hw, 0x8, + BIT(6), 0, 0); +static SPRD_GATE_CLK_HW(sensor2_eb, "sensor2-eb", &mm_ahb.common.hw, 0x8, + BIT(7), 0, 0); +static SPRD_GATE_CLK_HW(mcphy_cfg_eb, "mcphy-cfg-eb", &mm_ahb.common.hw, 0x8, + BIT(8), 0, 0); + +static struct sprd_clk_common *sc9863a_mm_gate_clks[] = { + /* address base is 0x60800000 */ + &mahb_ckg_eb.common, + &mdcam_eb.common, + &misp_eb.common, + &mahbcsi_eb.common, + &mcsi_s_eb.common, + &mcsi_t_eb.common, + &dcam_axi_eb.common, + &isp_axi_eb.common, + &mcsi_eb.common, + &mcsi_s_ckg_eb.common, + &mcsi_t_ckg_eb.common, + &sensor0_eb.common, + &sensor1_eb.common, + &sensor2_eb.common, + &mcphy_cfg_eb.common, +}; + +static struct clk_hw_onecell_data sc9863a_mm_gate_hws = { + .hws = { + [CLK_MAHB_CKG_EB] = &mahb_ckg_eb.common.hw, + [CLK_MDCAM_EB] = &mdcam_eb.common.hw, + [CLK_MISP_EB] = &misp_eb.common.hw, + [CLK_MAHBCSI_EB] = &mahbcsi_eb.common.hw, + [CLK_MCSI_S_EB] = &mcsi_s_eb.common.hw, + [CLK_MCSI_T_EB] = &mcsi_t_eb.common.hw, + [CLK_DCAM_AXI_EB] = &dcam_axi_eb.common.hw, + [CLK_ISP_AXI_EB] = &isp_axi_eb.common.hw, + [CLK_MCSI_EB] = &mcsi_eb.common.hw, + [CLK_MCSI_S_CKG_EB] = &mcsi_s_ckg_eb.common.hw, + [CLK_MCSI_T_CKG_EB] = &mcsi_t_ckg_eb.common.hw, + [CLK_SENSOR0_EB] = &sensor0_eb.common.hw, + [CLK_SENSOR1_EB] = &sensor1_eb.common.hw, + [CLK_SENSOR2_EB] = &sensor2_eb.common.hw, + [CLK_MCPHY_CFG_EB] = &mcphy_cfg_eb.common.hw, + }, + .num = CLK_MM_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9863a_mm_gate_desc = { + .clk_clks = sc9863a_mm_gate_clks, + .num_clk_clks = ARRAY_SIZE(sc9863a_mm_gate_clks), + .hw_clks = &sc9863a_mm_gate_hws, +}; + +static SPRD_SC_GATE_CLK_FW_NAME(sim0_eb, "sim0-eb", "ext-26m", 0x0, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(iis0_eb, "iis0-eb", "ext-26m", 0x0, + 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(iis1_eb, "iis1-eb", "ext-26m", 0x0, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(iis2_eb, "iis2-eb", "ext-26m", 0x0, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(spi0_eb, "spi0-eb", "ext-26m", 0x0, + 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(spi1_eb, "spi1-eb", "ext-26m", 0x0, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(spi2_eb, "spi2-eb", "ext-26m", 0x0, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c0_eb, "i2c0-eb", "ext-26m", 0x0, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c1_eb, "i2c1-eb", "ext-26m", 0x0, + 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c2_eb, "i2c2-eb", "ext-26m", 0x0, + 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c3_eb, "i2c3-eb", "ext-26m", 0x0, + 0x1000, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c4_eb, "i2c4-eb", "ext-26m", 0x0, + 0x1000, BIT(12), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(uart0_eb, "uart0-eb", "ext-26m", 0x0, + 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(uart1_eb, "uart1-eb", "ext-26m", 0x0, + 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(uart2_eb, "uart2-eb", "ext-26m", 0x0, + 0x1000, BIT(15), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(uart3_eb, "uart3-eb", "ext-26m", 0x0, + 0x1000, BIT(16), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(uart4_eb, "uart4-eb", "ext-26m", 0x0, + 0x1000, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(sim0_32k_eb, "sim0_32k-eb", "ext-26m", 0x0, + 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(spi3_eb, "spi3-eb", "ext-26m", 0x0, + 0x1000, BIT(19), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c5_eb, "i2c5-eb", "ext-26m", 0x0, + 0x1000, BIT(20), 0, 0); +static SPRD_SC_GATE_CLK_FW_NAME(i2c6_eb, "i2c6-eb", "ext-26m", 0x0, + 0x1000, BIT(21), 0, 0); + +static struct sprd_clk_common *sc9863a_apapb_gate[] = { + /* address base is 0x71300000 */ + &sim0_eb.common, + &iis0_eb.common, + &iis1_eb.common, + &iis2_eb.common, + &spi0_eb.common, + &spi1_eb.common, + &spi2_eb.common, + &i2c0_eb.common, + &i2c1_eb.common, + &i2c2_eb.common, + &i2c3_eb.common, + &i2c4_eb.common, + &uart0_eb.common, + &uart1_eb.common, + &uart2_eb.common, + &uart3_eb.common, + &uart4_eb.common, + &sim0_32k_eb.common, + &spi3_eb.common, + &i2c5_eb.common, + &i2c6_eb.common, +}; + +static struct clk_hw_onecell_data sc9863a_apapb_gate_hws = { + .hws = { + [CLK_SIM0_EB] = &sim0_eb.common.hw, + [CLK_IIS0_EB] = &iis0_eb.common.hw, + [CLK_IIS1_EB] = &iis1_eb.common.hw, + [CLK_IIS2_EB] = &iis2_eb.common.hw, + [CLK_SPI0_EB] = &spi0_eb.common.hw, + [CLK_SPI1_EB] = &spi1_eb.common.hw, + [CLK_SPI2_EB] = &spi2_eb.common.hw, + [CLK_I2C0_EB] = &i2c0_eb.common.hw, + [CLK_I2C1_EB] = &i2c1_eb.common.hw, + [CLK_I2C2_EB] = &i2c2_eb.common.hw, + [CLK_I2C3_EB] = &i2c3_eb.common.hw, + [CLK_I2C4_EB] = &i2c4_eb.common.hw, + [CLK_UART0_EB] = &uart0_eb.common.hw, + [CLK_UART1_EB] = &uart1_eb.common.hw, + [CLK_UART2_EB] = &uart2_eb.common.hw, + [CLK_UART3_EB] = &uart3_eb.common.hw, + [CLK_UART4_EB] = &uart4_eb.common.hw, + [CLK_SIM0_32K_EB] = &sim0_32k_eb.common.hw, + [CLK_SPI3_EB] = &spi3_eb.common.hw, + [CLK_I2C5_EB] = &i2c5_eb.common.hw, + [CLK_I2C6_EB] = &i2c6_eb.common.hw, + }, + .num = CLK_AP_APB_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9863a_apapb_gate_desc = { + .clk_clks = sc9863a_apapb_gate, + .num_clk_clks = ARRAY_SIZE(sc9863a_apapb_gate), + .hw_clks = &sc9863a_apapb_gate_hws, +}; + +static const struct of_device_id sprd_sc9863a_clk_ids[] = { + { .compatible = "sprd,sc9863a-ap-clk", /* 0x21500000 */ + .data = &sc9863a_ap_clk_desc }, + { .compatible = "sprd,sc9863a-pmu-gate", /* 0x402b0000 */ + .data = &sc9863a_pmu_gate_desc }, + { .compatible = "sprd,sc9863a-pll", /* 0x40353000 */ + .data = &sc9863a_pll_desc }, + { .compatible = "sprd,sc9863a-mpll", /* 0x40359000 */ + .data = &sc9863a_mpll_desc }, + { .compatible = "sprd,sc9863a-rpll", /* 0x4035c000 */ + .data = &sc9863a_rpll_desc }, + { .compatible = "sprd,sc9863a-dpll", /* 0x40363000 */ + .data = &sc9863a_dpll_desc }, + { .compatible = "sprd,sc9863a-aon-clk", /* 0x402d0000 */ + .data = &sc9863a_aon_clk_desc }, + { .compatible = "sprd,sc9863a-apahb-gate", /* 0x20e00000 */ + .data = &sc9863a_apahb_gate_desc }, + { .compatible = "sprd,sc9863a-aonapb-gate", /* 0x402e0000 */ + .data = &sc9863a_aonapb_gate_desc }, + { .compatible = "sprd,sc9863a-mm-gate", /* 0x60800000 */ + .data = &sc9863a_mm_gate_desc }, + { .compatible = "sprd,sc9863a-apapb-gate", /* 0x71300000 */ + .data = &sc9863a_apapb_gate_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, sprd_sc9863a_clk_ids); + +static int sc9863a_clk_probe(struct platform_device *pdev) +{ + const struct sprd_clk_desc *desc; + int ret; + + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -ENODEV; + + ret = sprd_clk_regmap_init(pdev, desc); + if (ret) + return ret; + + return sprd_clk_probe(&pdev->dev, desc->hw_clks); +} + +static struct platform_driver sc9863a_clk_driver = { + .probe = sc9863a_clk_probe, + .driver = { + .name = "sc9863a-clk", + .of_match_table = sprd_sc9863a_clk_ids, + }, +}; +module_platform_driver(sc9863a_clk_driver); + +MODULE_DESCRIPTION("Spreadtrum SC9863A Clock Driver"); +MODULE_LICENSE("GPL v2"); From ba0eb9d57a3781a450b8b5eb15c497cccb18ee45 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 24 Mar 2020 19:14:12 -0700 Subject: [PATCH 558/809] clk: tegra: Use NULL for pointer initialization This silences a sparse warning about using a plain integer instead of NULL for a pointer. Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra210.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index c6304f5e813e..defe3b7ebfa4 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2993,7 +2993,7 @@ static const char * const la_parents[] = { }; static struct tegra_clk_periph tegra210_la = - TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, 0); + TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, NULL); static __init void tegra210_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base) From 2cf7a4cbcb4e108aae666dc6a81cedf69e1cba37 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 9 Mar 2020 15:12:31 -0700 Subject: [PATCH 559/809] clk: qcom: rpmh: Simplify clk_rpmh_bcm_send_cmd() This function has some duplication in unlocking a mutex and returns in a few different places. Let's use some if statements to consolidate code and make this a bit easier to read. Cc: Bjorn Andersson CC: Taniya Das Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200309221232.145630-2-sboyd@kernel.org --- drivers/clk/qcom/clk-rpmh.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index bfc29aec3a78..b1b277b55682 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -259,38 +259,33 @@ static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) { struct tcs_cmd cmd = { 0 }; u32 cmd_state; - int ret; + int ret = 0; mutex_lock(&rpmh_clk_lock); - - cmd_state = 0; if (enable) { cmd_state = 1; if (c->aggr_state) cmd_state = c->aggr_state; + } else { + cmd_state = 0; } - if (c->last_sent_aggr_state == cmd_state) { - mutex_unlock(&rpmh_clk_lock); - return 0; + if (c->last_sent_aggr_state != cmd_state) { + cmd.addr = c->res_addr; + cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state); + + ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable); + if (ret) { + dev_err(c->dev, "set active state of %s failed: (%d)\n", + c->res_name, ret); + } else { + c->last_sent_aggr_state = cmd_state; + } } - cmd.addr = c->res_addr; - cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state); - - ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable); - if (ret) { - dev_err(c->dev, "set active state of %s failed: (%d)\n", - c->res_name, ret); - mutex_unlock(&rpmh_clk_lock); - return ret; - } - - c->last_sent_aggr_state = cmd_state; - mutex_unlock(&rpmh_clk_lock); - return 0; + return ret; } static int clk_rpmh_bcm_prepare(struct clk_hw *hw) From 751d7923434f60bdb8507ce27651f5737bb59a74 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 9 Mar 2020 15:12:32 -0700 Subject: [PATCH 560/809] clk: qcom: rpmh: Drop unnecessary semicolons Some functions end in }; which is just bad style. Remove the extra semicolon. Cc: Bjorn Andersson Cc: Taniya Das Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20200309221232.145630-3-sboyd@kernel.org --- drivers/clk/qcom/clk-rpmh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index b1b277b55682..e2c669b08aff 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -227,7 +227,7 @@ static int clk_rpmh_prepare(struct clk_hw *hw) mutex_unlock(&rpmh_clk_lock); return ret; -}; +} static void clk_rpmh_unprepare(struct clk_hw *hw) { @@ -293,14 +293,14 @@ static int clk_rpmh_bcm_prepare(struct clk_hw *hw) struct clk_rpmh *c = to_clk_rpmh(hw); return clk_rpmh_bcm_send_cmd(c, true); -}; +} static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) { struct clk_rpmh *c = to_clk_rpmh(hw); clk_rpmh_bcm_send_cmd(c, false); -}; +} static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -316,7 +316,7 @@ static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, clk_rpmh_bcm_send_cmd(c, true); return 0; -}; +} static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) From 32f5f62d7991c62095ee62a060b35dec0a9ac404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Tue, 3 Mar 2020 21:01:48 +0100 Subject: [PATCH 561/809] gpio: uapi: Improve phrasing around arrays representing empty strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Character arrays can be considered empty strings (if they are immediately terminated), but they cannot be NULL. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Bartosz Golaszewski --- include/uapi/linux/gpio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index dca320764e4d..0206383c0383 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -18,7 +18,7 @@ * struct gpiochip_info - Information about a certain GPIO chip * @name: the Linux kernel name of this GPIO chip * @label: a functional name for this GPIO chip, such as a product - * number, may be NULL + * number, may be empty * @lines: number of GPIO lines on this chip */ struct gpiochip_info { @@ -44,10 +44,10 @@ struct gpiochip_info { * @flags: various flags for this line * @name: the name of this GPIO line, such as the output pin of the line on the * chip, a rail or a pin header name on a board, as specified by the gpio - * chip, may be NULL + * chip, may be empty * @consumer: a functional name for the consumer of this GPIO line as set by - * whatever is using it, will be NULL if there is no current user but may - * also be NULL if the consumer doesn't set this up + * whatever is using it, will be empty if there is no current user but may + * also be empty if the consumer doesn't set this up */ struct gpioline_info { __u32 line_offset; From f8c3cea834d27ad1a292f735ef092be7aaef1bba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 3 Mar 2020 16:50:35 +0100 Subject: [PATCH 562/809] docs: gpio: driver.rst: don't mark literal blocks twice Two literal blocks there are marked with both "::" and .. code-block:: c This causes Sphinx (2.4.1) to do the wrong thing, causing lots of warnings: Documentation/driver-api/gpio/driver.rst:425: WARNING: Unexpected indentation. Documentation/driver-api/gpio/driver.rst:423: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:427: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/driver-api/gpio/driver.rst:429: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:429: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:429: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:433: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:446: WARNING: Unexpected indentation. Documentation/driver-api/gpio/driver.rst:440: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:440: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:447: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/driver-api/gpio/driver.rst:449: WARNING: Definition list ends without a blank line; unexpected unindent. Documentation/driver-api/gpio/driver.rst:462: WARNING: Unexpected indentation. Documentation/driver-api/gpio/driver.rst:460: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:462: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:465: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/driver-api/gpio/driver.rst:467: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:467: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:467: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:471: WARNING: Inline emphasis start-string without end-string. Documentation/driver-api/gpio/driver.rst:478: WARNING: Inline emphasis start-string without end-string. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/gpio/driver.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/driver-api/gpio/driver.rst index 871922529332..9809f593c0ab 100644 --- a/Documentation/driver-api/gpio/driver.rst +++ b/Documentation/driver-api/gpio/driver.rst @@ -416,7 +416,7 @@ The preferred way to set up the helpers is to fill in the struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip. If you do this, the additional irq_chip will be set up by gpiolib at the same time as setting up the rest of the GPIO functionality. The following -is a typical example of a cascaded interrupt handler using gpio_irq_chip:: +is a typical example of a cascaded interrupt handler using gpio_irq_chip: .. code-block:: c @@ -453,7 +453,7 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:: return devm_gpiochip_add_data(dev, &g->gc, g); The helper support using hierarchical interrupt controllers as well. -In this case the typical set-up will look like this:: +In this case the typical set-up will look like this: .. code-block:: c From 1a555713ac9d169dbe43363aafe0633f2dc58daf Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 3 Mar 2020 10:28:28 +0100 Subject: [PATCH 563/809] gpio: pl061: Warn when IRQ line has not been configured Existing (irq < 0) condition is always false because adev->irq has unsigned type and contains 0 in case of failed irq_of_parse_and_map(). Up to now all the mapping errors were silently ignored. Seems that repairing this check would be backwards-incompatible and might break the probe() for the implementations without IRQ support. Therefore warn the user instead. Signed-off-by: Alexander Sverdlin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pl061.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 5df7782e348f..3439120f166a 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -326,10 +326,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) writeb(0, pl061->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; - if (irq < 0) { - dev_err(&adev->dev, "invalid IRQ\n"); - return -ENODEV; - } + if (!irq) + dev_warn(&adev->dev, "IRQ support disabled\n"); pl061->parent_irq = irq; girq = &pl061->gc.irq; From d4e9361442e23fe6edd4c1702004f19fc15553df Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Sat, 7 Mar 2020 21:31:57 +0800 Subject: [PATCH 564/809] gpio: mxc: Add COMPILE_TEST support for GPIO_MXC Add COMPILE_TEST support to GPIO_MXC driver for better compile testing coverage. Signed-off-by: Anson Huang Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6234ccc90e7e..ef55c45131c5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -394,7 +394,7 @@ config GPIO_MVEBU config GPIO_MXC def_bool y - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST select GPIO_GENERIC select GENERIC_IRQ_CHIP From 6876ca311bfca5d7cae30c4b529aeb9449c072eb Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 9 Mar 2020 09:57:38 +0800 Subject: [PATCH 565/809] gpio: mxs: add COMPILE_TEST support for GPIO_MXS Add COMPILE_TEST support to GPIO_MXS driver for better compile testing coverage. Signed-off-by: Anson Huang Reported-by: kbuild test robot Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ef55c45131c5..1b96169d84f7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -400,7 +400,7 @@ config GPIO_MXC config GPIO_MXS def_bool y - depends on ARCH_MXS + depends on ARCH_MXS || COMPILE_TEST select GPIO_GENERIC select GENERIC_IRQ_CHIP From 525b0858ff2fdb78defec2d4d6d63baaa423d5fd Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 13 Mar 2020 16:42:44 +1300 Subject: [PATCH 566/809] gpio: mvebu: avoid error message for optional IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_irq() will generate an error message if the requested irq is not present mvebu-gpio f1010140.gpio: IRQ index 3 not found use platform_get_irq_optional() to avoid the error message being generated. Signed-off-by: Chris Packham Acked-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index d2b999c7987f..3c9f4fb3d5a2 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1247,7 +1247,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) * pins. */ for (i = 0; i < 4; i++) { - int irq = platform_get_irq(pdev, i); + int irq = platform_get_irq_optional(pdev, i); if (irq < 0) continue; From d1ee7e1f5c9191afb69ce46cc7752e4257340a31 Mon Sep 17 00:00:00 2001 From: Gabriel Ravier Date: Thu, 12 Mar 2020 15:50:21 +0100 Subject: [PATCH 567/809] tools: gpio-hammer: Avoid potential overflow in main If '-o' was used more than 64 times in a single invocation of gpio-hammer, this could lead to an overflow of the 'lines' array. This commit fixes this by avoiding the overflow and giving a proper diagnostic back to the user Signed-off-by: Gabriel Ravier Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-hammer.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index 0e0060a6eb34..083399d276e4 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -135,7 +135,14 @@ int main(int argc, char **argv) device_name = optarg; break; case 'o': - lines[i] = strtoul(optarg, NULL, 10); + /* + * Avoid overflow. Do not immediately error, we want to + * be able to accurately report on the amount of times + * '-o' was given to give an accurate error message + */ + if (i < GPIOHANDLES_MAX) + lines[i] = strtoul(optarg, NULL, 10); + i++; break; case '?': @@ -143,6 +150,14 @@ int main(int argc, char **argv) return -1; } } + + if (i >= GPIOHANDLES_MAX) { + fprintf(stderr, + "Only %d occurences of '-o' are allowed, %d were found\n", + GPIOHANDLES_MAX, i + 1); + return -1; + } + nlines = i; if (!device_name || !nlines) { From d19d2de61fb131abcd29f7c61d3f168f687bfd6e Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Sun, 15 Mar 2020 20:13:37 +0800 Subject: [PATCH 568/809] gpio: mmio: introduce BGPIOF_NO_SET_ON_INPUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some gpio controllers ignores pin value writing when that pin is configured as input mode. As a result, bgpio_dir_out should set pin to output before configuring pin values or gpio pin values can't be set up properly. Introduce two variants of bgpio_dir_out: bgpio_dir_out_val_first and bgpio_dir_out_dir_first, and assign direction_output according to a new flag: BGPIOF_NO_SET_ON_INPUT. Signed-off-by: Chuanhong Guo Tested-by: René van Dorst Reviewed-by: Sergio Paracuellos Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mmio.c | 23 +++++++++++++++++++---- include/linux/gpio/driver.h | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index f729e3e9e983..b778f33cc6af 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -389,12 +389,10 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) return GPIO_LINE_DIRECTION_IN; } -static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; - gc->set(gc, gpio, val); - spin_lock_irqsave(&gc->bgpio_lock, flags); gc->bgpio_dir |= bgpio_line2mask(gc, gpio); @@ -405,7 +403,21 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} +static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + bgpio_dir_out(gc, gpio, val); + gc->set(gc, gpio, val); + return 0; +} + +static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + gc->set(gc, gpio, val); + bgpio_dir_out(gc, gpio, val); return 0; } @@ -538,7 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc, if (dirout || dirin) { gc->reg_dir_out = dirout; gc->reg_dir_in = dirin; - gc->direction_output = bgpio_dir_out; + if (flags & BGPIOF_NO_SET_ON_INPUT) + gc->direction_output = bgpio_dir_out_dir_first; + else + gc->direction_output = bgpio_dir_out_val_first; gc->direction_input = bgpio_dir_in; gc->get_direction = bgpio_get_dir; } else { diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 6ef05bccc0a6..ed65e00ee977 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -572,6 +572,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, #define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ #define BGPIOF_NO_OUTPUT BIT(5) /* only input */ +#define BGPIOF_NO_SET_ON_INPUT BIT(6) int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq); From 427cabede05cd93a4ad79153679f6aab21dc1bfa Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Sun, 15 Mar 2020 20:13:38 +0800 Subject: [PATCH 569/809] gpio: mt7621: add BGPIOF_NO_SET_ON_INPUT flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DSET/DCLR registers only works on output pins. Add corresponding BGPIOF_NO_SET_ON_INPUT flag to bgpio_init call to fix direction_out behavior. Signed-off-by: Chuanhong Guo Tested-by: René van Dorst Reviewed-by: Sergio Paracuellos Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mt7621.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index b992321bb852..82fb20dca53a 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -227,8 +227,8 @@ mediatek_gpio_bank_probe(struct device *dev, ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE); diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE); - ret = bgpio_init(&rg->chip, dev, 4, - dat, set, ctrl, diro, NULL, 0); + ret = bgpio_init(&rg->chip, dev, 4, dat, set, ctrl, diro, NULL, + BGPIOF_NO_SET_ON_INPUT); if (ret) { dev_err(dev, "bgpio_init() failed\n"); return ret; From 55f17e2ae916e4443e5f0acf067a3b6e9180f1cd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 16 Mar 2020 09:23:40 +0000 Subject: [PATCH 570/809] tools: gpio-hammer: fix spelling mistake: "occurences" -> "occurrences" There is a spelling mistake in an error message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-hammer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index 083399d276e4..28d2329e83d2 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) if (i >= GPIOHANDLES_MAX) { fprintf(stderr, - "Only %d occurences of '-o' are allowed, %d were found\n", + "Only %d occurrences of '-o' are allowed, %d were found\n", GPIOHANDLES_MAX, i + 1); return -1; } From ee203bbd63c0ae75c7672f30ae09f74abfcf6f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 15 Mar 2020 17:34:34 +0100 Subject: [PATCH 571/809] gpiolib: gpio_name_to_desc: factor out !name check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since name == NULL can't ever match, move the check out of IRQ-disabled region. Signed-off-by: Michał Mirosław Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 00890f38f95f..c7ee224bcb86 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -301,6 +301,9 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) struct gpio_device *gdev; unsigned long flags; + if (!name) + return NULL; + spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(gdev, &gpio_devices, list) { @@ -309,7 +312,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) for (i = 0; i != gdev->ngpio; ++i) { struct gpio_desc *desc = &gdev->descs[i]; - if (!desc->name || !name) + if (!desc->name) continue; if (!strcmp(desc->name, name)) { From 1003bc16481a46fe5cecf99dcd3edbf48648d2a0 Mon Sep 17 00:00:00 2001 From: Gabriel Ravier Date: Mon, 16 Mar 2020 20:50:48 +0100 Subject: [PATCH 572/809] tools: gpio-hammer: Apply scripts/Lindent and retain good changes "retain good changes" means that I left the help string split up instead of having this weird thing where it tries to merge together the last three lines and it looks **really** bad Signed-off-by: Gabriel Ravier Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-hammer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index 28d2329e83d2..9fd926e8cb52 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -77,7 +77,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, fprintf(stdout, "[%c] ", swirr[j]); j++; - if (j == sizeof(swirr)-1) + if (j == sizeof(swirr) - 1) j = 0; fprintf(stdout, "["); From 97551625025320e9d635531625316e43c8ed62b0 Mon Sep 17 00:00:00 2001 From: Mykyta Poturai Date: Sun, 22 Mar 2020 12:10:17 +0200 Subject: [PATCH 573/809] tools: gpio: Fix typo in gpio-utils Replace COMSUMER with proper CONSUMER Signed-off-by: Mykyta Poturai Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index 53470de6a502..06003789e7c7 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c @@ -17,7 +17,7 @@ #include #include "gpio-utils.h" -#define COMSUMER "gpio-utils" +#define CONSUMER "gpio-utils" /** * doc: Operation of gpio @@ -209,7 +209,7 @@ int gpiotools_gets(const char *device_name, unsigned int *lines, ret = gpiotools_request_linehandle(device_name, lines, nlines, GPIOHANDLE_REQUEST_INPUT, data, - COMSUMER); + CONSUMER); if (ret < 0) return ret; @@ -259,7 +259,7 @@ int gpiotools_sets(const char *device_name, unsigned int *lines, ret = gpiotools_request_linehandle(device_name, lines, nlines, GPIOHANDLE_REQUEST_OUTPUT, data, - COMSUMER); + CONSUMER); if (ret < 0) return ret; From a741c2febeadc675aef84bcd6924b6522577d593 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Mar 2020 15:27:52 +0100 Subject: [PATCH 574/809] fanotify: Simplify create_fd() create_fd() is never used with invalid path. Also the only thing it needs to know from fanotify_event is the path. Simplify the function to take path directly and assume it is correct. Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify_user.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 0aa362b88550..e48fc07d80ef 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -96,15 +96,12 @@ out: return fsn_event; } -static int create_fd(struct fsnotify_group *group, - struct fanotify_event *event, +static int create_fd(struct fsnotify_group *group, struct path *path, struct file **file) { int client_fd; struct file *new_file; - pr_debug("%s: group=%p event=%p\n", __func__, group, event); - client_fd = get_unused_fd_flags(group->fanotify_data.f_flags); if (client_fd < 0) return client_fd; @@ -113,14 +110,9 @@ static int create_fd(struct fsnotify_group *group, * we need a new file handle for the userspace program so it can read even if it was * originally opened O_WRONLY. */ - /* it's possible this event was an overflow event. in that case dentry and mnt - * are NULL; That's fine, just don't call dentry open */ - if (event->path.dentry && event->path.mnt) - new_file = dentry_open(&event->path, - group->fanotify_data.f_flags | FMODE_NONOTIFY, - current_cred()); - else - new_file = ERR_PTR(-EOVERFLOW); + new_file = dentry_open(path, + group->fanotify_data.f_flags | FMODE_NONOTIFY, + current_cred()); if (IS_ERR(new_file)) { /* * we still send an event even if we can't open the file. this @@ -276,9 +268,13 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, metadata.pid = pid_vnr(event->pid); if (fanotify_event_has_path(event)) { - fd = create_fd(group, event, &f); - if (fd < 0) - return fd; + struct path *path = &event->path; + + if (path->mnt && path->dentry) { + fd = create_fd(group, path, &f); + if (fd < 0) + return fd; + } } else if (fanotify_event_has_fid(event)) { metadata.event_len += fanotify_event_info_len(event); } From afc894c784c84cb3bb85a235feca2cb278f7b023 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Mar 2020 16:55:37 +0100 Subject: [PATCH 575/809] fanotify: Store fanotify handles differently Currently, struct fanotify_fid groups fsid and file handle and is unioned together with struct path to save space. Also there is fh_type and fh_len directly in struct fanotify_event to avoid padding overhead. In the follwing patches, we will be adding more event types and this packing makes code difficult to follow. So unpack everything and create struct fanotify_fh which groups members logically related to file handle to make code easier to follow. In the following patch we will pack things again differently to make events smaller. Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 97 +++++++++++++++--------- fs/notify/fanotify/fanotify.h | 115 ++++++++++++++++------------- fs/notify/fanotify/fanotify_user.c | 39 +++++----- 3 files changed, 145 insertions(+), 106 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 960f4f4d9e8f..64b05be4058d 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -17,6 +17,31 @@ #include "fanotify.h" +static bool fanotify_path_equal(struct path *p1, struct path *p2) +{ + return p1->mnt == p2->mnt && p1->dentry == p2->dentry; +} + +static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, + __kernel_fsid_t *fsid2) +{ + return fsid1->val[0] == fsid1->val[0] && fsid2->val[1] == fsid2->val[1]; +} + +static bool fanotify_fh_equal(struct fanotify_fh *fh1, + struct fanotify_fh *fh2) +{ + if (fh1->type != fh2->type || fh1->len != fh2->len) + return false; + + /* Do not merge events if we failed to encode fh */ + if (fh1->type == FILEID_INVALID) + return false; + + return !fh1->len || + !memcmp(fanotify_fh_buf(fh1), fanotify_fh_buf(fh2), fh1->len); +} + static bool should_merge(struct fsnotify_event *old_fsn, struct fsnotify_event *new_fsn) { @@ -27,12 +52,12 @@ static bool should_merge(struct fsnotify_event *old_fsn, new = FANOTIFY_E(new_fsn); if (old_fsn->objectid != new_fsn->objectid || old->pid != new->pid || - old->fh_type != new->fh_type || old->fh_len != new->fh_len) + old->fh.type != new->fh.type) return false; if (fanotify_event_has_path(old)) { - return old->path.mnt == new->path.mnt && - old->path.dentry == new->path.dentry; + return fanotify_path_equal(fanotify_event_path(old), + fanotify_event_path(new)); } else if (fanotify_event_has_fid(old)) { /* * We want to merge many dirent events in the same dir (i.e. @@ -42,8 +67,11 @@ static bool should_merge(struct fsnotify_event *old_fsn, * mask FAN_CREATE|FAN_DELETE|FAN_ONDIR if it describes mkdir+ * unlink pair or rmdir+create pair of events. */ - return (old->mask & FS_ISDIR) == (new->mask & FS_ISDIR) && - fanotify_fid_equal(&old->fid, &new->fid, old->fh_len); + if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR)) + return false; + + return fanotify_fsid_equal(&old->fsid, &new->fsid) && + fanotify_fh_equal(&old->fh, &new->fh); } /* Do not merge events if we failed to encode fid */ @@ -213,15 +241,14 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, return test_mask & user_mask; } -static int fanotify_encode_fid(struct fanotify_event *event, - struct inode *inode, gfp_t gfp, - __kernel_fsid_t *fsid) +static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + gfp_t gfp) { - struct fanotify_fid *fid = &event->fid; - int dwords, bytes = 0; - int err, type; + int dwords, type, bytes = 0; + char *ext_buf = NULL; + void *buf = fh->buf; + int err; - fid->ext_fh = NULL; dwords = 0; err = -ENOENT; type = exportfs_encode_inode_fh(inode, NULL, &dwords, NULL); @@ -232,31 +259,32 @@ static int fanotify_encode_fid(struct fanotify_event *event, if (bytes > FANOTIFY_INLINE_FH_LEN) { /* Treat failure to allocate fh as failure to allocate event */ err = -ENOMEM; - fid->ext_fh = kmalloc(bytes, gfp); - if (!fid->ext_fh) + ext_buf = kmalloc(bytes, gfp); + if (!ext_buf) goto out_err; + + *fanotify_fh_ext_buf_ptr(fh) = ext_buf; + buf = ext_buf; } - type = exportfs_encode_inode_fh(inode, fanotify_fid_fh(fid, bytes), - &dwords, NULL); + type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL); err = -EINVAL; if (!type || type == FILEID_INVALID || bytes != dwords << 2) goto out_err; - fid->fsid = *fsid; - event->fh_len = bytes; + fh->type = type; + fh->len = bytes; - return type; + return; out_err: - pr_warn_ratelimited("fanotify: failed to encode fid (fsid=%x.%x, " - "type=%d, bytes=%d, err=%i)\n", - fsid->val[0], fsid->val[1], type, bytes, err); - kfree(fid->ext_fh); - fid->ext_fh = NULL; - event->fh_len = 0; - - return FILEID_INVALID; + pr_warn_ratelimited("fanotify: failed to encode fid (type=%d, len=%d, err=%i)\n", + type, bytes, err); + kfree(ext_buf); + *fanotify_fh_ext_buf_ptr(fh) = NULL; + /* Report the event without a file identifier on encode error */ + fh->type = FILEID_INVALID; + fh->len = 0; } /* @@ -326,16 +354,17 @@ init: __maybe_unused event->pid = get_pid(task_pid(current)); else event->pid = get_pid(task_tgid(current)); - event->fh_len = 0; + event->fh.len = 0; if (id && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { - /* Report the event without a file identifier on encode error */ - event->fh_type = fanotify_encode_fid(event, id, gfp, fsid); + event->fsid = *fsid; + if (id) + fanotify_encode_fh(&event->fh, id, gfp); } else if (path) { - event->fh_type = FILEID_ROOT; + event->fh.type = FILEID_ROOT; event->path = *path; path_get(path); } else { - event->fh_type = FILEID_INVALID; + event->fh.type = FILEID_INVALID; event->path.mnt = NULL; event->path.dentry = NULL; } @@ -483,8 +512,8 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event) event = FANOTIFY_E(fsn_event); if (fanotify_event_has_path(event)) path_put(&event->path); - else if (fanotify_event_has_ext_fh(event)) - kfree(event->fid.ext_fh); + else if (fanotify_fh_has_ext_buf(&event->fh)) + kfree(fanotify_fh_ext_buf(&event->fh)); put_pid(event->pid); if (fanotify_is_perm_event(event->mask)) { kmem_cache_free(fanotify_perm_event_cachep, diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 68b30504284c..f9da4481613d 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -18,39 +18,37 @@ enum { /* * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation). - * For 32bit arch, fid increases the size of fanotify_event by 12 bytes and - * fh_* fields increase the size of fanotify_event by another 4 bytes. - * For 64bit arch, fid increases the size of fanotify_fid by 8 bytes and - * fh_* fields are packed in a hole after mask. + * fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is + * stored in either the first or last 2 dwords. */ -#if BITS_PER_LONG == 32 #define FANOTIFY_INLINE_FH_LEN (3 << 2) -#else -#define FANOTIFY_INLINE_FH_LEN (4 << 2) -#endif -struct fanotify_fid { - __kernel_fsid_t fsid; - union { - unsigned char fh[FANOTIFY_INLINE_FH_LEN]; - unsigned char *ext_fh; - }; -}; +struct fanotify_fh { + unsigned char buf[FANOTIFY_INLINE_FH_LEN]; + u8 type; + u8 len; +} __aligned(4); -static inline void *fanotify_fid_fh(struct fanotify_fid *fid, - unsigned int fh_len) +static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) { - return fh_len <= FANOTIFY_INLINE_FH_LEN ? fid->fh : fid->ext_fh; + return fh->len > FANOTIFY_INLINE_FH_LEN; } -static inline bool fanotify_fid_equal(struct fanotify_fid *fid1, - struct fanotify_fid *fid2, - unsigned int fh_len) +static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh) { - return fid1->fsid.val[0] == fid2->fsid.val[0] && - fid1->fsid.val[1] == fid2->fsid.val[1] && - !memcmp(fanotify_fid_fh(fid1, fh_len), - fanotify_fid_fh(fid2, fh_len), fh_len); + BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) > + FANOTIFY_INLINE_FH_LEN); + return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *)); +} + +static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh) +{ + return *fanotify_fh_ext_buf_ptr(fh); +} + +static inline void *fanotify_fh_buf(struct fanotify_fh *fh) +{ + return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf; } /* @@ -62,50 +60,53 @@ struct fanotify_event { struct fsnotify_event fse; u32 mask; /* - * Those fields are outside fanotify_fid to pack fanotify_event nicely - * on 64bit arch and to use fh_type as an indication of whether path - * or fid are used in the union: - * FILEID_ROOT (0) for path, > 0 for fid, FILEID_INVALID for neither. + * With FAN_REPORT_FID, we do not hold any reference on the + * victim object. Instead we store its NFS file handle and its + * filesystem's fsid as a unique identifier. */ - u8 fh_type; - u8 fh_len; - u16 pad; - union { - /* - * We hold ref to this path so it may be dereferenced at any - * point during this object's lifetime - */ - struct path path; - /* - * With FAN_REPORT_FID, we do not hold any reference on the - * victim object. Instead we store its NFS file handle and its - * filesystem's fsid as a unique identifier. - */ - struct fanotify_fid fid; - }; + __kernel_fsid_t fsid; + struct fanotify_fh fh; + /* + * We hold ref to this path so it may be dereferenced at any + * point during this object's lifetime + */ + struct path path; struct pid *pid; }; static inline bool fanotify_event_has_path(struct fanotify_event *event) { - return event->fh_type == FILEID_ROOT; + return event->fh.type == FILEID_ROOT; } static inline bool fanotify_event_has_fid(struct fanotify_event *event) { - return event->fh_type != FILEID_ROOT && - event->fh_type != FILEID_INVALID; + return event->fh.type != FILEID_ROOT && + event->fh.type != FILEID_INVALID; } -static inline bool fanotify_event_has_ext_fh(struct fanotify_event *event) +static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) { - return fanotify_event_has_fid(event) && - event->fh_len > FANOTIFY_INLINE_FH_LEN; + if (fanotify_event_has_fid(event)) + return &event->fsid; + else + return NULL; } -static inline void *fanotify_event_fh(struct fanotify_event *event) +static inline struct fanotify_fh *fanotify_event_object_fh( + struct fanotify_event *event) { - return fanotify_fid_fh(&event->fid, event->fh_len); + if (fanotify_event_has_fid(event)) + return &event->fh; + else + return NULL; +} + +static inline int fanotify_event_object_fh_len(struct fanotify_event *event) +{ + struct fanotify_fh *fh = fanotify_event_object_fh(event); + + return fh ? fh->len : 0; } /* @@ -139,6 +140,14 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse) return container_of(fse, struct fanotify_event, fse); } +static inline struct path *fanotify_event_path(struct fanotify_event *event) +{ + if (fanotify_event_has_path(event)) + return &event->path; + else + return NULL; +} + struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, struct inode *inode, u32 mask, const void *data, int data_type, diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index e48fc07d80ef..0b3b74fa3a27 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -53,11 +53,13 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; static int fanotify_event_info_len(struct fanotify_event *event) { - if (!fanotify_event_has_fid(event)) + int fh_len = fanotify_event_object_fh_len(event); + + if (!fh_len) return 0; return roundup(sizeof(struct fanotify_event_info_fid) + - sizeof(struct file_handle) + event->fh_len, + sizeof(struct file_handle) + fh_len, FANOTIFY_EVENT_ALIGN); } @@ -200,8 +202,9 @@ static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) { struct fanotify_event_info_fid info = { }; struct file_handle handle = { }; - unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh; - size_t fh_len = event->fh_len; + unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; + struct fanotify_fh *fh = fanotify_event_object_fh(event); + size_t fh_len = fh->len; size_t len = fanotify_event_info_len(event); if (!len) @@ -213,13 +216,13 @@ static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) /* Copy event info fid header followed by vaiable sized file handle */ info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID; info.hdr.len = len; - info.fsid = event->fid.fsid; + info.fsid = *fanotify_event_fsid(event); if (copy_to_user(buf, &info, sizeof(info))) return -EFAULT; buf += sizeof(info); len -= sizeof(info); - handle.handle_type = event->fh_type; + handle.handle_type = fh->type; handle.handle_bytes = fh_len; if (copy_to_user(buf, &handle, sizeof(handle))) return -EFAULT; @@ -230,12 +233,12 @@ static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) * For an inline fh, copy through stack to exclude the copy from * usercopy hardening protections. */ - fh = fanotify_event_fh(event); + fh_buf = fanotify_fh_buf(fh); if (fh_len <= FANOTIFY_INLINE_FH_LEN) { - memcpy(bounce, fh, fh_len); - fh = bounce; + memcpy(bounce, fh_buf, fh_len); + fh_buf = bounce; } - if (copy_to_user(buf, fh, fh_len)) + if (copy_to_user(buf, fh_buf, fh_len)) return -EFAULT; /* Pad with 0's */ @@ -254,12 +257,14 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, { struct fanotify_event_metadata metadata; struct fanotify_event *event; + struct path *path; struct file *f = NULL; int ret, fd = FAN_NOFD; pr_debug("%s: group=%p event=%p\n", __func__, group, fsn_event); event = container_of(fsn_event, struct fanotify_event, fse); + path = fanotify_event_path(event); metadata.event_len = FAN_EVENT_METADATA_LEN; metadata.metadata_len = FAN_EVENT_METADATA_LEN; metadata.vers = FANOTIFY_METADATA_VERSION; @@ -267,16 +272,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; metadata.pid = pid_vnr(event->pid); - if (fanotify_event_has_path(event)) { - struct path *path = &event->path; - - if (path->mnt && path->dentry) { - fd = create_fd(group, path, &f); - if (fd < 0) - return fd; - } - } else if (fanotify_event_has_fid(event)) { + if (fanotify_event_has_fid(event)) { metadata.event_len += fanotify_event_info_len(event); + } else if (path && path->mnt && path->dentry) { + fd = create_fd(group, path, &f); + if (fd < 0) + return fd; } metadata.fd = fd; From 7088f35720a55b99624ea36091538baec7ec611f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Mar 2020 17:04:20 +0100 Subject: [PATCH 576/809] fanotify: divorce fanotify_path_event and fanotify_fid_event Breakup the union and make them both inherit from abstract fanotify_event. fanotify_path_event, fanotify_fid_event and fanotify_perm_event inherit from fanotify_event. type field in abstract fanotify_event determines the concrete event type. fanotify_path_event, fanotify_fid_event and fanotify_perm_event are allocated from separate memcache pools. Rename fanotify_perm_event casting macro to FANOTIFY_PERM(), so that FANOTIFY_PE() and FANOTIFY_FE() can be used as casting macros to fanotify_path_event and fanotify_fid_event. [JK: Cleanup FANOTIFY_PE() and FANOTIFY_FE() to be proper inline functions and remove requirement that fanotify_event is the first in event structures] Link: https://lore.kernel.org/r/20200319151022.31456-11-amir73il@gmail.com Suggested-by: Jan Kara Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 126 +++++++++++++++++++++-------- fs/notify/fanotify/fanotify.h | 77 +++++++++++------- fs/notify/fanotify/fanotify_user.c | 71 ++++++++-------- 3 files changed, 180 insertions(+), 94 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 64b05be4058d..39eb71f7c413 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -29,7 +29,7 @@ static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, } static bool fanotify_fh_equal(struct fanotify_fh *fh1, - struct fanotify_fh *fh2) + struct fanotify_fh *fh2) { if (fh1->type != fh2->type || fh1->len != fh2->len) return false; @@ -42,6 +42,17 @@ static bool fanotify_fh_equal(struct fanotify_fh *fh1, !memcmp(fanotify_fh_buf(fh1), fanotify_fh_buf(fh2), fh1->len); } +static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1, + struct fanotify_fid_event *ffe2) +{ + /* Do not merge fid events without object fh */ + if (!ffe1->object_fh.len) + return false; + + return fanotify_fsid_equal(&ffe1->fsid, &ffe2->fsid) && + fanotify_fh_equal(&ffe1->object_fh, &ffe2->object_fh); +} + static bool should_merge(struct fsnotify_event *old_fsn, struct fsnotify_event *new_fsn) { @@ -51,14 +62,15 @@ static bool should_merge(struct fsnotify_event *old_fsn, old = FANOTIFY_E(old_fsn); new = FANOTIFY_E(new_fsn); - if (old_fsn->objectid != new_fsn->objectid || old->pid != new->pid || - old->fh.type != new->fh.type) + if (old_fsn->objectid != new_fsn->objectid || + old->type != new->type || old->pid != new->pid) return false; - if (fanotify_event_has_path(old)) { + switch (old->type) { + case FANOTIFY_EVENT_TYPE_PATH: return fanotify_path_equal(fanotify_event_path(old), fanotify_event_path(new)); - } else if (fanotify_event_has_fid(old)) { + case FANOTIFY_EVENT_TYPE_FID: /* * We want to merge many dirent events in the same dir (i.e. * creates/unlinks/renames), but we do not want to merge dirent @@ -70,11 +82,12 @@ static bool should_merge(struct fsnotify_event *old_fsn, if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR)) return false; - return fanotify_fsid_equal(&old->fsid, &new->fsid) && - fanotify_fh_equal(&old->fh, &new->fh); + return fanotify_fid_event_equal(FANOTIFY_FE(old), + FANOTIFY_FE(new)); + default: + WARN_ON_ONCE(1); } - /* Do not merge events if we failed to encode fid */ return false; } @@ -310,6 +323,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, __kernel_fsid_t *fsid) { struct fanotify_event *event = NULL; + struct fanotify_fid_event *ffe = NULL; gfp_t gfp = GFP_KERNEL_ACCOUNT; struct inode *id = fanotify_fid_inode(inode, mask, data, data_type); const struct path *path = fsnotify_data_path(data, data_type); @@ -334,14 +348,32 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp); if (!pevent) goto out; + event = &pevent->fae; + event->type = FANOTIFY_EVENT_TYPE_PATH_PERM; pevent->response = 0; pevent->state = FAN_EVENT_INIT; goto init; } - event = kmem_cache_alloc(fanotify_event_cachep, gfp); - if (!event) - goto out; + + if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { + ffe = kmem_cache_alloc(fanotify_fid_event_cachep, gfp); + if (!ffe) + goto out; + + event = &ffe->fae; + event->type = FANOTIFY_EVENT_TYPE_FID; + } else { + struct fanotify_path_event *pevent; + + pevent = kmem_cache_alloc(fanotify_path_event_cachep, gfp); + if (!pevent) + goto out; + + event = &pevent->fae; + event->type = FANOTIFY_EVENT_TYPE_PATH; + } + init: __maybe_unused /* * Use the victim inode instead of the watching inode as the id for @@ -354,19 +386,23 @@ init: __maybe_unused event->pid = get_pid(task_pid(current)); else event->pid = get_pid(task_tgid(current)); - event->fh.len = 0; - if (id && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { - event->fsid = *fsid; + + if (fanotify_event_has_fid(event)) { + ffe->object_fh.len = 0; + if (fsid) + ffe->fsid = *fsid; if (id) - fanotify_encode_fh(&event->fh, id, gfp); - } else if (path) { - event->fh.type = FILEID_ROOT; - event->path = *path; - path_get(path); - } else { - event->fh.type = FILEID_INVALID; - event->path.mnt = NULL; - event->path.dentry = NULL; + fanotify_encode_fh(&ffe->object_fh, id, gfp); + } else if (fanotify_event_has_path(event)) { + struct path *p = fanotify_event_path(event); + + if (path) { + *p = *path; + path_get(path); + } else { + p->mnt = NULL; + p->dentry = NULL; + } } out: memalloc_unuse_memcg(); @@ -486,7 +522,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, ret = 0; } else if (fanotify_is_perm_event(mask)) { - ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event), + ret = fanotify_get_response(group, FANOTIFY_PERM(event), iter_info); } finish: @@ -505,22 +541,46 @@ static void fanotify_free_group_priv(struct fsnotify_group *group) free_uid(user); } +static void fanotify_free_path_event(struct fanotify_event *event) +{ + path_put(fanotify_event_path(event)); + kmem_cache_free(fanotify_path_event_cachep, FANOTIFY_PE(event)); +} + +static void fanotify_free_perm_event(struct fanotify_event *event) +{ + path_put(fanotify_event_path(event)); + kmem_cache_free(fanotify_perm_event_cachep, FANOTIFY_PERM(event)); +} + +static void fanotify_free_fid_event(struct fanotify_event *event) +{ + struct fanotify_fid_event *ffe = FANOTIFY_FE(event); + + if (fanotify_fh_has_ext_buf(&ffe->object_fh)) + kfree(fanotify_fh_ext_buf(&ffe->object_fh)); + kmem_cache_free(fanotify_fid_event_cachep, ffe); +} + static void fanotify_free_event(struct fsnotify_event *fsn_event) { struct fanotify_event *event; event = FANOTIFY_E(fsn_event); - if (fanotify_event_has_path(event)) - path_put(&event->path); - else if (fanotify_fh_has_ext_buf(&event->fh)) - kfree(fanotify_fh_ext_buf(&event->fh)); put_pid(event->pid); - if (fanotify_is_perm_event(event->mask)) { - kmem_cache_free(fanotify_perm_event_cachep, - FANOTIFY_PE(fsn_event)); - return; + switch (event->type) { + case FANOTIFY_EVENT_TYPE_PATH: + fanotify_free_path_event(event); + break; + case FANOTIFY_EVENT_TYPE_PATH_PERM: + fanotify_free_perm_event(event); + break; + case FANOTIFY_EVENT_TYPE_FID: + fanotify_free_fid_event(event); + break; + default: + WARN_ON_ONCE(1); } - kmem_cache_free(fanotify_event_cachep, event); } static void fanotify_free_mark(struct fsnotify_mark *fsn_mark) diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index f9da4481613d..3b50ee44a0cd 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -5,7 +5,8 @@ #include extern struct kmem_cache *fanotify_mark_cache; -extern struct kmem_cache *fanotify_event_cachep; +extern struct kmem_cache *fanotify_fid_event_cachep; +extern struct kmem_cache *fanotify_path_event_cachep; extern struct kmem_cache *fanotify_perm_event_cachep; /* Possible states of the permission event */ @@ -52,43 +53,45 @@ static inline void *fanotify_fh_buf(struct fanotify_fh *fh) } /* - * Structure for normal fanotify events. It gets allocated in + * Common structure for fanotify events. Concrete structs are allocated in * fanotify_handle_event() and freed when the information is retrieved by - * userspace + * userspace. The type of event determines how it was allocated, how it will + * be freed and which concrete struct it may be cast to. */ +enum fanotify_event_type { + FANOTIFY_EVENT_TYPE_FID, + FANOTIFY_EVENT_TYPE_PATH, + FANOTIFY_EVENT_TYPE_PATH_PERM, +}; + struct fanotify_event { struct fsnotify_event fse; u32 mask; - /* - * With FAN_REPORT_FID, we do not hold any reference on the - * victim object. Instead we store its NFS file handle and its - * filesystem's fsid as a unique identifier. - */ - __kernel_fsid_t fsid; - struct fanotify_fh fh; - /* - * We hold ref to this path so it may be dereferenced at any - * point during this object's lifetime - */ - struct path path; + enum fanotify_event_type type; struct pid *pid; }; -static inline bool fanotify_event_has_path(struct fanotify_event *event) +struct fanotify_fid_event { + struct fanotify_event fae; + __kernel_fsid_t fsid; + struct fanotify_fh object_fh; +}; + +static inline struct fanotify_fid_event * +FANOTIFY_FE(struct fanotify_event *event) { - return event->fh.type == FILEID_ROOT; + return container_of(event, struct fanotify_fid_event, fae); } static inline bool fanotify_event_has_fid(struct fanotify_event *event) { - return event->fh.type != FILEID_ROOT && - event->fh.type != FILEID_INVALID; + return event->type == FANOTIFY_EVENT_TYPE_FID; } static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) { - if (fanotify_event_has_fid(event)) - return &event->fsid; + if (event->type == FANOTIFY_EVENT_TYPE_FID) + return &FANOTIFY_FE(event)->fsid; else return NULL; } @@ -96,8 +99,8 @@ static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) static inline struct fanotify_fh *fanotify_event_object_fh( struct fanotify_event *event) { - if (fanotify_event_has_fid(event)) - return &event->fh; + if (event->type == FANOTIFY_EVENT_TYPE_FID) + return &FANOTIFY_FE(event)->object_fh; else return NULL; } @@ -109,6 +112,17 @@ static inline int fanotify_event_object_fh_len(struct fanotify_event *event) return fh ? fh->len : 0; } +struct fanotify_path_event { + struct fanotify_event fae; + struct path path; +}; + +static inline struct fanotify_path_event * +FANOTIFY_PE(struct fanotify_event *event) +{ + return container_of(event, struct fanotify_path_event, fae); +} + /* * Structure for permission fanotify events. It gets allocated and freed in * fanotify_handle_event() since we wait there for user response. When the @@ -118,15 +132,16 @@ static inline int fanotify_event_object_fh_len(struct fanotify_event *event) */ struct fanotify_perm_event { struct fanotify_event fae; + struct path path; unsigned short response; /* userspace answer to the event */ unsigned short state; /* state of the event */ int fd; /* fd we passed to userspace for this event */ }; static inline struct fanotify_perm_event * -FANOTIFY_PE(struct fsnotify_event *fse) +FANOTIFY_PERM(struct fanotify_event *event) { - return container_of(fse, struct fanotify_perm_event, fae.fse); + return container_of(event, struct fanotify_perm_event, fae); } static inline bool fanotify_is_perm_event(u32 mask) @@ -140,10 +155,18 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse) return container_of(fse, struct fanotify_event, fse); } +static inline bool fanotify_event_has_path(struct fanotify_event *event) +{ + return event->type == FANOTIFY_EVENT_TYPE_PATH || + event->type == FANOTIFY_EVENT_TYPE_PATH_PERM; +} + static inline struct path *fanotify_event_path(struct fanotify_event *event) { - if (fanotify_event_has_path(event)) - return &event->path; + if (event->type == FANOTIFY_EVENT_TYPE_PATH) + return &FANOTIFY_PE(event)->path; + else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM) + return &FANOTIFY_PERM(event)->path; else return NULL; } diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 0b3b74fa3a27..6cb94a6bc980 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -46,7 +46,8 @@ extern const struct fsnotify_ops fanotify_fsnotify_ops; struct kmem_cache *fanotify_mark_cache __read_mostly; -struct kmem_cache *fanotify_event_cachep __read_mostly; +struct kmem_cache *fanotify_fid_event_cachep __read_mostly; +struct kmem_cache *fanotify_path_event_cachep __read_mostly; struct kmem_cache *fanotify_perm_event_cachep __read_mostly; #define FANOTIFY_EVENT_ALIGN 4 @@ -64,16 +65,16 @@ static int fanotify_event_info_len(struct fanotify_event *event) } /* - * Get an fsnotify notification event if one exists and is small + * Get an fanotify notification event if one exists and is small * enough to fit in "count". Return an error pointer if the count * is not large enough. When permission event is dequeued, its state is * updated accordingly. */ -static struct fsnotify_event *get_one_event(struct fsnotify_group *group, +static struct fanotify_event *get_one_event(struct fsnotify_group *group, size_t count) { size_t event_size = FAN_EVENT_METADATA_LEN; - struct fsnotify_event *fsn_event = NULL; + struct fanotify_event *event = NULL; pr_debug("%s: group=%p count=%zd\n", __func__, group, count); @@ -87,15 +88,15 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, } if (event_size > count) { - fsn_event = ERR_PTR(-EINVAL); + event = ERR_PTR(-EINVAL); goto out; } - fsn_event = fsnotify_remove_first_event(group); - if (fanotify_is_perm_event(FANOTIFY_E(fsn_event)->mask)) - FANOTIFY_PE(fsn_event)->state = FAN_EVENT_REPORTED; + event = FANOTIFY_E(fsnotify_remove_first_event(group)); + if (fanotify_is_perm_event(event->mask)) + FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; out: spin_unlock(&group->notification_lock); - return fsn_event; + return event; } static int create_fd(struct fsnotify_group *group, struct path *path, @@ -252,19 +253,16 @@ static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) } static ssize_t copy_event_to_user(struct fsnotify_group *group, - struct fsnotify_event *fsn_event, + struct fanotify_event *event, char __user *buf, size_t count) { struct fanotify_event_metadata metadata; - struct fanotify_event *event; - struct path *path; + struct path *path = fanotify_event_path(event); struct file *f = NULL; int ret, fd = FAN_NOFD; - pr_debug("%s: group=%p event=%p\n", __func__, group, fsn_event); + pr_debug("%s: group=%p event=%p\n", __func__, group, event); - event = container_of(fsn_event, struct fanotify_event, fse); - path = fanotify_event_path(event); metadata.event_len = FAN_EVENT_METADATA_LEN; metadata.metadata_len = FAN_EVENT_METADATA_LEN; metadata.vers = FANOTIFY_METADATA_VERSION; @@ -293,9 +291,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, goto out_close_fd; if (fanotify_is_perm_event(event->mask)) - FANOTIFY_PE(fsn_event)->fd = fd; + FANOTIFY_PERM(event)->fd = fd; - if (fanotify_event_has_path(event)) { + if (f) { fd_install(fd, f); } else if (fanotify_event_has_fid(event)) { ret = copy_fid_to_user(event, buf + FAN_EVENT_METADATA_LEN); @@ -332,7 +330,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct fsnotify_group *group; - struct fsnotify_event *kevent; + struct fanotify_event *event; char __user *start; int ret; DEFINE_WAIT_FUNC(wait, woken_wake_function); @@ -344,13 +342,13 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, add_wait_queue(&group->notification_waitq, &wait); while (1) { - kevent = get_one_event(group, count); - if (IS_ERR(kevent)) { - ret = PTR_ERR(kevent); + event = get_one_event(group, count); + if (IS_ERR(event)) { + ret = PTR_ERR(event); break; } - if (!kevent) { + if (!event) { ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) break; @@ -366,7 +364,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, continue; } - ret = copy_event_to_user(group, kevent, buf, count); + ret = copy_event_to_user(group, event, buf, count); if (unlikely(ret == -EOPENSTALE)) { /* * We cannot report events with stale fd so drop it. @@ -381,17 +379,17 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, * Permission events get queued to wait for response. Other * events can be destroyed now. */ - if (!fanotify_is_perm_event(FANOTIFY_E(kevent)->mask)) { - fsnotify_destroy_event(group, kevent); + if (!fanotify_is_perm_event(event->mask)) { + fsnotify_destroy_event(group, &event->fse); } else { if (ret <= 0) { spin_lock(&group->notification_lock); finish_permission_event(group, - FANOTIFY_PE(kevent), FAN_DENY); + FANOTIFY_PERM(event), FAN_DENY); wake_up(&group->fanotify_data.access_waitq); } else { spin_lock(&group->notification_lock); - list_add_tail(&kevent->list, + list_add_tail(&event->fse.list, &group->fanotify_data.access_list); spin_unlock(&group->notification_lock); } @@ -437,8 +435,6 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t static int fanotify_release(struct inode *ignored, struct file *file) { struct fsnotify_group *group = file->private_data; - struct fanotify_perm_event *event; - struct fsnotify_event *fsn_event; /* * Stop new events from arriving in the notification queue. since @@ -453,6 +449,8 @@ static int fanotify_release(struct inode *ignored, struct file *file) */ spin_lock(&group->notification_lock); while (!list_empty(&group->fanotify_data.access_list)) { + struct fanotify_perm_event *event; + event = list_first_entry(&group->fanotify_data.access_list, struct fanotify_perm_event, fae.fse.list); list_del_init(&event->fae.fse.list); @@ -466,12 +464,14 @@ static int fanotify_release(struct inode *ignored, struct file *file) * response is consumed and fanotify_get_response() returns. */ while (!fsnotify_notify_queue_is_empty(group)) { - fsn_event = fsnotify_remove_first_event(group); - if (!(FANOTIFY_E(fsn_event)->mask & FANOTIFY_PERM_EVENTS)) { + struct fanotify_event *event; + + event = FANOTIFY_E(fsnotify_remove_first_event(group)); + if (!(event->mask & FANOTIFY_PERM_EVENTS)) { spin_unlock(&group->notification_lock); - fsnotify_destroy_event(group, fsn_event); + fsnotify_destroy_event(group, &event->fse); } else { - finish_permission_event(group, FANOTIFY_PE(fsn_event), + finish_permission_event(group, FANOTIFY_PERM(event), FAN_ALLOW); } spin_lock(&group->notification_lock); @@ -1136,7 +1136,10 @@ static int __init fanotify_user_setup(void) fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); - fanotify_event_cachep = KMEM_CACHE(fanotify_event, SLAB_PANIC); + fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event, + SLAB_PANIC); + fanotify_path_event_cachep = KMEM_CACHE(fanotify_path_event, + SLAB_PANIC); if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) { fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event, SLAB_PANIC); From 9e2ba2c34f1922ca1e0c7d31b30ace5842c2e7d1 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:19 +0200 Subject: [PATCH 577/809] fanotify: send FAN_DIR_MODIFY event flavor with dir inode and name Dirent events are going to be supported in two flavors: 1. Directory fid info + mask that includes the specific event types (e.g. FAN_CREATE) and an optional FAN_ONDIR flag. 2. Directory fid info + name + mask that includes only FAN_DIR_MODIFY. To request the second event flavor, user needs to set the event type FAN_DIR_MODIFY in the mark mask. The first flavor is supported since kernel v5.1 for groups initialized with flag FAN_REPORT_FID. It is intended to be used for watching directories in "batch mode" - the watcher is notified when directory is changed and re-scans the directory content in response. This event flavor is stored more compactly in the event queue, so it is optimal for workloads with frequent directory changes. The second event flavor is intended to be used for watching large directories, where the cost of re-scan of the directory on every change is considered too high. The watcher getting the event with the directory fid and entry name is expected to call fstatat(2) to query the content of the entry after the change. Legacy inotify events are reported with name and event mask (e.g. "foo", FAN_CREATE | FAN_ONDIR). That can lead users to the conclusion that there is *currently* an entry "foo" that is a sub-directory, when in fact "foo" may be negative or non-dir by the time user gets the event. To make it clear that the current state of the named entry is unknown, when reporting an event with name info, fanotify obfuscates the specific event types (e.g. create,delete,rename) and uses a common event type - FAN_DIR_MODIFY to describe the change. This should make it harder for users to make wrong assumptions and write buggy filesystem monitors. At this point, name info reporting is not yet implemented, so trying to set FAN_DIR_MODIFY in mark mask will return -EINVAL. Link: https://lore.kernel.org/r/20200319151022.31456-12-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 7 ++++--- fs/notify/fsnotify.c | 2 +- include/linux/fsnotify.h | 6 ++++++ include/linux/fsnotify_backend.h | 4 +++- include/uapi/linux/fanotify.h | 1 + 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 39eb71f7c413..74676228f784 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -235,9 +235,9 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, test_mask = event_mask & marks_mask & ~marks_ignored_mask; /* - * dirent modification events (create/delete/move) do not carry the - * child entry name/inode information. Instead, we report FAN_ONDIR - * for mkdir/rmdir so user can differentiate them from creat/unlink. + * For dirent modification events (create/delete/move) that do not carry + * the child entry name information, we report FAN_ONDIR for mkdir/rmdir + * so user can differentiate them from creat/unlink. * * For backward compatibility and consistency, do not report FAN_ONDIR * to user in legacy fanotify mode (reporting fd) and report FAN_ONDIR @@ -463,6 +463,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, BUILD_BUG_ON(FAN_MOVED_FROM != FS_MOVED_FROM); BUILD_BUG_ON(FAN_CREATE != FS_CREATE); BUILD_BUG_ON(FAN_DELETE != FS_DELETE); + BUILD_BUG_ON(FAN_DIR_MODIFY != FS_DIR_MODIFY); BUILD_BUG_ON(FAN_DELETE_SELF != FS_DELETE_SELF); BUILD_BUG_ON(FAN_MOVE_SELF != FS_MOVE_SELF); BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 193530f57963..72d332ce8e12 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -383,7 +383,7 @@ static __init int fsnotify_init(void) { int ret; - BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25); + BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26); ret = init_srcu_struct(&fsnotify_mark_srcu); if (ret) diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 860018f3e545..5ab28f6c7d26 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -30,6 +30,12 @@ static inline void fsnotify_name(struct inode *dir, __u32 mask, const struct qstr *name, u32 cookie) { fsnotify(dir, mask, child, FSNOTIFY_EVENT_INODE, name, cookie); + /* + * Send another flavor of the event without child inode data and + * without the specific event type (e.g. FS_CREATE|FS_IS_DIR). + * The name is relative to the dir inode the event is reported to. + */ + fsnotify(dir, FS_DIR_MODIFY, dir, FSNOTIFY_EVENT_INODE, name, 0); } static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index c72cbea20ef7..f0c506405b54 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -47,6 +47,7 @@ #define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */ #define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ #define FS_OPEN_EXEC_PERM 0x00040000 /* open/exec event in a permission hook */ +#define FS_DIR_MODIFY 0x00080000 /* Directory entry was modified */ #define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ /* This inode cares about things that happen to its children. Always set for @@ -66,7 +67,8 @@ * The watching parent may get an FS_ATTRIB|FS_EVENT_ON_CHILD event * when a directory entry inside a child subdir changes. */ -#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE) +#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | \ + FS_DIR_MODIFY) #define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \ FS_OPEN_EXEC_PERM) diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index 2a1844edda47..615fa2c87179 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -24,6 +24,7 @@ #define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ #define FAN_OPEN_EXEC_PERM 0x00040000 /* File open/exec in perm check */ +#define FAN_DIR_MODIFY 0x00080000 /* Directory entry was modified */ #define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */ From d766b553615ce67f33848ec4f6672b3158198a5c Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:20 +0200 Subject: [PATCH 578/809] fanotify: prepare to report both parent and child fid's For some events, we are going to report both child and parent fid's, so pass fsid and file handle as arguments to copy_fid_to_user(), which is going to be called with parent and child file handles. Link: https://lore.kernel.org/r/20200319151022.31456-13-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify_user.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 6cb94a6bc980..3a11f6a0339f 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -52,6 +52,13 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; #define FANOTIFY_EVENT_ALIGN 4 +static int fanotify_fid_info_len(int fh_len) +{ + return roundup(sizeof(struct fanotify_event_info_fid) + + sizeof(struct file_handle) + fh_len, + FANOTIFY_EVENT_ALIGN); +} + static int fanotify_event_info_len(struct fanotify_event *event) { int fh_len = fanotify_event_object_fh_len(event); @@ -59,9 +66,7 @@ static int fanotify_event_info_len(struct fanotify_event *event) if (!fh_len) return 0; - return roundup(sizeof(struct fanotify_event_info_fid) + - sizeof(struct file_handle) + fh_len, - FANOTIFY_EVENT_ALIGN); + return fanotify_fid_info_len(fh_len); } /* @@ -199,14 +204,14 @@ static int process_access_response(struct fsnotify_group *group, return -ENOENT; } -static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) +static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + char __user *buf) { struct fanotify_event_info_fid info = { }; struct file_handle handle = { }; unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; - struct fanotify_fh *fh = fanotify_event_object_fh(event); size_t fh_len = fh->len; - size_t len = fanotify_event_info_len(event); + size_t len = fanotify_fid_info_len(fh_len); if (!len) return 0; @@ -217,7 +222,7 @@ static int copy_fid_to_user(struct fanotify_event *event, char __user *buf) /* Copy event info fid header followed by vaiable sized file handle */ info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID; info.hdr.len = len; - info.fsid = *fanotify_event_fsid(event); + info.fsid = *fsid; if (copy_to_user(buf, &info, sizeof(info))) return -EFAULT; @@ -296,7 +301,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, if (f) { fd_install(fd, f); } else if (fanotify_event_has_fid(event)) { - ret = copy_fid_to_user(event, buf + FAN_EVENT_METADATA_LEN); + ret = copy_fid_to_user(fanotify_event_fsid(event), + fanotify_event_object_fh(event), + buf + FAN_EVENT_METADATA_LEN); if (ret < 0) return ret; } From 01affd5471dcab04c6cb0c2acaf132a20488f86f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Mar 2020 19:35:07 +0100 Subject: [PATCH 579/809] fanotify: Drop fanotify_event_has_fid() When some events have directory id and some object id, fanotify_event_has_fid() becomes mostly useless and confusing because we usually need to know which type of file handle the event has. So just drop the function and use fanotify_event_object_fh() instead. Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 2 +- fs/notify/fanotify/fanotify.h | 5 ----- fs/notify/fanotify/fanotify_user.c | 4 ++-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 74676228f784..ef39664e389c 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -387,7 +387,7 @@ init: __maybe_unused else event->pid = get_pid(task_tgid(current)); - if (fanotify_event_has_fid(event)) { + if (fanotify_event_object_fh(event)) { ffe->object_fh.len = 0; if (fsid) ffe->fsid = *fsid; diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 3b50ee44a0cd..eecf4be3bfd1 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -83,11 +83,6 @@ FANOTIFY_FE(struct fanotify_event *event) return container_of(event, struct fanotify_fid_event, fae); } -static inline bool fanotify_event_has_fid(struct fanotify_event *event) -{ - return event->type == FANOTIFY_EVENT_TYPE_FID; -} - static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) { if (event->type == FANOTIFY_EVENT_TYPE_FID) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 3a11f6a0339f..b93585406aad 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -275,7 +275,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; metadata.pid = pid_vnr(event->pid); - if (fanotify_event_has_fid(event)) { + if (fanotify_event_object_fh(event)) { metadata.event_len += fanotify_event_info_len(event); } else if (path && path->mnt && path->dentry) { fd = create_fd(group, path, &f); @@ -300,7 +300,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, if (f) { fd_install(fd, f); - } else if (fanotify_event_has_fid(event)) { + } else if (fanotify_event_object_fh(event)) { ret = copy_fid_to_user(fanotify_event_fsid(event), fanotify_event_object_fh(event), buf + FAN_EVENT_METADATA_LEN); From 7074695ac6fb965d478f373b95bc5c636e9f21b0 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 24 Mar 2020 15:29:12 -0300 Subject: [PATCH 580/809] powerpc/prom_init: Remove leftover comment The if statement that this comment referred to was removed in commit 11fdb309341c ("powerpc/prom_init: Remove support for OPAL v2"). Signed-off-by: Fabiano Rosas Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200324182912.1048906-1-farosas@linux.ibm.com --- arch/powerpc/kernel/prom_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 673f13b87db1..806be751c336 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -3477,7 +3477,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ hdr = dt_header_start; - /* Don't print anything after quiesce under OPAL, it crashes OFW */ prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase); prom_debug("->dt_header_start=0x%lx\n", hdr); From 6c7c851f1b666a8a455678a0b480b9162de86052 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 3 Mar 2020 16:42:01 +0100 Subject: [PATCH 581/809] s390/diag: fix display of diagnose call statistics Show the full diag statistic table and not just parts of it. The issue surfaced in a KVM guest with a number of vcpus defined smaller than NR_DIAG_STAT. Fixes: 1ec2772e0c3c ("s390/diag: add a statistic for diagnose calls") Cc: stable@vger.kernel.org Signed-off-by: Michael Mueller Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/diag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index e9dac9a24d3f..61f2b0412345 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -84,7 +84,7 @@ static int show_diag_stat(struct seq_file *m, void *v) static void *show_diag_stat_start(struct seq_file *m, loff_t *pos) { - return *pos <= nr_cpu_ids ? (void *)((unsigned long) *pos + 1) : NULL; + return *pos <= NR_DIAG_STAT ? (void *)((unsigned long) *pos + 1) : NULL; } static void *show_diag_stat_next(struct seq_file *m, void *v, loff_t *pos) From 4141b6a5e9f171325effc36a22eb92bf961e7a5c Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 23 Mar 2020 11:09:07 +0100 Subject: [PATCH 582/809] s390/cpum_sf: Fix wrong page count in error message When perf record -e SF_CYCLES_BASIC_DIAG runs with very high frequency, the samples arrive faster than the perf process can save them to file. Eventually, for longer running processes, this leads to the siutation where the trace buffers allocated by perf slowly fills up. At one point the auxiliary trace buffer is full and the CPU Measurement sampling facility is turned off. Furthermore a warning is printed to the kernel log buffer: cpum_sf: The AUX buffer with 0 pages for the diagnostic-sampling mode is full The number of allocated pages for the auxiliary trace buffer is shown as zero pages. That is wrong. Fix this by saving the number of allocated pages before entering the work loop in the interrupt handler. When the interrupt handler processes the samples, it may detect the buffer full condition and stop sampling, reducing the buffer size to zero. Print the correct value in the error message: cpum_sf: The AUX buffer with 256 pages for the diagnostic-sampling mode is full Signed-off-by: Thomas Richter Signed-off-by: Vasily Gorbik --- arch/s390/kernel/perf_cpum_sf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index cf2020b8db44..85a711d783eb 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -1578,6 +1578,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) unsigned long range = 0, size; unsigned long long overflow = 0; struct perf_output_handle *handle = &cpuhw->handle; + unsigned long num_sdb; aux = perf_get_aux(handle); if (WARN_ON_ONCE(!aux)) @@ -1589,13 +1590,14 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) size >> PAGE_SHIFT); perf_aux_output_end(handle, size); + num_sdb = aux->sfb.num_sdb; while (!done) { /* Get an output handle */ aux = perf_aux_output_begin(handle, cpuhw->event); if (handle->size == 0) { pr_err("The AUX buffer with %lu pages for the " "diagnostic-sampling mode is full\n", - aux->sfb.num_sdb); + num_sdb); debug_sprintf_event(sfdbg, 1, "%s: AUX buffer used up\n", __func__); From 2c7749b90536b76795eab4cada028c2ddad25fc3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Mar 2020 13:47:30 -0700 Subject: [PATCH 583/809] s390: use fallthrough; Convert the various uses of fallthrough comments to fallthrough; Done via script Link: https://lore.kernel.org/lkml/b56602fcf79f849e733e7b521bb0e17895d390fa.1582230379.git.joe.com/ Signed-off-by: Joe Perches Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/signal.c | 4 ++-- arch/s390/kernel/topology.c | 2 +- arch/s390/mm/fault.c | 11 +++++------ arch/s390/mm/pgalloc.c | 2 +- drivers/s390/char/con3215.c | 2 +- drivers/s390/char/hmcdrv_ftp.c | 2 +- drivers/s390/char/sclp_sdias.c | 2 +- drivers/s390/char/tape_core.c | 6 +++--- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index e6fca5498e1f..b295090e2ce6 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -487,7 +487,7 @@ void do_signal(struct pt_regs *regs) regs->gprs[2] = -EINTR; break; } - /* fallthrough */ + fallthrough; case -ERESTARTNOINTR: regs->gprs[2] = regs->orig_gpr2; regs->psw.addr = @@ -514,7 +514,7 @@ void do_signal(struct pt_regs *regs) case -ERESTART_RESTARTBLOCK: /* Restart with sys_restart_syscall */ regs->int_code = __NR_restart_syscall; - /* fallthrough */ + fallthrough; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index d03edebce754..5f70cefc13e4 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -83,7 +83,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_copy(&mask, cpu_present_mask); break; default: - /* fallthrough */ + fallthrough; case TOPOLOGY_MODE_SINGLE: cpumask_copy(&mask, cpumask_of(cpu)); break; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 151adef0d5dd..15c6c811d254 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -122,7 +122,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) if (*table & _REGION_ENTRY_INVALID) goto out; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ + fallthrough; case _ASCE_TYPE_REGION2: table += (address & _REGION2_INDEX) >> _REGION2_SHIFT; if (bad_address(table)) @@ -131,7 +131,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) if (*table & _REGION_ENTRY_INVALID) goto out; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ + fallthrough; case _ASCE_TYPE_REGION3: table += (address & _REGION3_INDEX) >> _REGION3_SHIFT; if (bad_address(table)) @@ -140,7 +140,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) if (*table & (_REGION_ENTRY_INVALID | _REGION3_ENTRY_LARGE)) goto out; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ + fallthrough; case _ASCE_TYPE_SEGMENT: table += (address & _SEGMENT_INDEX) >> _SEGMENT_SHIFT; if (bad_address(table)) @@ -327,7 +327,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int access, case VM_FAULT_BADACCESS: if (access == VM_EXEC && signal_return(regs) == 0) break; - /* fallthrough */ + fallthrough; case VM_FAULT_BADMAP: /* Bad memory access. Check if it is kernel or user space. */ if (user_mode(regs)) { @@ -337,9 +337,8 @@ static noinline void do_fault_error(struct pt_regs *regs, int access, do_sigsegv(regs, si_code); break; } - /* fallthrough */ + fallthrough; case VM_FAULT_BADCONTEXT: - /* fallthrough */ case VM_FAULT_PFAULT: do_no_context(regs); break; diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index d3be3fe2c55d..af3bddd5e568 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -326,7 +326,7 @@ void __tlb_remove_table(void *_table) mask >>= 24; if (mask != 0) break; - /* fallthrough */ + fallthrough; case 3: /* 4K page table with pgstes */ if (mask & 3) atomic_xor_bits(&page->_refcount, 3 << 24); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index e7cf0a1d4f71..92757f9bd010 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -398,7 +398,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, } if (dstat == 0x08) break; - /* else, fall through */ + fallthrough; case 0x04: /* Device end interrupt. */ if ((raw = req->info) == NULL) diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c index 0e70397d6e04..37ee8f698c3b 100644 --- a/drivers/s390/char/hmcdrv_ftp.c +++ b/drivers/s390/char/hmcdrv_ftp.c @@ -137,7 +137,7 @@ static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp) while ((*cmd != '\0') && !iscntrl(*cmd)) ++cmd; ftp->fname = start; - /* fall through */ + fallthrough; default: *cmd = '\0'; break; diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 13f97fd73aca..644b61013679 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c @@ -214,7 +214,7 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) break; case SDIAS_EVSTATE_NO_DATA: TRACE("no data\n"); - /* fall through */ + fallthrough; default: pr_err("Error from SCLP while copying hsa. Event status = %x\n", sdias_evbuf.event_status); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 3e0b2f63a9d2..380e6a67719c 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -677,7 +677,7 @@ tape_generic_remove(struct ccw_device *cdev) switch (device->tape_state) { case TS_INIT: tape_state_set(device, TS_NOT_OPER); - /* fallthrough */ + fallthrough; case TS_NOT_OPER: /* * Nothing to do. @@ -950,7 +950,7 @@ __tape_start_request(struct tape_device *device, struct tape_request *request) break; if (device->tape_state == TS_UNUSED) break; - /* fallthrough */ + fallthrough; default: if (device->tape_state == TS_BLKUSE) break; @@ -1118,7 +1118,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) case -ETIMEDOUT: DBF_LH(1, "(%08x): Request timed out\n", device->cdev_id); - /* fallthrough */ + fallthrough; case -EIO: __tape_end_request(device, request, -EIO); break; From fcf0220abc5b65d12ff48ba9870cf3d90801b075 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Mar 2020 13:39:51 -0700 Subject: [PATCH 584/809] s390/zcrypt: use fallthrough; Convert the various uses of fallthrough comments to fallthrough; Done via script Link: https://lore.kernel.org/lkml/b56602fcf79f849e733e7b521bb0e17895d390fa.1582230379.git.joe.com/ Signed-off-by: Joe Perches Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.c | 2 +- drivers/s390/crypto/ap_queue.c | 8 ++++---- drivers/s390/crypto/zcrypt_msgtype6.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 0246bb35790f..c413211c6116 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -360,7 +360,7 @@ void ap_wait(enum ap_wait wait) wake_up(&ap_poll_wait); break; } - /* Fall through */ + fallthrough; case AP_WAIT_TIMEOUT: spin_lock_bh(&ap_poll_timer_lock); if (!hrtimer_is_queued(&ap_poll_timer)) { diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 39c0b246c69a..9cb997cffa61 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -152,7 +152,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) ap_msg->receive(aq, ap_msg, aq->reply); break; } - /* fall through */ + fallthrough; case AP_RESPONSE_NO_PENDING_REPLY: if (!status.queue_empty || aq->queue_count <= 0) break; @@ -219,7 +219,7 @@ static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq) case AP_RESPONSE_NORMAL: if (aq->queue_count > 0) return AP_WAIT_AGAIN; - /* fall through */ + fallthrough; default: return AP_WAIT_NONE; } @@ -254,7 +254,7 @@ static enum ap_wait ap_sm_write(struct ap_queue *aq) aq->state = AP_STATE_WORKING; return AP_WAIT_AGAIN; } - /* fall through */ + fallthrough; case AP_RESPONSE_Q_FULL: aq->state = AP_STATE_QUEUE_FULL; return AP_WAIT_INTERRUPT; @@ -380,7 +380,7 @@ static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq) case AP_RESPONSE_NORMAL: if (aq->queue_count > 0) return AP_WAIT_AGAIN; - /* fallthrough */ + fallthrough; case AP_RESPONSE_NO_PENDING_REPLY: return AP_WAIT_TIMEOUT; default: diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index eadd3a438a4b..fd1cbb2d6b3f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -801,7 +801,7 @@ static int convert_response_ica(struct zcrypt_queue *zq, if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_ica(zq, reply, outputdata, outputdatalength); - /* fall through - wrong cprb version is an unknown response */ + fallthrough; /* wrong cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -834,7 +834,7 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, } if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_xcrb(zq, reply, xcRB); - /* fall through - wrong cprb version is an unknown response */ + fallthrough; /* wrong cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ zq->online = 0; @@ -864,7 +864,7 @@ static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, return convert_error(zq, reply); if (msg->cprbx.cprb_ver_id == 0x04) return convert_type86_ep11_xcrb(zq, reply, xcRB); - /* fall through - wrong cprb version is an unknown resp */ + fallthrough; /* wrong cprb version is an unknown resp */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -894,7 +894,7 @@ static int convert_response_rng(struct zcrypt_queue *zq, return -EINVAL; if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_rng(zq, reply, data); - /* fall through - wrong cprb version is an unknown response */ + fallthrough; /* wrong cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", From 0696178e7741c50e2634209276c344017e690bec Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Mar 2020 13:39:50 -0700 Subject: [PATCH 585/809] s390/vfio: use fallthrough; Convert the various uses of fallthrough comments to fallthrough; Done via script Link: https://lore.kernel.org/lkml/b56602fcf79f849e733e7b521bb0e17895d390fa.1582230379.git.joe.com/ Signed-off-by: Joe Perches Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/vfio_ap_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 5c0f53c6dde7..e0bde8518745 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -90,7 +90,7 @@ static void vfio_ap_wait_for_irqclear(int apqn) case AP_RESPONSE_RESET_IN_PROGRESS: if (!status.irq_enabled) return; - /* Fall through */ + fallthrough; case AP_RESPONSE_BUSY: msleep(20); break; From b09fcecb6c91113cd39e50ba32c5afc29bcb20c9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Mar 2020 13:39:50 -0700 Subject: [PATCH 586/809] s390/cio: use fallthrough; Convert the various uses of fallthrough comments to fallthrough; Done via script Link: https://lore.kernel.org/lkml/b56602fcf79f849e733e7b521bb0e17895d390fa.1582230379.git.joe.com/ Signed-off-by: Joe Perches Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/cio/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 0c6245fc7706..50007cb9be5b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1262,7 +1262,7 @@ static int recovery_check(struct device *dev, void *data) sch = to_subchannel(cdev->dev.parent); if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm) break; - /* fall through */ + fallthrough; case DEV_STATE_DISCONNECTED: CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", cdev->private->dev_id.ssid, @@ -2091,7 +2091,7 @@ static void ccw_device_todo(struct work_struct *work) case CDEV_TODO_UNREG_EVAL: if (!sch_is_pseudo_sch(sch)) css_schedule_eval(sch->schid); - /* fall-through */ + fallthrough; case CDEV_TODO_UNREG: if (sch_is_pseudo_sch(sch)) ccw_device_unregister(cdev); From 6952a4f646446fde9e190b62c5e45f84c6cf91aa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 8 Mar 2020 17:26:32 +0100 Subject: [PATCH 587/809] selftests: add pid namespace ENOMEM regression test We recently regressed (cf. [1] and its corresponding fix in [2]) returning ENOMEM when trying to create a process in a pid namespace whose init process/child subreaper has already died. This has caused confusion at least once before that (cf. [3]). Let's add a simple regression test to catch this in the future. [1]: 49cb2fc42ce4 ("fork: extend clone3() to support setting a PID") [2]: b26ebfe12f34 ("pid: Fix error return value in some cases") [3]: 35f71bc0a09a ("fork: report pid reservation failure properly") Cc: Corey Minyard Cc: Oleg Nesterov Cc: Adrian Reber Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Andrei Vagin Signed-off-by: Christian Brauner --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + .../selftests/pid_namespace/.gitignore | 1 + .../testing/selftests/pid_namespace/Makefile | 8 ++++ tools/testing/selftests/pid_namespace/config | 2 + .../pid_namespace/regression_enomem.c | 45 +++++++++++++++++++ tools/testing/selftests/pidfd/pidfd.h | 2 + 7 files changed, 60 insertions(+) create mode 100644 tools/testing/selftests/pid_namespace/.gitignore create mode 100644 tools/testing/selftests/pid_namespace/Makefile create mode 100644 tools/testing/selftests/pid_namespace/config create mode 100644 tools/testing/selftests/pid_namespace/regression_enomem.c diff --git a/MAINTAINERS b/MAINTAINERS index a6fbdf354d34..8cc9e6a7c1fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13158,6 +13158,7 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git F: samples/pidfd/ F: tools/testing/selftests/pidfd/ +F: tools/testing/selftests/pid_namespace/ F: tools/testing/selftests/clone3/ K: (?i)pidfd K: (?i)clone3 diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 6ec503912bea..5fc587b7136f 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -38,6 +38,7 @@ TARGETS += netfilter TARGETS += networking/timestamping TARGETS += nsfs TARGETS += pidfd +TARGETS += pid_namespace TARGETS += powerpc TARGETS += proc TARGETS += pstore diff --git a/tools/testing/selftests/pid_namespace/.gitignore b/tools/testing/selftests/pid_namespace/.gitignore new file mode 100644 index 000000000000..93ab9d7e5b7e --- /dev/null +++ b/tools/testing/selftests/pid_namespace/.gitignore @@ -0,0 +1 @@ +regression_enomem diff --git a/tools/testing/selftests/pid_namespace/Makefile b/tools/testing/selftests/pid_namespace/Makefile new file mode 100644 index 000000000000..dcaefa224ca0 --- /dev/null +++ b/tools/testing/selftests/pid_namespace/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +CFLAGS += -g -I../../../../usr/include/ + +TEST_GEN_PROGS := regression_enomem + +include ../lib.mk + +$(OUTPUT)/regression_enomem: regression_enomem.c ../pidfd/pidfd.h diff --git a/tools/testing/selftests/pid_namespace/config b/tools/testing/selftests/pid_namespace/config new file mode 100644 index 000000000000..26cdb27e7dbb --- /dev/null +++ b/tools/testing/selftests/pid_namespace/config @@ -0,0 +1,2 @@ +CONFIG_PID_NS=y +CONFIG_USER_NS=y diff --git a/tools/testing/selftests/pid_namespace/regression_enomem.c b/tools/testing/selftests/pid_namespace/regression_enomem.c new file mode 100644 index 000000000000..73d532556d17 --- /dev/null +++ b/tools/testing/selftests/pid_namespace/regression_enomem.c @@ -0,0 +1,45 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" +#include "../kselftest_harness.h" +#include "../pidfd/pidfd.h" + +/* + * Regression test for: + * 35f71bc0a09a ("fork: report pid reservation failure properly") + * b26ebfe12f34 ("pid: Fix error return value in some cases") + */ +TEST(regression_enomem) +{ + pid_t pid; + + if (geteuid()) + EXPECT_EQ(0, unshare(CLONE_NEWUSER)); + + EXPECT_EQ(0, unshare(CLONE_NEWPID)); + + pid = fork(); + ASSERT_GE(pid, 0); + + if (pid == 0) + exit(EXIT_SUCCESS); + + EXPECT_EQ(0, wait_for_pid(pid)); + + pid = fork(); + ASSERT_LT(pid, 0); + ASSERT_EQ(errno, ENOMEM); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h index d482515604db..c1921a53dbed 100644 --- a/tools/testing/selftests/pidfd/pidfd.h +++ b/tools/testing/selftests/pidfd/pidfd.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "../kselftest.h" From eadcaa3dfd706bbf46682c8b8b5979262443c3c3 Mon Sep 17 00:00:00 2001 From: Tony Jones Date: Wed, 25 Mar 2020 09:40:53 -0700 Subject: [PATCH 588/809] perf callchain: Update docs regarding kernel/user space unwinding The method of unwinding for kernel space is defined by the kernel config, not by the value of --call-graph. Improve the documentation to reflect this. Signed-off-by: Tony Jones Link: http://lore.kernel.org/lkml/20200325164053.10177-1-tonyj@suse.de Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-config.txt | 14 ++++++++------ tools/perf/Documentation/perf-record.txt | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 8ead55593984..f16d8a71d3f5 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -405,14 +405,16 @@ ui.*:: This option is only applied to TUI. call-graph.*:: - When sub-commands 'top' and 'report' work with -g/—-children - there're options in control of call-graph. + The following controls the handling of call-graphs (obtained via the + -g/--call-graph options). call-graph.record-mode:: - The record-mode can be 'fp' (frame pointer), 'dwarf' and 'lbr'. - The value of 'dwarf' is effective only if perf detect needed library - (libunwind or a recent version of libdw). - 'lbr' only work for cpus that support it. + The mode for user space can be 'fp' (frame pointer), 'dwarf' + and 'lbr'. The value 'dwarf' is effective only if libunwind + (or a recent version of libdw) is present on the system; + the value 'lbr' only works for certain cpus. The method for + kernel space is controlled not by this option but by the + kernel config (CONFIG_UNWINDER_*). call-graph.dump-size:: The size of stack to dump in order to do post-unwinding. Default is 8192 (byte). diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 7f4db7592467..b25e028458e2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -237,16 +237,22 @@ OPTIONS option and remains only for backward compatibility. See --event. -g:: - Enables call-graph (stack chain/backtrace) recording. + Enables call-graph (stack chain/backtrace) recording for both + kernel space and user space. --call-graph:: Setup and enable call-graph (stack chain/backtrace) recording, - implies -g. Default is "fp". + implies -g. Default is "fp" (for user space). - Allows specifying "fp" (frame pointer) or "dwarf" - (DWARF's CFI - Call Frame Information) or "lbr" - (Hardware Last Branch Record facility) as the method to collect - the information used to show the call graphs. + The unwinding method used for kernel space is dependent on the + unwinder used by the active kernel configuration, i.e + CONFIG_UNWINDER_FRAME_POINTER (fp) or CONFIG_UNWINDER_ORC (orc) + + Any option specified here controls the method used for user space. + + Valid options are "fp" (frame pointer), "dwarf" (DWARF's CFI - + Call Frame Information) or "lbr" (Hardware Last Branch Record + facility). In some systems, where binaries are build with gcc --fomit-frame-pointer, using the "fp" method will produce bogus From cacfb956d46edc5d7a1165161bfc6ca3de9519d9 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:21 +0200 Subject: [PATCH 589/809] fanotify: record name info for FAN_DIR_MODIFY event For FAN_DIR_MODIFY event, allocate a variable size event struct to store the dir entry name along side the directory file handle. At this point, name info reporting is not yet implemented, so trying to set FAN_DIR_MODIFY in mark mask will return -EINVAL. Link: https://lore.kernel.org/r/20200319151022.31456-14-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 76 ++++++++++++++++++++++++++---- fs/notify/fanotify/fanotify.h | 40 +++++++++++++++- fs/notify/fanotify/fanotify_user.c | 4 +- 3 files changed, 108 insertions(+), 12 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index ef39664e389c..599654564b2a 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -53,6 +53,23 @@ static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1, fanotify_fh_equal(&ffe1->object_fh, &ffe2->object_fh); } +static bool fanotify_name_event_equal(struct fanotify_name_event *fne1, + struct fanotify_name_event *fne2) +{ + /* + * Do not merge name events without dir fh. + * FAN_DIR_MODIFY does not encode object fh, so it may be empty. + */ + if (!fne1->dir_fh.len) + return false; + + if (fne1->name_len != fne2->name_len || + !fanotify_fh_equal(&fne1->dir_fh, &fne2->dir_fh)) + return false; + + return !memcmp(fne1->name, fne2->name, fne1->name_len); +} + static bool should_merge(struct fsnotify_event *old_fsn, struct fsnotify_event *new_fsn) { @@ -84,6 +101,9 @@ static bool should_merge(struct fsnotify_event *old_fsn, return fanotify_fid_event_equal(FANOTIFY_FE(old), FANOTIFY_FE(new)); + case FANOTIFY_EVENT_TYPE_FID_NAME: + return fanotify_name_event_equal(FANOTIFY_NE(old), + FANOTIFY_NE(new)); default: WARN_ON_ONCE(1); } @@ -262,6 +282,9 @@ static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, void *buf = fh->buf; int err; + if (!inode) + goto out; + dwords = 0; err = -ENOENT; type = exportfs_encode_inode_fh(inode, NULL, &dwords, NULL); @@ -295,6 +318,7 @@ out_err: type, bytes, err); kfree(ext_buf); *fanotify_fh_ext_buf_ptr(fh) = NULL; +out: /* Report the event without a file identifier on encode error */ fh->type = FILEID_INVALID; fh->len = 0; @@ -320,10 +344,12 @@ static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask, struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, struct inode *inode, u32 mask, const void *data, int data_type, + const struct qstr *file_name, __kernel_fsid_t *fsid) { struct fanotify_event *event = NULL; struct fanotify_fid_event *ffe = NULL; + struct fanotify_name_event *fne = NULL; gfp_t gfp = GFP_KERNEL_ACCOUNT; struct inode *id = fanotify_fid_inode(inode, mask, data, data_type); const struct path *path = fsnotify_data_path(data, data_type); @@ -356,6 +382,23 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, goto init; } + /* + * For FAN_DIR_MODIFY event, we report the fid of the directory and + * the name of the modified entry. + * Allocate an fanotify_name_event struct and copy the name. + */ + if (mask & FAN_DIR_MODIFY && !(WARN_ON_ONCE(!file_name))) { + fne = kmalloc(sizeof(*fne) + file_name->len + 1, gfp); + if (!fne) + goto out; + + event = &fne->fae; + event->type = FANOTIFY_EVENT_TYPE_FID_NAME; + fne->name_len = file_name->len; + strcpy(fne->name, file_name->name); + goto init; + } + if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { ffe = kmem_cache_alloc(fanotify_fid_event_cachep, gfp); if (!ffe) @@ -374,7 +417,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, event->type = FANOTIFY_EVENT_TYPE_PATH; } -init: __maybe_unused +init: /* * Use the victim inode instead of the watching inode as the id for * event queue, so event reported on parent is merged with event @@ -387,13 +430,16 @@ init: __maybe_unused else event->pid = get_pid(task_tgid(current)); - if (fanotify_event_object_fh(event)) { - ffe->object_fh.len = 0; - if (fsid) - ffe->fsid = *fsid; - if (id) - fanotify_encode_fh(&ffe->object_fh, id, gfp); - } else if (fanotify_event_has_path(event)) { + if (fsid && fanotify_event_fsid(event)) + *fanotify_event_fsid(event) = *fsid; + + if (fanotify_event_object_fh(event)) + fanotify_encode_fh(fanotify_event_object_fh(event), id, gfp); + + if (fanotify_event_dir_fh(event)) + fanotify_encode_fh(fanotify_event_dir_fh(event), id, gfp); + + if (fanotify_event_has_path(event)) { struct path *p = fanotify_event_path(event); if (path) { @@ -501,7 +547,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, } event = fanotify_alloc_event(group, inode, mask, data, data_type, - &fsid); + file_name, &fsid); ret = -ENOMEM; if (unlikely(!event)) { /* @@ -563,6 +609,15 @@ static void fanotify_free_fid_event(struct fanotify_event *event) kmem_cache_free(fanotify_fid_event_cachep, ffe); } +static void fanotify_free_name_event(struct fanotify_event *event) +{ + struct fanotify_name_event *fne = FANOTIFY_NE(event); + + if (fanotify_fh_has_ext_buf(&fne->dir_fh)) + kfree(fanotify_fh_ext_buf(&fne->dir_fh)); + kfree(fne); +} + static void fanotify_free_event(struct fsnotify_event *fsn_event) { struct fanotify_event *event; @@ -579,6 +634,9 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event) case FANOTIFY_EVENT_TYPE_FID: fanotify_free_fid_event(event); break; + case FANOTIFY_EVENT_TYPE_FID_NAME: + fanotify_free_name_event(event); + break; default: WARN_ON_ONCE(1); } diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index eecf4be3bfd1..35bfbf4a7aac 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -59,7 +59,8 @@ static inline void *fanotify_fh_buf(struct fanotify_fh *fh) * be freed and which concrete struct it may be cast to. */ enum fanotify_event_type { - FANOTIFY_EVENT_TYPE_FID, + FANOTIFY_EVENT_TYPE_FID, /* fixed length */ + FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */ FANOTIFY_EVENT_TYPE_PATH, FANOTIFY_EVENT_TYPE_PATH_PERM, }; @@ -83,10 +84,26 @@ FANOTIFY_FE(struct fanotify_event *event) return container_of(event, struct fanotify_fid_event, fae); } +struct fanotify_name_event { + struct fanotify_event fae; + __kernel_fsid_t fsid; + struct fanotify_fh dir_fh; + u8 name_len; + char name[0]; +}; + +static inline struct fanotify_name_event * +FANOTIFY_NE(struct fanotify_event *event) +{ + return container_of(event, struct fanotify_name_event, fae); +} + static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) { if (event->type == FANOTIFY_EVENT_TYPE_FID) return &FANOTIFY_FE(event)->fsid; + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + return &FANOTIFY_NE(event)->fsid; else return NULL; } @@ -100,6 +117,15 @@ static inline struct fanotify_fh *fanotify_event_object_fh( return NULL; } +static inline struct fanotify_fh *fanotify_event_dir_fh( + struct fanotify_event *event) +{ + if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + return &FANOTIFY_NE(event)->dir_fh; + else + return NULL; +} + static inline int fanotify_event_object_fh_len(struct fanotify_event *event) { struct fanotify_fh *fh = fanotify_event_object_fh(event); @@ -107,6 +133,17 @@ static inline int fanotify_event_object_fh_len(struct fanotify_event *event) return fh ? fh->len : 0; } +static inline bool fanotify_event_has_name(struct fanotify_event *event) +{ + return event->type == FANOTIFY_EVENT_TYPE_FID_NAME; +} + +static inline int fanotify_event_name_len(struct fanotify_event *event) +{ + return fanotify_event_has_name(event) ? + FANOTIFY_NE(event)->name_len : 0; +} + struct fanotify_path_event { struct fanotify_event fae; struct path path; @@ -169,4 +206,5 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event) struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, struct inode *inode, u32 mask, const void *data, int data_type, + const struct qstr *file_name, __kernel_fsid_t *fsid); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index b93585406aad..a9d287a56098 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -210,7 +210,7 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, struct fanotify_event_info_fid info = { }; struct file_handle handle = { }; unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; - size_t fh_len = fh->len; + size_t fh_len = fh ? fh->len : 0; size_t len = fanotify_fid_info_len(fh_len); if (!len) @@ -828,7 +828,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) group->memcg = get_mem_cgroup_from_mm(current->mm); oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL, - FSNOTIFY_EVENT_NONE, NULL); + FSNOTIFY_EVENT_NONE, NULL, NULL); if (unlikely(!oevent)) { fd = -ENOMEM; goto out_destroy_group; From 44d705b0370b1d581f46ff23e5d33e8b5ff8ec58 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 19 Mar 2020 17:10:22 +0200 Subject: [PATCH 590/809] fanotify: report name info for FAN_DIR_MODIFY event Report event FAN_DIR_MODIFY with name in a variable length record similar to how fid's are reported. With name info reporting implemented, setting FAN_DIR_MODIFY in mark mask is now allowed. When events are reported with name, the reported fid identifies the directory and the name follows the fid. The info record type for this event info is FAN_EVENT_INFO_TYPE_DFID_NAME. For now, all reported events have at most one info record which is either FAN_EVENT_INFO_TYPE_FID or FAN_EVENT_INFO_TYPE_DFID_NAME (for FAN_DIR_MODIFY). Later on, events "on child" will report both records. There are several ways that an application can use this information: 1. When watching a single directory, the name is always relative to the watched directory, so application need to fstatat(2) the name relative to the watched directory. 2. When watching a set of directories, the application could keep a map of dirfd for all watched directories and hash the map by fid obtained with name_to_handle_at(2). When getting a name event, the fid in the event info could be used to lookup the base dirfd in the map and then call fstatat(2) with that dirfd. 3. When watching a filesystem (FAN_MARK_FILESYSTEM) or a large set of directories, the application could use open_by_handle_at(2) with the fid in event info to obtain dirfd for the directory where event happened and call fstatat(2) with this dirfd. The last option scales better for a large number of watched directories. The first two options may be available in the future also for non privileged fanotify watchers, because open_by_handle_at(2) requires the CAP_DAC_READ_SEARCH capability. Link: https://lore.kernel.org/r/20200319151022.31456-15-amir73il@gmail.com Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/fanotify/fanotify.c | 2 +- fs/notify/fanotify/fanotify_user.c | 117 ++++++++++++++++++++++------- include/linux/fanotify.h | 3 +- include/uapi/linux/fanotify.h | 8 +- 4 files changed, 100 insertions(+), 30 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 599654564b2a..4c1a4eb597d5 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -520,7 +520,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC); BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM); - BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19); + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); mask = fanotify_group_event_mask(group, iter_info, mask, data, data_type); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index a9d287a56098..42cb794c62ac 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -51,22 +51,35 @@ struct kmem_cache *fanotify_path_event_cachep __read_mostly; struct kmem_cache *fanotify_perm_event_cachep __read_mostly; #define FANOTIFY_EVENT_ALIGN 4 +#define FANOTIFY_INFO_HDR_LEN \ + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) -static int fanotify_fid_info_len(int fh_len) +static int fanotify_fid_info_len(int fh_len, int name_len) { - return roundup(sizeof(struct fanotify_event_info_fid) + - sizeof(struct file_handle) + fh_len, - FANOTIFY_EVENT_ALIGN); + int info_len = fh_len; + + if (name_len) + info_len += name_len + 1; + + return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN); } static int fanotify_event_info_len(struct fanotify_event *event) { + int info_len = 0; int fh_len = fanotify_event_object_fh_len(event); - if (!fh_len) - return 0; + if (fh_len) + info_len += fanotify_fid_info_len(fh_len, 0); - return fanotify_fid_info_len(fh_len); + if (fanotify_event_name_len(event)) { + struct fanotify_name_event *fne = FANOTIFY_NE(event); + + info_len += fanotify_fid_info_len(fne->dir_fh.len, + fne->name_len); + } + + return info_len; } /* @@ -204,23 +217,32 @@ static int process_access_response(struct fsnotify_group *group, return -ENOENT; } -static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, - char __user *buf) +static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + const char *name, size_t name_len, + char __user *buf, size_t count) { struct fanotify_event_info_fid info = { }; struct file_handle handle = { }; unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; size_t fh_len = fh ? fh->len : 0; - size_t len = fanotify_fid_info_len(fh_len); + size_t info_len = fanotify_fid_info_len(fh_len, name_len); + size_t len = info_len; - if (!len) + pr_debug("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n", + __func__, fh_len, name_len, info_len, count); + + if (!fh_len || (name && !name_len)) return 0; - if (WARN_ON_ONCE(len < sizeof(info) + sizeof(handle) + fh_len)) + if (WARN_ON_ONCE(len < sizeof(info) || len > count)) return -EFAULT; - /* Copy event info fid header followed by vaiable sized file handle */ - info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID; + /* + * Copy event info fid header followed by variable sized file handle + * and optionally followed by variable sized filename. + */ + info.hdr.info_type = name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : + FAN_EVENT_INFO_TYPE_FID; info.hdr.len = len; info.fsid = *fsid; if (copy_to_user(buf, &info, sizeof(info))) @@ -228,6 +250,9 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, buf += sizeof(info); len -= sizeof(info); + if (WARN_ON_ONCE(len < sizeof(handle))) + return -EFAULT; + handle.handle_type = fh->type; handle.handle_bytes = fh_len; if (copy_to_user(buf, &handle, sizeof(handle))) @@ -235,9 +260,12 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, buf += sizeof(handle); len -= sizeof(handle); + if (WARN_ON_ONCE(len < fh_len)) + return -EFAULT; + /* - * For an inline fh, copy through stack to exclude the copy from - * usercopy hardening protections. + * For an inline fh and inline file name, copy through stack to exclude + * the copy from usercopy hardening protections. */ fh_buf = fanotify_fh_buf(fh); if (fh_len <= FANOTIFY_INLINE_FH_LEN) { @@ -247,14 +275,28 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, if (copy_to_user(buf, fh_buf, fh_len)) return -EFAULT; - /* Pad with 0's */ buf += fh_len; len -= fh_len; + + if (name_len) { + /* Copy the filename with terminating null */ + name_len++; + if (WARN_ON_ONCE(len < name_len)) + return -EFAULT; + + if (copy_to_user(buf, name, name_len)) + return -EFAULT; + + buf += name_len; + len -= name_len; + } + + /* Pad with 0's */ WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN); if (len > 0 && clear_user(buf, len)) return -EFAULT; - return 0; + return info_len; } static ssize_t copy_event_to_user(struct fsnotify_group *group, @@ -268,16 +310,15 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, pr_debug("%s: group=%p event=%p\n", __func__, group, event); - metadata.event_len = FAN_EVENT_METADATA_LEN; + metadata.event_len = FAN_EVENT_METADATA_LEN + + fanotify_event_info_len(event); metadata.metadata_len = FAN_EVENT_METADATA_LEN; metadata.vers = FANOTIFY_METADATA_VERSION; metadata.reserved = 0; metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; metadata.pid = pid_vnr(event->pid); - if (fanotify_event_object_fh(event)) { - metadata.event_len += fanotify_event_info_len(event); - } else if (path && path->mnt && path->dentry) { + if (path && path->mnt && path->dentry) { fd = create_fd(group, path, &f); if (fd < 0) return fd; @@ -295,17 +336,39 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN)) goto out_close_fd; + buf += FAN_EVENT_METADATA_LEN; + count -= FAN_EVENT_METADATA_LEN; + if (fanotify_is_perm_event(event->mask)) FANOTIFY_PERM(event)->fd = fd; - if (f) { + if (f) fd_install(fd, f); - } else if (fanotify_event_object_fh(event)) { - ret = copy_fid_to_user(fanotify_event_fsid(event), - fanotify_event_object_fh(event), - buf + FAN_EVENT_METADATA_LEN); + + /* Event info records order is: dir fid + name, child fid */ + if (fanotify_event_name_len(event)) { + struct fanotify_name_event *fne = FANOTIFY_NE(event); + + ret = copy_info_to_user(fanotify_event_fsid(event), + fanotify_event_dir_fh(event), + fne->name, fne->name_len, + buf, count); if (ret < 0) return ret; + + buf += ret; + count -= ret; + } + + if (fanotify_event_object_fh_len(event)) { + ret = copy_info_to_user(fanotify_event_fsid(event), + fanotify_event_object_fh(event), + NULL, 0, buf, count); + if (ret < 0) + return ret; + + buf += ret; + count -= ret; } return metadata.event_len; diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index b79fa9bb7359..3049a6c06d9e 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -47,7 +47,8 @@ * Directory entry modification events - reported only to directory * where entry is modified and not to a watching parent. */ -#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE) +#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \ + FAN_DIR_MODIFY) /* Events that can only be reported with data type FSNOTIFY_EVENT_INODE */ #define FANOTIFY_INODE_EVENTS (FANOTIFY_DIRENT_EVENTS | \ diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index 615fa2c87179..a88c7c6d0692 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -117,6 +117,7 @@ struct fanotify_event_metadata { }; #define FAN_EVENT_INFO_TYPE_FID 1 +#define FAN_EVENT_INFO_TYPE_DFID_NAME 2 /* Variable length info record following event metadata */ struct fanotify_event_info_header { @@ -125,7 +126,12 @@ struct fanotify_event_info_header { __u16 len; }; -/* Unique file identifier info record */ +/* + * Unique file identifier info record. This is used both for + * FAN_EVENT_INFO_TYPE_FID records and for FAN_EVENT_INFO_TYPE_DFID_NAME + * records. For FAN_EVENT_INFO_TYPE_DFID_NAME there is additionally a null + * terminated name immediately after the file handle. + */ struct fanotify_event_info_fid { struct fanotify_event_info_header hdr; __kernel_fsid_t fsid; From 5eefcaed501dd9e3933dbff58720244bd75ed90f Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Mon, 9 Mar 2020 12:02:01 -0700 Subject: [PATCH 591/809] gpio: brcmstb: support gpio-line-names property The default handling of the gpio-line-names property by the gpiolib-of implementation does not work with the multiple gpiochip banks per device structure used by the gpio-brcmstb driver. This commit adds driver level support for the device tree property so that GPIO lines can be assigned friendly names. Signed-off-by: Doug Berger Link: https://lore.kernel.org/r/1583780521-45702-1-git-send-email-opendmb@gmail.com Acked-by: Gregory Fong Acked-by: Florian Fainelli Signed-off-by: Linus Walleij --- drivers/gpio/gpio-brcmstb.c | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 05e3f99ae59c..fcfc1a1f1a5c 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -603,6 +603,49 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = { .resume_noirq = brcmstb_gpio_resume, }; +static void brcmstb_gpio_set_names(struct device *dev, + struct brcmstb_gpio_bank *bank) +{ + struct device_node *np = dev->of_node; + const char **names; + int nstrings, base; + unsigned int i; + + base = bank->id * MAX_GPIO_PER_BANK; + + nstrings = of_property_count_strings(np, "gpio-line-names"); + if (nstrings <= base) + /* Line names not present */ + return; + + names = devm_kcalloc(dev, MAX_GPIO_PER_BANK, sizeof(*names), + GFP_KERNEL); + if (!names) + return; + + /* + * Make sure to not index beyond the end of the number of descriptors + * of the GPIO device. + */ + for (i = 0; i < bank->width; i++) { + const char *name; + int ret; + + ret = of_property_read_string_index(np, "gpio-line-names", + base + i, &name); + if (ret) { + if (ret != -ENODATA) + dev_err(dev, "unable to name line %d: %d\n", + base + i, ret); + break; + } + if (*name) + names[i] = name; + } + + bank->gc.names = names; +} + static int brcmstb_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -726,6 +769,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); gc->write_reg(reg_base + GIO_MASK(bank->id), 0); + brcmstb_gpio_set_names(dev, bank); err = gpiochip_add_data(gc, bank); if (err) { dev_err(dev, "Could not add gpiochip for bank %d\n", From a7032637b54186e5649917679727d7feaec932b1 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 12 Aug 2019 14:50:43 -0700 Subject: [PATCH 592/809] powerpc: Prefer __section and __printf from compiler_attributes.h Reported-by: Sedat Dilek Suggested-by: Josh Poimboeuf Signed-off-by: Nick Desaulniers [mpe: Drop changes to a/p/boot which doesn't use linux headers] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190812215052.71840-10-ndesaulniers@google.com --- arch/powerpc/include/asm/cache.h | 2 +- arch/powerpc/kernel/btext.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 72b81015cebe..609cab1d58f2 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -97,7 +97,7 @@ static inline u32 l1_icache_bytes(void) #endif -#define __read_mostly __attribute__((__section__(".data..read_mostly"))) +#define __read_mostly __section(.data..read_mostly) #ifdef CONFIG_PPC_BOOK3S_32 extern long _get_L2CR(void); diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 6dfceaa820e4..f57712a55815 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -26,7 +26,7 @@ static void scrollscreen(void); #endif -#define __force_data __attribute__((__section__(".data"))) +#define __force_data __section(.data) static int g_loc_X __force_data; static int g_loc_Y __force_data; From b1a504a6500df50e83b701b7946b34fce27ad8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 6 Mar 2020 16:01:40 +0100 Subject: [PATCH 593/809] powerpc/xive: Use XIVE_BAD_IRQ instead of zero to catch non configured IPIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a CPU is brought up, an IPI number is allocated and recorded under the XIVE CPU structure. Invalid IPI numbers are tracked with interrupt number 0x0. On the PowerNV platform, the interrupt number space starts at 0x10 and this works fine. However, on the sPAPR platform, it is possible to allocate the interrupt number 0x0 and this raises an issue when CPU 0 is unplugged. The XIVE spapr driver tracks allocated interrupt numbers in a bitmask and it is not correctly updated when interrupt number 0x0 is freed. It stays allocated and it is then impossible to reallocate. Fix by using the XIVE_BAD_IRQ value instead of zero on both platforms. Reported-by: David Gibson Fixes: eac1e731b59e ("powerpc/xive: guest exploitation of the XIVE interrupt controller") Cc: stable@vger.kernel.org # v4.14+ Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Tested-by: David Gibson Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306150143.5551-2-clg@kaod.org --- arch/powerpc/sysdev/xive/common.c | 12 +++--------- arch/powerpc/sysdev/xive/native.c | 4 ++-- arch/powerpc/sysdev/xive/spapr.c | 4 ++-- arch/powerpc/sysdev/xive/xive-internal.h | 7 +++++++ 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 9651ca061828..0e918fe6a4ec 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -68,13 +68,6 @@ static u32 xive_ipi_irq; /* Xive state for each CPU */ static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu); -/* - * A "disabled" interrupt should never fire, to catch problems - * we set its logical number to this - */ -#define XIVE_BAD_IRQ 0x7fffffff -#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1) - /* An invalid CPU target */ #define XIVE_INVALID_TARGET (-1) @@ -1150,7 +1143,7 @@ static int xive_setup_cpu_ipi(unsigned int cpu) xc = per_cpu(xive_cpu, cpu); /* Check if we are already setup */ - if (xc->hw_ipi != 0) + if (xc->hw_ipi != XIVE_BAD_IRQ) return 0; /* Grab an IPI from the backend, this will populate xc->hw_ipi */ @@ -1187,7 +1180,7 @@ static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) /* Disable the IPI and free the IRQ data */ /* Already cleaned up ? */ - if (xc->hw_ipi == 0) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; /* Mask the IPI */ @@ -1343,6 +1336,7 @@ static int xive_prepare_cpu(unsigned int cpu) if (np) xc->chip_id = of_get_ibm_chip_id(np); of_node_put(np); + xc->hw_ipi = XIVE_BAD_IRQ; per_cpu(xive_cpu, cpu) = xc; } diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index 0ff6b739052c..50e1a8e02497 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -312,7 +312,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc) s64 rc; /* Free the IPI */ - if (!xc->hw_ipi) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; for (;;) { rc = opal_xive_free_irq(xc->hw_ipi); @@ -320,7 +320,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc) msleep(OPAL_BUSY_DELAY_MS); continue; } - xc->hw_ipi = 0; + xc->hw_ipi = XIVE_BAD_IRQ; break; } } diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index 55dc61cb4867..3f15615712b5 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c @@ -560,11 +560,11 @@ static int xive_spapr_get_ipi(unsigned int cpu, struct xive_cpu *xc) static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc) { - if (!xc->hw_ipi) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; xive_irq_bitmap_free(xc->hw_ipi); - xc->hw_ipi = 0; + xc->hw_ipi = XIVE_BAD_IRQ; } #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/sysdev/xive/xive-internal.h b/arch/powerpc/sysdev/xive/xive-internal.h index 59cd366e7933..382980f4de2d 100644 --- a/arch/powerpc/sysdev/xive/xive-internal.h +++ b/arch/powerpc/sysdev/xive/xive-internal.h @@ -5,6 +5,13 @@ #ifndef __XIVE_INTERNAL_H #define __XIVE_INTERNAL_H +/* + * A "disabled" interrupt should never fire, to catch problems + * we set its logical number to this + */ +#define XIVE_BAD_IRQ 0x7fffffff +#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1) + /* Each CPU carry one of these with various per-CPU state */ struct xive_cpu { #ifdef CONFIG_SMP From 97ef275077932c65b1b8ec5022abd737a9fbf3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 6 Mar 2020 16:01:41 +0100 Subject: [PATCH 594/809] powerpc/xive: Fix xmon support on the PowerNV platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PowerNV platform has multiple IRQ chips and the xmon command dumping the state of the XIVE interrupt should only operate on the XIVE IRQ chip. Fixes: 5896163f7f91 ("powerpc/xmon: Improve output of XIVE interrupts") Cc: stable@vger.kernel.org # v5.4+ Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306150143.5551-3-clg@kaod.org --- arch/powerpc/sysdev/xive/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 0e918fe6a4ec..fe8d396e2301 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -258,11 +258,15 @@ notrace void xmon_xive_do_dump(int cpu) int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d) { + struct irq_chip *chip = irq_data_get_irq_chip(d); int rc; u32 target; u8 prio; u32 lirq; + if (!is_xive_irq(chip)) + return -EINVAL; + rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq); if (rc) { xmon_printf("IRQ 0x%08x : no config rc=%d\n", hw_irq, rc); From 5191e0ba51df3a886a2040002e09afd53f625232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 6 Mar 2020 16:01:42 +0100 Subject: [PATCH 595/809] powerpc/xmon: Add source flags to output of XIVE interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some firmwares or hypervisors can advertise different source characteristics. Track their value under XMON. What we are mostly interested in is the StoreEOI flag. Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306150143.5551-4-clg@kaod.org --- arch/powerpc/sysdev/xive/common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index fe8d396e2301..0a47ddf3c148 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -280,7 +280,10 @@ int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d) struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); u64 val = xive_esb_read(xd, XIVE_ESB_GET); - xmon_printf("PQ=%c%c", + xmon_printf("flags=%c%c%c PQ=%c%c", + xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ', + xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ', + xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ', val & XIVE_ESB_VAL_P ? 'P' : '-', val & XIVE_ESB_VAL_Q ? 'Q' : '-'); } From 930914b7d528fc6b0249bffc00564100bcf6ef75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 6 Mar 2020 16:01:43 +0100 Subject: [PATCH 596/809] powerpc/xive: Add a debugfs file to dump internal XIVE state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As does XMON, the debugfs file /sys/kernel/debug/powerpc/xive exposes the XIVE internal state of the machine CPUs and interrupts. Available on the PowerNV and sPAPR platforms. Signed-off-by: Cédric Le Goater [mpe: Make the debugfs file 0400] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200306150143.5551-5-clg@kaod.org --- arch/powerpc/sysdev/xive/common.c | 105 +++++++++++++++++++++++ arch/powerpc/sysdev/xive/native.c | 3 + arch/powerpc/sysdev/xive/spapr.c | 19 ++++ arch/powerpc/sysdev/xive/xive-internal.h | 2 + 4 files changed, 129 insertions(+) diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 0a47ddf3c148..b294f70f1a67 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -1555,3 +1556,107 @@ static int __init xive_off(char *arg) return 0; } __setup("xive=off", xive_off); + +void xive_debug_show_cpu(struct seq_file *m, int cpu) +{ + struct xive_cpu *xc = per_cpu(xive_cpu, cpu); + + seq_printf(m, "CPU %d:", cpu); + if (xc) { + seq_printf(m, "pp=%02x CPPR=%02x ", xc->pending_prio, xc->cppr); + +#ifdef CONFIG_SMP + { + u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET); + + seq_printf(m, "IPI=0x%08x PQ=%c%c ", xc->hw_ipi, + val & XIVE_ESB_VAL_P ? 'P' : '-', + val & XIVE_ESB_VAL_Q ? 'Q' : '-'); + } +#endif + { + struct xive_q *q = &xc->queue[xive_irq_priority]; + u32 i0, i1, idx; + + if (q->qpage) { + idx = q->idx; + i0 = be32_to_cpup(q->qpage + idx); + idx = (idx + 1) & q->msk; + i1 = be32_to_cpup(q->qpage + idx); + seq_printf(m, "EQ idx=%d T=%d %08x %08x ...", + q->idx, q->toggle, i0, i1); + } + } + } + seq_puts(m, "\n"); +} + +void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data *d) +{ + struct irq_chip *chip = irq_data_get_irq_chip(d); + int rc; + u32 target; + u8 prio; + u32 lirq; + + if (!is_xive_irq(chip)) + return; + + rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq); + if (rc) { + seq_printf(m, "IRQ 0x%08x : no config rc=%d\n", hw_irq, rc); + return; + } + + seq_printf(m, "IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ", + hw_irq, target, prio, lirq); + + if (d) { + struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); + u64 val = xive_esb_read(xd, XIVE_ESB_GET); + + seq_printf(m, "flags=%c%c%c PQ=%c%c", + xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ', + xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ', + xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ', + val & XIVE_ESB_VAL_P ? 'P' : '-', + val & XIVE_ESB_VAL_Q ? 'Q' : '-'); + } + seq_puts(m, "\n"); +} + +static int xive_core_debug_show(struct seq_file *m, void *private) +{ + unsigned int i; + struct irq_desc *desc; + int cpu; + + if (xive_ops->debug_show) + xive_ops->debug_show(m, private); + + for_each_possible_cpu(cpu) + xive_debug_show_cpu(m, cpu); + + for_each_irq_desc(i, desc) { + struct irq_data *d = irq_desc_get_irq_data(desc); + unsigned int hw_irq; + + if (!d) + continue; + + hw_irq = (unsigned int)irqd_to_hwirq(d); + + /* IPIs are special (HW number 0) */ + if (hw_irq) + xive_debug_show_irq(m, hw_irq, d); + } + return 0; +} +DEFINE_SHOW_ATTRIBUTE(xive_core_debug); + +int xive_core_debug_init(void) +{ + debugfs_create_file("xive", 0400, powerpc_debugfs_root, + NULL, &xive_core_debug_fops); + return 0; +} diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index 50e1a8e02497..5218fdc4b29a 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -850,3 +851,5 @@ int xive_native_get_vp_state(u32 vp_id, u64 *out_state) return 0; } EXPORT_SYMBOL_GPL(xive_native_get_vp_state); + +machine_arch_initcall(powernv, xive_core_debug_init); diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index 3f15615712b5..7ab5c6780997 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -645,6 +646,21 @@ static void xive_spapr_sync_source(u32 hw_irq) plpar_int_sync(0, hw_irq); } +static int xive_spapr_debug_show(struct seq_file *m, void *private) +{ + struct xive_irq_bitmap *xibm; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + + list_for_each_entry(xibm, &xive_irq_bitmaps, list) { + memset(buf, 0, PAGE_SIZE); + bitmap_print_to_pagebuf(true, buf, xibm->bitmap, xibm->count); + seq_printf(m, "bitmap #%d: %s", xibm->count, buf); + } + kfree(buf); + + return 0; +} + static const struct xive_ops xive_spapr_ops = { .populate_irq_data = xive_spapr_populate_irq_data, .configure_irq = xive_spapr_configure_irq, @@ -662,6 +678,7 @@ static const struct xive_ops xive_spapr_ops = { #ifdef CONFIG_SMP .get_ipi = xive_spapr_get_ipi, .put_ipi = xive_spapr_put_ipi, + .debug_show = xive_spapr_debug_show, #endif /* CONFIG_SMP */ .name = "spapr", }; @@ -839,3 +856,5 @@ bool __init xive_spapr_init(void) pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10)); return true; } + +machine_arch_initcall(pseries, xive_core_debug_init); diff --git a/arch/powerpc/sysdev/xive/xive-internal.h b/arch/powerpc/sysdev/xive/xive-internal.h index 382980f4de2d..b7b901da2168 100644 --- a/arch/powerpc/sysdev/xive/xive-internal.h +++ b/arch/powerpc/sysdev/xive/xive-internal.h @@ -57,12 +57,14 @@ struct xive_ops { int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc); void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc); #endif + int (*debug_show)(struct seq_file *m, void *private); const char *name; }; bool xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset, u8 max_prio); __be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift); +int xive_core_debug_init(void); static inline u32 xive_alloc_order(u32 queue_shift) { From 8ec26c25c33d21468a8b39722337463550b15e5b Mon Sep 17 00:00:00 2001 From: Douglas Miller Date: Mon, 27 Feb 2017 08:28:14 -0600 Subject: [PATCH 597/809] powerpc/xmon: Add ASCII dump to d1,d2,d4,d8 commands. The reason debuggers add an ASCII dump to other types of memory dumps is to give the user visual reference points in the case that ASCII strings are adjacent to other structures or element. For example, when examining the task_struct structure one can look for the comm[] string and use it to locate other important elements. ASCII strings do not have endianess, they exist in memory in the same order regardless of CPU endianess. ASCII strings are, by definition, human readable and so should be presented in a human readable format. For these reasons, the supplemental ASCII dump does not re-order the strings from memory to match the endianess of the corresponding 16, 32, or 64 bit words. That would make the ASCII dump much less useful. Signed-off-by: Douglas Miller Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/1488205694-13337-1-git-send-email-dougmill@linux.vnet.ibm.com --- arch/powerpc/xmon/xmon.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index ea303b7e4e29..7af840c0fc93 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2713,7 +2713,12 @@ static void dump_by_size(unsigned long addr, long count, int size) printf("%0*llx", size * 2, val); } - printf("\n"); + printf(" |"); + for (j = 0; j < 16; ++j) { + val = temp[j]; + putchar(' ' <= val && val <= '~' ? val : '.'); + } + printf("|\n"); } } From 2a3d252dffe14582f238e21b09923e3772263123 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 25 Mar 2020 09:40:22 -0700 Subject: [PATCH 598/809] perf parse-events: Add defensive NULL check Terms may have a NULL config in which case a strcmp will SEGV. This can be reproduced with: perf stat -e '*/event=?,nr/' sleep 1 Add a NULL check to avoid this. This was caught by LLVM's libfuzzer. Signed-off-by: Ian Rogers Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: clang-built-linux@googlegroups.com Link: http://lore.kernel.org/lkml/20200325164022.41385-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 616fbda7c3fc..ef6a63f3d386 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -984,12 +984,11 @@ static int pmu_resolve_param_term(struct parse_events_term *term, struct parse_events_term *t; list_for_each_entry(t, head_terms, list) { - if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { - if (!strcmp(t->config, term->config)) { - t->used = true; - *value = t->val.num; - return 0; - } + if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && + t->config && !strcmp(t->config, term->config)) { + t->used = true; + *value = t->val.num; + return 0; } } From e4ffd066ff440a57097e9140fa9e16ceef905de8 Mon Sep 17 00:00:00 2001 From: He Zhe Date: Fri, 14 Feb 2020 02:21:06 +0800 Subject: [PATCH 599/809] perf: Normalize gcc parameter when generating arch errno table The $(CC) passed to arch_errno_names.sh may include a series of parameters along with gcc itself. To avoid overwriting the following parameters of arch_errno_names.sh and break the build like below, we just pick up the first word of the $(CC). find: unknown predicate `-m64/arch' x86_64-wrs-linux-gcc: warning: '-x c' after last input file has no effect x86_64-wrs-linux-gcc: error: unrecognized command line option '-m64/include/uapi/asm-generic/errno.h' x86_64-wrs-linux-gcc: fatal error: no input files Signed-off-by: He Zhe Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/1581618066-187262-2-git-send-email-zhe.he@windriver.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index a02aca9b21f4..d15a311408f1 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -574,7 +574,7 @@ arch_errno_hdr_dir := $(srctree)/tools arch_errno_tbl := $(srctree)/tools/perf/trace/beauty/arch_errno_names.sh $(arch_errno_name_array): $(arch_errno_tbl) - $(Q)$(SHELL) '$(arch_errno_tbl)' $(CC) $(arch_errno_hdr_dir) > $@ + $(Q)$(SHELL) '$(arch_errno_tbl)' $(firstword $(CC)) $(arch_errno_hdr_dir) > $@ sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh From 7703889e8ee1b318f632be7ba4d58d9962ecf34f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:39 +1100 Subject: [PATCH 600/809] powerpc: Update MAINTAINERS A while back Paul pointed out I'd been maintaining the tree more or less solo for over five years, so perhaps it's time to update the MAINTAINERS entry. Ben & Paul still wrote most of the code, so keep them as Reviewers so they still get Cc'ed on things. But if you're wondering why your patch hasn't been merged that's my fault. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200224233146.23734-1-mpe@ellerman.id.au --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a0d86490c2c6..1e36f88384f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9600,9 +9600,9 @@ F: arch/powerpc/platforms/powermac/ F: drivers/macintosh/ LINUX FOR POWERPC (32-BIT AND 64-BIT) -M: Benjamin Herrenschmidt -M: Paul Mackerras M: Michael Ellerman +R: Benjamin Herrenschmidt +R: Paul Mackerras W: https://github.com/linuxppc/linux/wiki L: linuxppc-dev@lists.ozlabs.org Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ From fd65a1aaad488d8346f235816c68203b95bb15f1 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:40 +1100 Subject: [PATCH 601/809] powerpc: Update wiki link in MAINTAINERS The wiki has moved, update the link. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200224233146.23734-2-mpe@ellerman.id.au --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1e36f88384f9..0081f492e550 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9603,7 +9603,7 @@ LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Michael Ellerman R: Benjamin Herrenschmidt R: Paul Mackerras -W: https://github.com/linuxppc/linux/wiki +W: https://github.com/linuxppc/wiki/wiki L: linuxppc-dev@lists.ozlabs.org Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git From b24f9ee4526f65bb5acdd68a07f4099486208a9e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:41 +1100 Subject: [PATCH 602/809] powerpc: Remove PA SEMI MAINTAINERS entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PA SEMI entries have been orphaned for 3 ½ years, so fold them into the main POWERPC entry. The result of get_maintainer.pl is more or less unchanged. Signed-off-by: Michael Ellerman Acked-by: Olof Johansson Link: https://lore.kernel.org/r/20200224233146.23734-3-mpe@ellerman.id.au --- MAINTAINERS | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0081f492e550..1806496279c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9620,6 +9620,8 @@ F: drivers/crypto/vmx/ F: drivers/i2c/busses/i2c-opal.c F: drivers/net/ethernet/ibm/ibmveth.* F: drivers/net/ethernet/ibm/ibmvnic.* +F: drivers/*/*/*pasemi* +F: drivers/*/*pasemi* F: drivers/pci/hotplug/pnv_php.c F: drivers/pci/hotplug/rpa* F: drivers/rtc/rtc-opal.c @@ -9674,13 +9676,6 @@ S: Orphan F: arch/powerpc/*/*virtex* F: arch/powerpc/*/*/*virtex* -LINUX FOR POWERPC PA SEMI PWRFICIENT -L: linuxppc-dev@lists.ozlabs.org -S: Orphan -F: arch/powerpc/platforms/pasemi/ -F: drivers/*/*pasemi* -F: drivers/*/*/*pasemi* - LINUX KERNEL DUMP TEST MODULE (LKDTM) M: Kees Cook S: Maintained @@ -12540,16 +12535,6 @@ W: http://wireless.kernel.org/en/users/Drivers/p54 S: Maintained F: drivers/net/wireless/intersil/p54/ -PA SEMI ETHERNET DRIVER -L: netdev@vger.kernel.org -S: Orphan -F: drivers/net/ethernet/pasemi/* - -PA SEMI SMBUS DRIVER -L: linux-i2c@vger.kernel.org -S: Orphan -F: drivers/i2c/busses/i2c-pasemi.c - PACKING M: Vladimir Oltean L: netdev@vger.kernel.org From 1ca99770e5aca6036e88a37610a17d5d65ea9752 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:42 +1100 Subject: [PATCH 603/809] powerpc: Mark 4xx as Orphan in MAINTAINERS The 4xx platforms are no longer maintained. Signed-off-by: Michael Ellerman Acked-by: Alistair Popple Link: https://lore.kernel.org/r/20200224233146.23734-4-mpe@ellerman.id.au --- MAINTAINERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1806496279c3..e722ecbe415a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9644,11 +9644,8 @@ F: arch/powerpc/platforms/512x/ F: arch/powerpc/platforms/52xx/ LINUX FOR POWERPC EMBEDDED PPC4XX -M: Alistair Popple -M: Matt Porter -W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org -S: Maintained +S: Orphan F: arch/powerpc/platforms/40x/ F: arch/powerpc/platforms/44x/ From ec2debfedeca017dfa741d742ec790a80a73ab62 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:43 +1100 Subject: [PATCH 604/809] powerpc: Drop XILINX MAINTAINERS entry This has been orphaned for ~7 years, remove it. Signed-off-by: Michael Ellerman Acked-by: Grant Likely Link: https://lore.kernel.org/r/20200224233146.23734-5-mpe@ellerman.id.au --- MAINTAINERS | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e722ecbe415a..1e9f18cd2db9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9667,12 +9667,6 @@ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/8xx/ -LINUX FOR POWERPC EMBEDDED XILINX VIRTEX -L: linuxppc-dev@lists.ozlabs.org -S: Orphan -F: arch/powerpc/*/*virtex* -F: arch/powerpc/*/*/*virtex* - LINUX KERNEL DUMP TEST MODULE (LKDTM) M: Kees Cook S: Maintained From b865a8b560105d08f55f562cbc89719f6d3e816b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:44 +1100 Subject: [PATCH 605/809] powerpc: Update MPC5XXX MAINTAINERS entry It's several years since the last commit from Anatolij, so mark MPC5XXX as "Odd Fixes" rather than "Maintained". Also the git link no longer works so remove it. Signed-off-by: Michael Ellerman Acked-by: Anatolij Gustschin Link: https://lore.kernel.org/r/20200224233146.23734-6-mpe@ellerman.id.au --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1e9f18cd2db9..a8c8791800fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9638,8 +9638,7 @@ N: pseries LINUX FOR POWERPC EMBEDDED MPC5XXX M: Anatolij Gustschin L: linuxppc-dev@lists.ozlabs.org -T: git git://git.denx.de/linux-denx-agust.git -S: Maintained +S: Odd Fixes F: arch/powerpc/platforms/512x/ F: arch/powerpc/platforms/52xx/ From 790082a2ac154ba66e1f202f471af7ab42e302f9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:45 +1100 Subject: [PATCH 606/809] powerpc: Update powermac MAINTAINERS entry Ben is no longer actively maintaining the powermac code, but we know where to find him if something really needs attention. The www.penguinppc.org link is dead so remove it. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200224233146.23734-7-mpe@ellerman.id.au --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a8c8791800fd..0532ab217331 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9593,9 +9593,8 @@ F: include/uapi/linux/lightnvm.h LINUX FOR POWER MACINTOSH M: Benjamin Herrenschmidt -W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org -S: Maintained +S: Odd Fixes F: arch/powerpc/platforms/powermac/ F: drivers/macintosh/ From f46b7a8ea0b391658796cc0adfccd1e990b4a223 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 10:31:46 +1100 Subject: [PATCH 607/809] powerpc: Update 83xx/85xx MAINTAINERS entry Scott said he was still maintaining this "sort of", so change the status to Odd Fixes. Kumar has long ago moved on to greener pastures. Remove the dead penguinppc.org link. Signed-off-by: Michael Ellerman Acked-by: Scott Wood Link: https://lore.kernel.org/r/20200224233146.23734-8-mpe@ellerman.id.au --- MAINTAINERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0532ab217331..167f99bc6a3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9649,11 +9649,9 @@ F: arch/powerpc/platforms/44x/ LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX M: Scott Wood -M: Kumar Gala -W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git -S: Maintained +S: Odd fixes F: arch/powerpc/platforms/83xx/ F: arch/powerpc/platforms/85xx/ F: Documentation/devicetree/bindings/powerpc/fsl/ From 65de8bb2b7d0d4f5ac3a54aa1f16d36320a4b6ab Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 25 Feb 2020 20:25:34 +1100 Subject: [PATCH 608/809] powerpc: Switch 8xx MAINTAINERS entry to Christophe It's over 10 years since the last commit from Vitaly, so I suspect he's moved on to other things. Christophe has been the primary contributor to 8xx in the last several years, so anoint him as the maintainer. Remove the dead penguingppc.org link. Signed-off-by: Michael Ellerman Acked-by: Christophe Leroy Link: https://lore.kernel.org/r/20200225092534.9587-1-mpe@ellerman.id.au --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 167f99bc6a3b..dad68253cc4a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9657,8 +9657,7 @@ F: arch/powerpc/platforms/85xx/ F: Documentation/devicetree/bindings/powerpc/fsl/ LINUX FOR POWERPC EMBEDDED PPC8XX -M: Vitaly Bordug -W: http://www.penguinppc.org/ +M: Christophe Leroy L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/8xx/ From 4b4d181d63518334070a877ba789211bde77da9e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 13 Mar 2020 22:20:19 +1100 Subject: [PATCH 609/809] powerpc/smp: Drop superfluous NULL check We don't need the NULL check of np, the result is the same because the OF helpers cope with NULL, of_node_to_nid(NULL) == NUMA_NO_NODE (-1). Signed-off-by: Michael Ellerman Reviewed-by: Srikar Dronamraju Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200313112020.28235-1-mpe@ellerman.id.au --- arch/powerpc/kernel/smp.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 37c12e3bab9e..aae61a3b3201 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1197,11 +1197,8 @@ int get_physical_package_id(int cpu) */ if (pkg_id == -1 && firmware_has_feature(FW_FEATURE_LPAR)) { struct device_node *np = of_get_cpu_node(cpu, NULL); - - if (np) { - pkg_id = of_node_to_nid(np); - of_node_put(np); - } + pkg_id = of_node_to_nid(np); + of_node_put(np); } #endif /* CONFIG_PPC_SPLPAR */ From c72e8da06250390bb7759399a32fa0ab6f84e6d1 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 13 Mar 2020 22:20:20 +1100 Subject: [PATCH 610/809] powerpc/smp: Use IS_ENABLED() to avoid #ifdef We can avoid the #ifdef by using IS_ENABLED() in the existing condition check. Signed-off-by: Michael Ellerman Reviewed-by: Srikar Dronamraju Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200313112020.28235-2-mpe@ellerman.id.au --- arch/powerpc/kernel/smp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index aae61a3b3201..6d2a3a3666f0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1189,18 +1189,17 @@ int get_physical_package_id(int cpu) { int pkg_id = cpu_to_chip_id(cpu); -#ifdef CONFIG_PPC_SPLPAR /* * If the platform is PowerNV or Guest on KVM, ibm,chip-id is * defined. Hence we would return the chip-id as the result of * get_physical_package_id. */ - if (pkg_id == -1 && firmware_has_feature(FW_FEATURE_LPAR)) { + if (pkg_id == -1 && firmware_has_feature(FW_FEATURE_LPAR) && + IS_ENABLED(CONFIG_PPC_SPLPAR)) { struct device_node *np = of_get_cpu_node(cpu, NULL); pkg_id = of_node_to_nid(np); of_node_put(np); } -#endif /* CONFIG_PPC_SPLPAR */ return pkg_id; } From f1eec3b0d0a849996ebee733b053efa71803dad5 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 16 Mar 2020 15:00:38 +0530 Subject: [PATCH 611/809] ext4: check for non-zero journal inum in ext4_calculate_overhead While calculating overhead for internal journal, also check that j_inum shouldn't be 0. Otherwise we get below error with xfstests generic/050 with external journal (XXX_LOGDEV config) enabled. It could be simply reproduced with loop device with an external journal and marking blockdev as RO before mounting. [ 3337.146838] EXT4-fs error (device pmem1p2): ext4_get_journal_inode:4634: comm mount: inode #0: comm mount: iget: illegal inode # ------------[ cut here ]------------ generic_make_request: Trying to write to read-only block-device pmem1p2 (partno 2) WARNING: CPU: 107 PID: 115347 at block/blk-core.c:788 generic_make_request_checks+0x6b4/0x7d0 CPU: 107 PID: 115347 Comm: mount Tainted: G L --------- -t - 4.18.0-167.el8.ppc64le #1 NIP: c0000000006f6d44 LR: c0000000006f6d40 CTR: 0000000030041dd4 <...> NIP [c0000000006f6d44] generic_make_request_checks+0x6b4/0x7d0 LR [c0000000006f6d40] generic_make_request_checks+0x6b0/0x7d0 <...> Call Trace: generic_make_request_checks+0x6b0/0x7d0 (unreliable) generic_make_request+0x3c/0x420 submit_bio+0xd8/0x200 submit_bh_wbc+0x1e8/0x250 __sync_dirty_buffer+0xd0/0x210 ext4_commit_super+0x310/0x420 [ext4] __ext4_error+0xa4/0x1e0 [ext4] __ext4_iget+0x388/0xe10 [ext4] ext4_get_journal_inode+0x40/0x150 [ext4] ext4_calculate_overhead+0x5a8/0x610 [ext4] ext4_fill_super+0x3188/0x3260 [ext4] mount_bdev+0x778/0x8f0 ext4_mount+0x28/0x50 [ext4] mount_fs+0x74/0x230 vfs_kern_mount.part.6+0x6c/0x250 do_mount+0x2fc/0x1280 sys_mount+0x158/0x180 system_call+0x5c/0x70 EXT4-fs (pmem1p2): no journal found EXT4-fs (pmem1p2): can't get journal size EXT4-fs (pmem1p2): mounted filesystem without journal. Opts: dax,norecovery Fixes: 3c816ded78bb ("ext4: use journal inode to determine journal overhead") Reported-by: Harish Sriram Signed-off-by: Ritesh Harjani Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/20200316093038.25485-1-riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index de5398c07161..5dc65b7583cb 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3609,7 +3609,8 @@ int ext4_calculate_overhead(struct super_block *sb) */ if (sbi->s_journal && !sbi->journal_bdev) overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_maxlen); - else if (ext4_has_feature_journal(sb) && !sbi->s_journal) { + else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) { + /* j_inum for internal journal is non-zero */ j_inode = ext4_get_journal_inode(sb, j_inum); if (j_inode) { j_blocks = j_inode->i_size >> sb->s_blocksize_bits; From 5e47868fb94b63c7068dcfd2469d99fba06bae9d Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 18 Mar 2020 11:43:01 +0530 Subject: [PATCH 612/809] ext4: unregister sysfs path before destroying jbd2 journal Call ext4_unregister_sysfs(), before destroying jbd2 journal, since below might cause, NULL pointer dereference issue. This got reported with LTP tests. ext4_put_super() cat /sys/fs/ext4/loop2/journal_task | ext4_attr_show(); ext4_jbd2_journal_destroy(); | | journal_task_show() | | | task_pid_vnr(NULL); sbi->s_journal = NULL; Signed-off-by: Ritesh Harjani Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/20200318061301.4320-1-riteshh@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 5dc65b7583cb..27ab130a40d1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1024,6 +1024,13 @@ static void ext4_put_super(struct super_block *sb) destroy_workqueue(sbi->rsv_conversion_wq); + /* + * Unregister sysfs before destroying jbd2 journal. + * Since we could still access attr_journal_task attribute via sysfs + * path which could have sbi->s_journal->j_task as NULL + */ + ext4_unregister_sysfs(sb); + if (sbi->s_journal) { aborted = is_journal_aborted(sbi->s_journal); err = jbd2_journal_destroy(sbi->s_journal); @@ -1034,7 +1041,6 @@ static void ext4_put_super(struct super_block *sb) } } - ext4_unregister_sysfs(sb); ext4_es_unregister_shrinker(sbi); del_timer_sync(&sbi->s_err_report); ext4_release_system_zone(sb); From d05466b27b19af8e148376590ed54d289b607f0a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 18 Mar 2020 13:13:17 +0100 Subject: [PATCH 613/809] ext4: avoid ENOSPC when avoiding to reuse recently deleted inodes When ext4 is running on a filesystem without a journal, it tries not to reuse recently deleted inodes to provide better chances for filesystem recovery in case of crash. However this logic forbids reuse of freed inodes for up to 5 minutes and especially for filesystems with smaller number of inodes can lead to ENOSPC errors returned when allocating new inodes. Fix the problem by allowing to reuse recently deleted inode if there's no other inode free in the scanned range. Signed-off-by: Jan Kara Link: https://lore.kernel.org/r/20200318121317.31941-1-jack@suse.cz Signed-off-by: Theodore Ts'o --- fs/ext4/ialloc.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index f95ee99091e4..9652a0eadd1c 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -712,21 +712,34 @@ out: static int find_inode_bit(struct super_block *sb, ext4_group_t group, struct buffer_head *bitmap, unsigned long *ino) { + bool check_recently_deleted = EXT4_SB(sb)->s_journal == NULL; + unsigned long recently_deleted_ino = EXT4_INODES_PER_GROUP(sb); + next: *ino = ext4_find_next_zero_bit((unsigned long *) bitmap->b_data, EXT4_INODES_PER_GROUP(sb), *ino); if (*ino >= EXT4_INODES_PER_GROUP(sb)) - return 0; + goto not_found; - if ((EXT4_SB(sb)->s_journal == NULL) && - recently_deleted(sb, group, *ino)) { + if (check_recently_deleted && recently_deleted(sb, group, *ino)) { + recently_deleted_ino = *ino; *ino = *ino + 1; if (*ino < EXT4_INODES_PER_GROUP(sb)) goto next; - return 0; + goto not_found; } - + return 1; +not_found: + if (recently_deleted_ino >= EXT4_INODES_PER_GROUP(sb)) + return 0; + /* + * Not reusing recently deleted inodes is mostly a preference. We don't + * want to report ENOSPC or skew allocation patterns because of that. + * So return even recently deleted inode if we could find better in the + * given range. + */ + *ino = recently_deleted_ino; return 1; } From c96e2b8564adfb8ac14469ebc51ddc1bfecb3ae2 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 18 Mar 2020 14:19:38 -0500 Subject: [PATCH 614/809] ext4: do not commit super on read-only bdev Under some circumstances we may encounter a filesystem error on a read-only block device, and if we try to save the error info to the superblock and commit it, we'll wind up with a noisy error and backtrace, i.e.: [ 3337.146838] EXT4-fs error (device pmem1p2): ext4_get_journal_inode:4634: comm mount: inode #0: comm mount: iget: illegal inode # ------------[ cut here ]------------ generic_make_request: Trying to write to read-only block-device pmem1p2 (partno 2) WARNING: CPU: 107 PID: 115347 at block/blk-core.c:788 generic_make_request_checks+0x6b4/0x7d0 ... To avoid this, commit the error info in the superblock only if the block device is writable. Reported-by: Ritesh Harjani Signed-off-by: Eric Sandeen Reviewed-by: Andreas Dilger Link: https://lore.kernel.org/r/4b6e774d-cc00-3469-7abb-108eb151071a@sandeen.net Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 27ab130a40d1..4d460747cca7 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -372,7 +372,8 @@ static void save_error_info(struct super_block *sb, const char *func, unsigned int line) { __save_error_info(sb, func, line); - ext4_commit_super(sb, 1); + if (!bdev_read_only(sb->s_bdev)) + ext4_commit_super(sb, 1); } /* From c8980e1980ccdc2229aa2218d532ddc62e0aabe5 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Thu, 19 Mar 2020 11:00:28 -0400 Subject: [PATCH 615/809] ext4: disable dioread_nolock whenever delayed allocation is disabled The patch "ext4: make dioread_nolock the default" (244adf6426ee) causes generic/422 to fail when run in kvm-xfstests' ext3conv test case. This applies both the dioread_nolock and nodelalloc mount options, a combination not previously tested by kvm-xfstests. The failure occurs because the dioread_nolock code path splits a previously fallocated multiblock extent into a series of single block extents when overwriting a portion of that extent. That causes allocation of an extent tree leaf node and a reshuffling of extents. Once writeback is completed, the individual extents are recombined into a single extent, the extent is moved again, and the leaf node is deleted. The difference in block utilization before and after writeback due to the leaf node triggers the failure. The original reason for this behavior was to avoid ENOSPC when handling I/O completions during writeback in the dioread_nolock code paths when delayed allocation is disabled. It may no longer be necessary, because code was added in the past to reserve extra space to solve this problem when delayed allocation is enabled, and this code may also apply when delayed allocation is disabled. Until this can be verified, don't use the dioread_nolock code paths if delayed allocation is disabled. Signed-off-by: Eric Whitney Link: https://lore.kernel.org/r/20200319150028.24592-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o --- fs/ext4/ext4_jbd2.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index 7ea4f6fa173b..4b9002f0e84c 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h @@ -512,6 +512,9 @@ static inline int ext4_should_dioread_nolock(struct inode *inode) return 0; if (ext4_should_journal_data(inode)) return 0; + /* temporary fix to prevent generic/422 test failures */ + if (!test_opt(inode->i_sb, DELALLOC)) + return 0; return 1; } From a00ec3874e7d326ab2dffbed92faddf6a77a84e9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 26 Mar 2020 20:24:35 +0100 Subject: [PATCH 616/809] cpufreq: intel_pstate: Select schedutil as the default governor Modify cpufreq Kconfig to select schedutil as the default governor if the intel_pstate driver has been selected and SMP support is enabled (because schedutil depends on SMP). Also select schedutil as well as the performance governor from the intel_pstate Kconfig section to ensure the equivalence of the passive and active mode governor configuration options. Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig | 3 ++- drivers/cpufreq/Kconfig.x86 | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index bff5295016ae..9f0e7e79ed14 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -37,10 +37,11 @@ config CPU_FREQ_STAT choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ + default CPU_FREQ_DEFAULT_GOV_SCHEDUTIL if X86_INTEL_PSTATE && SMP default CPU_FREQ_DEFAULT_GOV_PERFORMANCE help This option sets which CPUFreq governor shall be loaded at - startup. If in doubt, select 'performance'. + startup. If in doubt, use the default setting. config CPU_FREQ_DEFAULT_GOV_PERFORMANCE bool "performance" diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index a6528388952e..758c69a2e1bf 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -8,6 +8,8 @@ config X86_INTEL_PSTATE depends on X86 select ACPI_PROCESSOR if ACPI select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO + select CPU_FREQ_GOV_PERFORMANCE + select CPU_FREQ_GOV_SCHEDUTIL if SMP help This driver provides a P state for Intel core processors. The driver implements an internal governor and will become From b0efe0281234e60c7c4f5fa812712fca50bec1b7 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Tue, 24 Mar 2020 05:12:09 +0100 Subject: [PATCH 617/809] rtc: make definitions in include/uapi/linux/rtc.h actually useful for user space BIT() macro is not defined in UAPI headers; there is, however, similarly defined _BITUL() macro present in include/uapi/linux/const.h; use it instead and include and in order to make the definitions provided in the header useful. Fixes: 3431ca4837bf ("rtc: define RTC_VL_READ values") Signed-off-by: Eugene Syromiatnikov Link: https://lore.kernel.org/r/20200324041209.GA30727@asgard.redhat.com Signed-off-by: Alexandre Belloni --- include/uapi/linux/rtc.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index 095af360326a..83bba58d47f4 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -12,6 +12,9 @@ #ifndef _UAPI_LINUX_RTC_H_ #define _UAPI_LINUX_RTC_H_ +#include +#include + /* * The struct used to pass data via the following ioctl. Similar to the * struct tm in , but it needs to be here so that the kernel @@ -92,10 +95,10 @@ struct rtc_pll_info { #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ -#define RTC_VL_DATA_INVALID BIT(0) /* Voltage too low, RTC data is invalid */ -#define RTC_VL_BACKUP_LOW BIT(1) /* Backup voltage is low */ -#define RTC_VL_BACKUP_EMPTY BIT(2) /* Backup empty or not present */ -#define RTC_VL_ACCURACY_LOW BIT(3) /* Voltage is low, RTC accuracy is reduced */ +#define RTC_VL_DATA_INVALID _BITUL(0) /* Voltage too low, RTC data is invalid */ +#define RTC_VL_BACKUP_LOW _BITUL(1) /* Backup voltage is low */ +#define RTC_VL_BACKUP_EMPTY _BITUL(2) /* Backup empty or not present */ +#define RTC_VL_ACCURACY_LOW _BITUL(3) /* Voltage is low, RTC accuracy is reduced */ #define RTC_VL_READ _IOR('p', 0x13, unsigned int) /* Voltage low detection */ #define RTC_VL_CLR _IO('p', 0x14) /* Clear voltage low information */ From da3f594737cfa24c44769ff17ce2643f85eb0ef5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 24 Mar 2020 14:56:46 +0100 Subject: [PATCH 618/809] ARM: integrator: impd1: Use GPIO_LOOKUP() helper macro impd1_probe() fills in the GPIO lookup table by manually populating an array of gpiod_lookup structures. Use the existing GPIO_LOOKUP() helper macro instead, to relax a dependency on the gpiod_lookup structure's member names. Signed-off-by: Geert Uytterhoeven Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20200324135653.6676-1-geert+renesas@glider.be Signed-off-by: Linus Walleij --- arch/arm/mach-integrator/impd1.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 1ecbea5331d6..6f875ded8419 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -410,13 +410,10 @@ static int __ref impd1_probe(struct lm_device *dev) * 5 = Key lower right */ /* We need the two MMCI GPIO entries */ - lookup->table[0].chip_label = chipname; - lookup->table[0].chip_hwnum = 3; - lookup->table[0].con_id = "wp"; - lookup->table[1].chip_label = chipname; - lookup->table[1].chip_hwnum = 4; - lookup->table[1].con_id = "cd"; - lookup->table[1].flags = GPIO_ACTIVE_LOW; + lookup->table[0] = (struct gpiod_lookup) + GPIO_LOOKUP(chipname, 3, "wp", 0); + lookup->table[1] = (struct gpiod_lookup) + GPIO_LOOKUP(chipname, 4, "cd", GPIO_ACTIVE_LOW); gpiod_add_lookup_table(lookup); } From 8c229ab6048b796aa8197d64eb2f9182d828ff61 Mon Sep 17 00:00:00 2001 From: Michael McCormick Date: Fri, 24 Jan 2020 14:52:38 +1300 Subject: [PATCH 619/809] rtc: pcf85063: Add pcf85063 clkout control to common clock framework The PCF85063 has a configurable clock output signal. Add support for it using in the CCF. Signed-off-by: Michael McCormick Link: https://lore.kernel.org/r/20200124015239.24662-1-michael.mccormick@enatel.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 1db17ba1fc64..7a87f461bec8 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -9,6 +9,7 @@ * Copyright (C) 2019 Micro Crystal AG * Author: Alexandre Belloni */ +#include #include #include #include @@ -44,6 +45,10 @@ #define PCF85063_OFFSET_STEP0 4340 #define PCF85063_OFFSET_STEP1 4069 +#define PCF85063_REG_CLKO_F_MASK 0x07 /* frequency mask */ +#define PCF85063_REG_CLKO_F_32768HZ 0x00 +#define PCF85063_REG_CLKO_F_OFF 0x07 + #define PCF85063_REG_RAM 0x03 #define PCF85063_REG_SC 0x04 /* datetime */ @@ -61,6 +66,9 @@ struct pcf85063_config { struct pcf85063 { struct rtc_device *rtc; struct regmap *regmap; +#ifdef CONFIG_COMMON_CLK + struct clk_hw clkout_hw; +#endif }; static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -357,6 +365,150 @@ static int pcf85063_load_capacitance(struct pcf85063 *pcf85063, PCF85063_REG_CTRL1_CAP_SEL, reg); } +#ifdef CONFIG_COMMON_CLK +/* + * Handling of the clkout + */ + +#define clkout_hw_to_pcf85063(_hw) container_of(_hw, struct pcf85063, clkout_hw) + +static int clkout_rates[] = { + 32768, + 16384, + 8192, + 4096, + 2048, + 1024, + 1, + 0 +}; + +static unsigned long pcf85063_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw); + unsigned int buf; + int ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf); + + if (ret < 0) + return 0; + + buf &= PCF85063_REG_CLKO_F_MASK; + return clkout_rates[buf]; +} + +static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] <= rate) + return clkout_rates[i]; + + return 0; +} + +static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw); + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] == rate) + return regmap_update_bits(pcf85063->regmap, + PCF85063_REG_CTRL2, + PCF85063_REG_CLKO_F_MASK, i); + + return -EINVAL; +} + +static int pcf85063_clkout_control(struct clk_hw *hw, bool enable) +{ + struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw); + unsigned int buf; + int ret; + + ret = regmap_read(pcf85063->regmap, PCF85063_REG_OFFSET, &buf); + if (ret < 0) + return ret; + buf &= PCF85063_REG_CLKO_F_MASK; + + if (enable) { + if (buf == PCF85063_REG_CLKO_F_OFF) + buf = PCF85063_REG_CLKO_F_32768HZ; + else + return 0; + } else { + if (buf != PCF85063_REG_CLKO_F_OFF) + buf = PCF85063_REG_CLKO_F_OFF; + else + return 0; + } + + return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2, + PCF85063_REG_CLKO_F_MASK, buf); +} + +static int pcf85063_clkout_prepare(struct clk_hw *hw) +{ + return pcf85063_clkout_control(hw, 1); +} + +static void pcf85063_clkout_unprepare(struct clk_hw *hw) +{ + pcf85063_clkout_control(hw, 0); +} + +static int pcf85063_clkout_is_prepared(struct clk_hw *hw) +{ + struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw); + unsigned int buf; + int ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf); + + if (ret < 0) + return 0; + + return (buf & PCF85063_REG_CLKO_F_MASK) != PCF85063_REG_CLKO_F_OFF; +} + +static const struct clk_ops pcf85063_clkout_ops = { + .prepare = pcf85063_clkout_prepare, + .unprepare = pcf85063_clkout_unprepare, + .is_prepared = pcf85063_clkout_is_prepared, + .recalc_rate = pcf85063_clkout_recalc_rate, + .round_rate = pcf85063_clkout_round_rate, + .set_rate = pcf85063_clkout_set_rate, +}; + +static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) +{ + struct clk *clk; + struct clk_init_data init; + + init.name = "pcf85063-clkout"; + init.ops = &pcf85063_clkout_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + pcf85063->clkout_hw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(pcf85063->rtc->dev.of_node, + "clock-output-names", &init.name); + + /* register the clock */ + clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw); + + if (!IS_ERR(clk)) + of_clk_add_provider(pcf85063->rtc->dev.of_node, + of_clk_src_simple_get, clk); + + return clk; +} +#endif + static const struct pcf85063_config pcf85063a_config = { .regmap = { .reg_bits = 8, @@ -457,6 +609,11 @@ static int pcf85063_probe(struct i2c_client *client) nvmem_cfg.priv = pcf85063->regmap; rtc_nvmem_register(pcf85063->rtc, &nvmem_cfg); +#ifdef CONFIG_COMMON_CLK + /* register clk in common clk framework */ + pcf85063_clkout_register_clk(pcf85063); +#endif + return rtc_register_device(pcf85063->rtc); } From efbc4303b255bb80ab1283794b36dd5fe1fb0ec3 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 27 Mar 2020 00:19:16 +0530 Subject: [PATCH 620/809] powerpc/pseries: Handle UE event for memcpy_mcsafe memcpy_mcsafe has been implemented for power machines which is used by pmem infrastructure, so that an UE encountered during memcpy from pmem devices would not result in panic instead a right error code is returned. The implementation expects machine check handler to ignore the event and set nip to continue the execution from fixup code. Appropriate changes are already made to powernv machine check handler, make similar changes to pseries machine check handler to ignore the the event and set nip to continue execution at the fixup entry if we hit UE at an instruction with a fixup entry. while we are at it, have a common function which searches the exception table entry and updates nip with fixup address, and any future common changes can be made in this function that are valid for both architectures. powernv changes are made by commit 895e3dceeb97 ("powerpc/mce: Handle UE event for memcpy_mcsafe") Reviewed-by: Mahesh Salgaonkar Reviewed-by: Santosh S Signed-off-by: Ganesh Goudar Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200326184916.31172-1-ganeshgr@linux.ibm.com --- arch/powerpc/include/asm/mce.h | 2 ++ arch/powerpc/kernel/mce.c | 14 ++++++++++++++ arch/powerpc/kernel/mce_power.c | 8 ++------ arch/powerpc/platforms/pseries/ras.c | 3 +++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h index 6a6ddaabdb34..376a395daf32 100644 --- a/arch/powerpc/include/asm/mce.h +++ b/arch/powerpc/include/asm/mce.h @@ -218,6 +218,8 @@ extern void machine_check_queue_event(void); extern void machine_check_print_event_info(struct machine_check_event *evt, bool user_mode, bool in_guest); unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr); +extern void mce_common_process_ue(struct pt_regs *regs, + struct mce_error_info *mce_err); #ifdef CONFIG_PPC_BOOK3S_64 void flush_and_reload_slb(void); #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index 34c1001e9e8b..8077b5fb18a7 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -251,6 +252,19 @@ void machine_check_queue_event(void) /* Queue irq work to process this event later. */ irq_work_queue(&mce_event_process_work); } + +void mce_common_process_ue(struct pt_regs *regs, + struct mce_error_info *mce_err) +{ + const struct exception_table_entry *entry; + + entry = search_kernel_exception_table(regs->nip); + if (entry) { + mce_err->ignore_event = true; + regs->nip = extable_fixup(entry); + } +} + /* * process pending MCE event from the mce event queue. This function will be * called during syscall exit. diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index 1cbf7f1a4e3d..067b094bfeff 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c @@ -579,14 +579,10 @@ static long mce_handle_ue_error(struct pt_regs *regs, struct mce_error_info *mce_err) { long handled = 0; - const struct exception_table_entry *entry; - entry = search_kernel_exception_table(regs->nip); - if (entry) { - mce_err->ignore_event = true; - regs->nip = extable_fixup(entry); + mce_common_process_ue(regs, mce_err); + if (mce_err->ignore_event) return 1; - } /* * On specific SCOM read via MMIO we may get a machine check diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 1d7f973c647b..aa6208c8d4f0 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -558,6 +558,9 @@ static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp) switch (mce_log->error_type) { case MC_ERROR_TYPE_UE: mce_err.error_type = MCE_ERROR_TYPE_UE; + mce_common_process_ue(regs, &mce_err); + if (mce_err.ignore_event) + disposition = RTAS_DISP_FULLY_RECOVERED; switch (err_sub_type) { case MC_ERROR_UE_IFETCH: mce_err.u.ue_error_type = MCE_UE_ERROR_IFETCH; From 968339fad422a58312f67718691b717dac45c399 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 25 Mar 2020 09:42:57 -0700 Subject: [PATCH 621/809] powerpc/boot: Delete unneeded .globl _zimage_start .globl sets the symbol binding to STB_GLOBAL while .weak sets the binding to STB_WEAK. GNU as let .weak override .globl since binutils-gdb 5ca547dc2399a0a5d9f20626d4bf5547c3ccfddd (1996). Clang integrated assembler let the last win but it may error in the future. Since it is a convention that only one binding directive is used, just delete .globl. Fixes: ee9d21b3b358 ("powerpc/boot: Ensure _zimage_start is a weak symbol") Signed-off-by: Fangrui Song Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200325164257.170229-1-maskray@google.com --- arch/powerpc/boot/crt0.S | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 92608f34d312..1d83966f5ef6 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -44,9 +44,6 @@ p_end: .long _end p_pstack: .long _platform_stack_top #endif - .globl _zimage_start - /* Clang appears to require the .weak directive to be after the symbol - * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921 */ .weak _zimage_start _zimage_start: .globl _zimage_start_lib From 1915253e356233ea0aabbe6a4960fba4d9db5085 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 26 Mar 2020 14:19:32 -0300 Subject: [PATCH 622/809] dt-bindings: imx8mq-clock: Fix the file path Currently the following warning is seen with 'make dt_binding_check': Documentation/devicetree/bindings/clock/imx8mq-clock.yaml: $id: relative path/filename doesn't match actual path or filename Fix it by removing the "bindings" directory from the file path. Signed-off-by: Fabio Estevam Link: https://lkml.kernel.org/r/20200326171933.13394-1-festevam@gmail.com Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/imx8mq-clock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml index 77790f0fdcd3..05d7d1471e0c 100644 --- a/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/bindings/clock/imx8mq-clock.yaml# +$id: http://devicetree.org/schemas/clock/imx8mq-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: NXP i.MX8M Quad Clock Control Module Binding From a8b4543093930724876ed892136151b4bb0ee6e0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 26 Mar 2020 14:19:33 -0300 Subject: [PATCH 623/809] dt-bindings: imx8mm-clock: Fix the file path Currently the following warning is seen with 'make dt_binding_check': Documentation/devicetree/bindings/clock/imx8mm-clock.yaml: $id: relative path/filename doesn't match actual path or filename Fix it by removing the "bindings" directory from the file path. Signed-off-by: Fabio Estevam Link: https://lkml.kernel.org/r/20200326171933.13394-2-festevam@gmail.com Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/imx8mm-clock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml index f5be181bd21d..ec830db1367b 100644 --- a/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx8mm-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/bindings/clock/imx8mm-clock.yaml# +$id: http://devicetree.org/schemas/clock/imx8mm-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: NXP i.MX8M Mini Clock Control Module Binding From 233ba5461838a56c19600216f0919e7cd3aec40e Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Fri, 20 Mar 2020 16:02:42 +0530 Subject: [PATCH 624/809] powerpc/64: Avoid isync in flush_dcache_range() As per ISA an isync is only needed on instruction cache block invalidate. Remove the same from dcache invalidate. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200320103242.229223-1-aneesh.kumar@linux.ibm.com --- arch/powerpc/include/asm/cacheflush.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 4a1c9f0200e1..e92191b390f3 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -65,17 +65,13 @@ static inline void flush_dcache_range(unsigned long start, unsigned long stop) unsigned long size = stop - (unsigned long)addr + (bytes - 1); unsigned long i; - if (IS_ENABLED(CONFIG_PPC64)) { + if (IS_ENABLED(CONFIG_PPC64)) mb(); /* sync */ - isync(); - } for (i = 0; i < size >> shift; i++, addr += bytes) dcbf(addr); mb(); /* sync */ - if (IS_ENABLED(CONFIG_PPC64)) - isync(); } /* From 194f75706b86847d1b4237958f7d6bd7ea7baf42 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 20 Mar 2020 09:19:14 +0100 Subject: [PATCH 625/809] s390/ism: remove pm support As s390 no longer supports ARCH_HIBERNATION_POSSIBLE, drop the unused pm ops from the ism driver. Signed-off-by: Ursula Braun Signed-off-by: Vasily Gorbik --- drivers/s390/net/ism_drv.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 4fc2056bd227..c75112ee7b97 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -567,31 +567,11 @@ static void ism_remove(struct pci_dev *pdev) kfree(ism); } -static int ism_suspend(struct device *dev) -{ - struct ism_dev *ism = dev_get_drvdata(dev); - - ism_dev_exit(ism); - return 0; -} - -static int ism_resume(struct device *dev) -{ - struct ism_dev *ism = dev_get_drvdata(dev); - - return ism_dev_init(ism); -} - -static SIMPLE_DEV_PM_OPS(ism_pm_ops, ism_suspend, ism_resume); - static struct pci_driver ism_driver = { .name = DRV_NAME, .id_table = ism_device_table, .probe = ism_probe, .remove = ism_remove, - .driver = { - .pm = &ism_pm_ops, - }, }; static int __init ism_init(void) From 712fa5f294f377ee3103c36c178e7d62c65dd108 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 23 Mar 2020 09:38:37 +0100 Subject: [PATCH 626/809] s390/mm: cleanup arch_get_unmapped_area() and friends Factor out check_asce_limit() function and fix few style defects in arch_get_unmapped_area() family of functions. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens [heiko.carstens@de.ibm.com: small coding style changes] Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pgalloc.h | 14 ++++++++++++ arch/s390/mm/hugetlbpage.c | 11 ++------- arch/s390/mm/mmap.c | 40 +++++++++------------------------ 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 77606c4acd58..f0d7457fa1da 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -48,6 +48,20 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) int crst_table_upgrade(struct mm_struct *mm, unsigned long limit); void crst_table_downgrade(struct mm_struct *); +static inline unsigned long check_asce_limit(struct mm_struct *mm, unsigned long addr, + unsigned long len) +{ + int rc; + + if (addr + len > mm->context.asce_limit && + addr + len <= TASK_SIZE) { + rc = crst_table_upgrade(mm, addr + len); + if (rc) + return (unsigned long) rc; + } + return addr; +} + static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long address) { unsigned long *table = crst_table_alloc(mm); diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 5674710a4841..f01daddcbc5e 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -326,7 +326,6 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, struct hstate *h = hstate_file(file); struct mm_struct *mm = current->mm; struct vm_area_struct *vma; - int rc; if (len & ~huge_page_mask(h)) return -EINVAL; @@ -353,15 +352,9 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, else addr = hugetlb_get_unmapped_area_topdown(file, addr, len, pgoff, flags); - if (addr & ~PAGE_MASK) + if (offset_in_page(addr)) return addr; check_asce_limit: - if (addr + len > current->mm->context.asce_limit && - addr + len <= TASK_SIZE) { - rc = crst_table_upgrade(mm, addr + len); - if (rc) - return (unsigned long) rc; - } - return addr; + return check_asce_limit(mm, addr, len); } diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index cbc718ba6d78..1b78f630a9ca 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -72,14 +72,13 @@ static inline unsigned long mmap_base(unsigned long rnd, return PAGE_ALIGN(STACK_TOP - gap - rnd); } -unsigned long -arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; struct vm_unmapped_area_info info; - int rc; if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; @@ -105,30 +104,20 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, info.align_mask = 0; info.align_offset = pgoff << PAGE_SHIFT; addr = vm_unmapped_area(&info); - if (addr & ~PAGE_MASK) + if (offset_in_page(addr)) return addr; check_asce_limit: - if (addr + len > current->mm->context.asce_limit && - addr + len <= TASK_SIZE) { - rc = crst_table_upgrade(mm, addr + len); - if (rc) - return (unsigned long) rc; - } - - return addr; + return check_asce_limit(mm, addr, len); } -unsigned long -arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - const unsigned long len, const unsigned long pgoff, - const unsigned long flags) +unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; - unsigned long addr = addr0; struct vm_unmapped_area_info info; - int rc; /* requested length too big for entire address space */ if (len > TASK_SIZE - mmap_min_addr) @@ -163,25 +152,18 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, * can happen with large stack limits and large mmap() * allocations. */ - if (addr & ~PAGE_MASK) { + if (offset_in_page(addr)) { VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; info.high_limit = TASK_SIZE; addr = vm_unmapped_area(&info); - if (addr & ~PAGE_MASK) + if (offset_in_page(addr)) return addr; } check_asce_limit: - if (addr + len > current->mm->context.asce_limit && - addr + len <= TASK_SIZE) { - rc = crst_table_upgrade(mm, addr + len); - if (rc) - return (unsigned long) rc; - } - - return addr; + return check_asce_limit(mm, addr, len); } /* From 34515df25d7e5ae19f66eadfb1351a3178344f36 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Mon, 23 Mar 2020 14:32:04 +0100 Subject: [PATCH 627/809] s390/zcrypt: use kvmalloc instead of kmalloc for 256k alloc Tests showed that it may happen that a 256k kmalloc may fail due to a temporary shortage on 256k slab entries. The find functions for cca and ep11 use a 256k array to fetch the states of all possible crypto cards and their domains in one piece. With the patch now kvmalloc is used to allocate this temporary memory as there is no need to have this memory area physical continuously. Signed-off-by: Harald Freudenberger Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 8 ++++---- drivers/s390/crypto/zcrypt_ep11misc.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index e6899107c586..1b835398feec 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -1569,9 +1569,9 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, return -EINVAL; /* fetch status of all crypto cards */ - device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, - sizeof(struct zcrypt_device_status_ext), - GFP_KERNEL); + device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); if (!device_status) return -ENOMEM; zcrypt_device_status_mask_ext(device_status); @@ -1641,7 +1641,7 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, } else rc = -ENODEV; - kfree(device_status); + kvfree(device_status); return rc; } diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c index d4caf46ff9df..7dd987afcd55 100644 --- a/drivers/s390/crypto/zcrypt_ep11misc.c +++ b/drivers/s390/crypto/zcrypt_ep11misc.c @@ -1217,9 +1217,9 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, struct ep11_card_info eci; /* fetch status of all crypto cards */ - device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, - sizeof(struct zcrypt_device_status_ext), - GFP_KERNEL); + device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); if (!device_status) return -ENOMEM; zcrypt_device_status_mask_ext(device_status); @@ -1227,7 +1227,7 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, /* allocate 1k space for up to 256 apqns */ _apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL); if (!_apqns) { - kfree(device_status); + kvfree(device_status); return -ENOMEM; } @@ -1282,7 +1282,7 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, rc = 0; } - kfree(device_status); + kvfree(device_status); return rc; } EXPORT_SYMBOL(ep11_findcard2); From 41677b1d9415f5512acf262c55bd48f71319ce29 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 24 Mar 2020 17:30:39 +0100 Subject: [PATCH 628/809] s390/ap: remove power management code from ap bus and drivers The s390 power management support has been removed. So the api registration and the suspend and resume callbacks and all the code related to this for the ap bus and the ap drivers is removed with this patch. Signed-off-by: Harald Freudenberger Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.c | 117 ++--------------------------- drivers/s390/crypto/ap_bus.h | 5 -- drivers/s390/crypto/ap_queue.c | 51 ------------- drivers/s390/crypto/zcrypt_cex2a.c | 2 - drivers/s390/crypto/zcrypt_cex2c.c | 2 - drivers/s390/crypto/zcrypt_cex4.c | 2 - 6 files changed, 5 insertions(+), 174 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index c413211c6116..35064443e748 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -18,13 +18,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -103,16 +103,9 @@ static struct hrtimer ap_poll_timer; */ static unsigned long long poll_timeout = 250000; -/* Suspend flag */ -static int ap_suspend_flag; /* Maximum domain id */ static int ap_max_domain_id; -/* - * Flag to check if domain was set through module parameter domain=. This is - * important when supsend and resume is done in a z/VM environment where the - * domain might change. - */ -static int user_set_domain; + static struct bus_type ap_bus_type; /* Adapter interrupt definitions */ @@ -386,8 +379,6 @@ void ap_request_timeout(struct timer_list *t) { struct ap_queue *aq = from_timer(aq, t, timeout); - if (ap_suspend_flag) - return; spin_lock_bh(&aq->lock); ap_wait(ap_sm_event(aq, AP_EVENT_TIMEOUT)); spin_unlock_bh(&aq->lock); @@ -401,8 +392,7 @@ void ap_request_timeout(struct timer_list *t) */ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) { - if (!ap_suspend_flag) - tasklet_schedule(&ap_tasklet); + tasklet_schedule(&ap_tasklet); return HRTIMER_NORESTART; } @@ -413,8 +403,7 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) static void ap_interrupt_handler(struct airq_struct *airq, bool floating) { inc_irq_stat(IRQIO_APB); - if (!ap_suspend_flag) - tasklet_schedule(&ap_tasklet); + tasklet_schedule(&ap_tasklet); } /** @@ -486,7 +475,7 @@ static int ap_poll_thread(void *data) while (!kthread_should_stop()) { add_wait_queue(&ap_poll_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - if (ap_suspend_flag || !ap_pending_requests()) { + if (!ap_pending_requests()) { schedule(); try_to_freeze(); } @@ -587,33 +576,6 @@ static int ap_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } -static void ap_bus_suspend(void) -{ - AP_DBF(DBF_DEBUG, "%s running\n", __func__); - - ap_suspend_flag = 1; - /* - * Disable scanning for devices, thus we do not want to scan - * for them after removing. - */ - flush_work(&ap_scan_work); - tasklet_disable(&ap_tasklet); -} - -static int __ap_card_devices_unregister(struct device *dev, void *dummy) -{ - if (is_card_dev(dev)) - device_unregister(dev); - return 0; -} - -static int __ap_queue_devices_unregister(struct device *dev, void *dummy) -{ - if (is_queue_dev(dev)) - device_unregister(dev); - return 0; -} - static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) { if (is_queue_dev(dev) && @@ -622,60 +584,6 @@ static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) return 0; } -static void ap_bus_resume(void) -{ - int rc; - - AP_DBF(DBF_DEBUG, "%s running\n", __func__); - - /* remove all queue devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, - __ap_queue_devices_unregister); - /* remove all card devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, - __ap_card_devices_unregister); - - /* Reset thin interrupt setting */ - if (ap_interrupts_available() && !ap_using_interrupts()) { - rc = register_adapter_interrupt(&ap_airq); - ap_airq_flag = (rc == 0); - } - if (!ap_interrupts_available() && ap_using_interrupts()) { - unregister_adapter_interrupt(&ap_airq); - ap_airq_flag = 0; - } - /* Reset domain */ - if (!user_set_domain) - ap_domain_index = -1; - /* Get things going again */ - ap_suspend_flag = 0; - if (ap_airq_flag) - xchg(ap_airq.lsi_ptr, 0); - tasklet_enable(&ap_tasklet); - queue_work(system_long_wq, &ap_scan_work); -} - -static int ap_power_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - switch (event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - ap_bus_suspend(); - break; - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - ap_bus_resume(); - break; - default: - break; - } - return NOTIFY_DONE; -} -static struct notifier_block ap_power_notifier = { - .notifier_call = ap_power_event, -}; - static struct bus_type ap_bus_type = { .name = "ap", .match = &ap_bus_match, @@ -852,8 +760,6 @@ EXPORT_SYMBOL(ap_driver_unregister); void ap_bus_force_rescan(void) { - if (ap_suspend_flag) - return; /* processing a asynchronous bus rescan */ del_timer(&ap_config_timer); queue_work(system_long_wq, &ap_scan_work); @@ -1546,8 +1452,6 @@ static void ap_scan_bus(struct work_struct *unused) static void ap_config_timeout(struct timer_list *unused) { - if (ap_suspend_flag) - return; queue_work(system_long_wq, &ap_scan_work); } @@ -1620,11 +1524,6 @@ static int __init ap_module_init(void) ap_domain_index); ap_domain_index = -1; } - /* In resume callback we need to know if the user had set the domain. - * If so, we can not just reset it. - */ - if (ap_domain_index >= 0) - user_set_domain = 1; if (ap_interrupts_available()) { rc = register_adapter_interrupt(&ap_airq); @@ -1667,17 +1566,11 @@ static int __init ap_module_init(void) goto out_work; } - rc = register_pm_notifier(&ap_power_notifier); - if (rc) - goto out_pm; - queue_work(system_long_wq, &ap_scan_work); initialised = true; return 0; -out_pm: - ap_poll_thread_stop(); out_work: hrtimer_cancel(&ap_poll_timer); root_device_unregister(ap_root_device); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 4348fdff1c61..8e8e37b6c0ee 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -91,7 +91,6 @@ enum ap_state { AP_STATE_IDLE, AP_STATE_WORKING, AP_STATE_QUEUE_FULL, - AP_STATE_SUSPEND_WAIT, AP_STATE_REMOVE, /* about to be removed from driver */ AP_STATE_UNBOUND, /* momentary not bound to a driver */ AP_STATE_BORKED, /* broken */ @@ -136,8 +135,6 @@ struct ap_driver { int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); - void (*suspend)(struct ap_device *); - void (*resume)(struct ap_device *); }; #define to_ap_drv(x) container_of((x), struct ap_driver, driver) @@ -259,8 +256,6 @@ void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg); struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type); void ap_queue_prepare_remove(struct ap_queue *aq); void ap_queue_remove(struct ap_queue *aq); -void ap_queue_suspend(struct ap_device *ap_dev); -void ap_queue_resume(struct ap_device *ap_dev); void ap_queue_init_state(struct ap_queue *aq); struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 9cb997cffa61..0eaf1d04e8df 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -200,31 +200,6 @@ static enum ap_wait ap_sm_read(struct ap_queue *aq) } } -/** - * ap_sm_suspend_read(): Receive pending reply messages from an AP queue - * without changing the device state in between. In suspend mode we don't - * allow sending new requests, therefore just fetch pending replies. - * @aq: pointer to the AP queue - * - * Returns AP_WAIT_NONE or AP_WAIT_AGAIN - */ -static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq) -{ - struct ap_queue_status status; - - if (!aq->reply) - return AP_WAIT_NONE; - status = ap_sm_recv(aq); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (aq->queue_count > 0) - return AP_WAIT_AGAIN; - fallthrough; - default: - return AP_WAIT_NONE; - } -} - /** * ap_sm_write(): Send messages from the request queue to an AP queue. * @aq: pointer to the AP queue @@ -417,10 +392,6 @@ static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { [AP_EVENT_POLL] = ap_sm_read, [AP_EVENT_TIMEOUT] = ap_sm_reset, }, - [AP_STATE_SUSPEND_WAIT] = { - [AP_EVENT_POLL] = ap_sm_suspend_read, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, [AP_STATE_REMOVE] = { [AP_EVENT_POLL] = ap_sm_nop, [AP_EVENT_TIMEOUT] = ap_sm_nop, @@ -449,28 +420,6 @@ enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event) return wait; } -/* - * Power management for queue devices - */ -void ap_queue_suspend(struct ap_device *ap_dev) -{ - struct ap_queue *aq = to_ap_queue(&ap_dev->device); - - /* Poll on the device until all requests are finished. */ - spin_lock_bh(&aq->lock); - aq->state = AP_STATE_SUSPEND_WAIT; - while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE) - ; - aq->state = AP_STATE_BORKED; - spin_unlock_bh(&aq->lock); -} -EXPORT_SYMBOL(ap_queue_suspend); - -void ap_queue_resume(struct ap_device *ap_dev) -{ -} -EXPORT_SYMBOL(ap_queue_resume); - /* * AP queue related attributes. */ diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 7cbb384ec535..b447f3e9e4a2 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -204,8 +204,6 @@ static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev) static struct ap_driver zcrypt_cex2a_queue_driver = { .probe = zcrypt_cex2a_queue_probe, .remove = zcrypt_cex2a_queue_remove, - .suspend = ap_queue_suspend, - .resume = ap_queue_resume, .ids = zcrypt_cex2a_queue_ids, .flags = AP_DRIVER_FLAG_DEFAULT, }; diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c index c78c0d119806..266440168bb7 100644 --- a/drivers/s390/crypto/zcrypt_cex2c.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -260,8 +260,6 @@ static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev) static struct ap_driver zcrypt_cex2c_queue_driver = { .probe = zcrypt_cex2c_queue_probe, .remove = zcrypt_cex2c_queue_remove, - .suspend = ap_queue_suspend, - .resume = ap_queue_resume, .ids = zcrypt_cex2c_queue_ids, .flags = AP_DRIVER_FLAG_DEFAULT, }; diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 8cfb1e2e9e1b..cdaa8348ad04 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -656,8 +656,6 @@ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) static struct ap_driver zcrypt_cex4_queue_driver = { .probe = zcrypt_cex4_queue_probe, .remove = zcrypt_cex4_queue_remove, - .suspend = ap_queue_suspend, - .resume = ap_queue_resume, .ids = zcrypt_cex4_queue_ids, .flags = AP_DRIVER_FLAG_DEFAULT, }; From 5e1fb45ec8e2eb80f00cce6661b747800e998c78 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 19 Mar 2020 10:36:32 +0100 Subject: [PATCH 629/809] s390/ccwgroup: remove pm support As s390 no longer supports ARCH_HIBERNATION_POSSIBLE, drop the unused pm ops from the ccwgroup bus driver. Signed-off-by: Julian Wiedmann Signed-off-by: Vasily Gorbik --- drivers/s390/cio/ccwgroup.c | 69 ------------------------------------- 1 file changed, 69 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b42a93736668..483a9ecfcbb1 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -485,79 +485,10 @@ static void ccwgroup_shutdown(struct device *dev) gdrv->shutdown(gdev); } -static int ccwgroup_pm_prepare(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - /* Fail while device is being set online/offline. */ - if (atomic_read(&gdev->onoff)) - return -EAGAIN; - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->prepare ? gdrv->prepare(gdev) : 0; -} - -static void ccwgroup_pm_complete(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return; - - if (gdrv->complete) - gdrv->complete(gdev); -} - -static int ccwgroup_pm_freeze(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->freeze ? gdrv->freeze(gdev) : 0; -} - -static int ccwgroup_pm_thaw(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->thaw ? gdrv->thaw(gdev) : 0; -} - -static int ccwgroup_pm_restore(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->restore ? gdrv->restore(gdev) : 0; -} - -static const struct dev_pm_ops ccwgroup_pm_ops = { - .prepare = ccwgroup_pm_prepare, - .complete = ccwgroup_pm_complete, - .freeze = ccwgroup_pm_freeze, - .thaw = ccwgroup_pm_thaw, - .restore = ccwgroup_pm_restore, -}; - static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", .remove = ccwgroup_remove, .shutdown = ccwgroup_shutdown, - .pm = &ccwgroup_pm_ops, }; bool dev_is_ccwgroup(struct device *dev) From dea284867701024d5058d7ab1542763a12006595 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 20 Mar 2020 14:00:00 +0100 Subject: [PATCH 630/809] s390/qdio: remove unused function declarations commit 50f769df1c4b ("[S390] qdio: improve inbound buffer acknowledgement") introduced these declarations, but noone added the actual code for them. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index e24a2cde487a..8564e8a8e359 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -394,8 +394,6 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_release_memory(struct qdio_irq *irq_ptr); -int qdio_setup_create_sysfs(struct ccw_device *cdev); -void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); int qdio_enable_async_operation(struct qdio_output_q *q); From b2745655be3658cd422ba2b07cf19eb64e0c0eaf Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 20 Mar 2020 14:00:00 +0100 Subject: [PATCH 631/809] s390/qdio: set qdio_irq->cdev at allocation time Set up qdio_irq->cdev right when the qdio_irq struct is allocated, so that all subsequent code can rely on this pointer. Then convert two helper functions to not pass a cdev parameter around. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Vasily Gorbik --- drivers/s390/cio/qdio.h | 3 +-- drivers/s390/cio/qdio_debug.c | 8 ++++---- drivers/s390/cio/qdio_debug.h | 3 +-- drivers/s390/cio/qdio_main.c | 10 ++++++---- drivers/s390/cio/qdio_setup.c | 8 +++----- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 8564e8a8e359..098bf8c9bbec 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -391,8 +391,7 @@ int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, struct subchannel_id *schid, struct qdio_ssqd_desc *data); int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); -void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, - struct ccw_device *cdev); +void qdio_print_subchannel_info(struct qdio_irq *irq_ptr); void qdio_release_memory(struct qdio_irq *irq_ptr); int qdio_setup_init(void); void qdio_setup_exit(void); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 8544faddf80c..f21fb406bef0 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -81,7 +81,7 @@ int qdio_allocate_dbf(struct qdio_initialize *init_data, /* allocate trace view for the interface */ snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s", - dev_name(&init_data->cdev->dev)); + dev_name(&irq_ptr->cdev->dev)); irq_ptr->debug_area = qdio_get_dbf_entry(text); if (irq_ptr->debug_area) DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused"); @@ -311,16 +311,16 @@ static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q) debugfs_create_file(name, 0444, parent, q, &qstat_fops); } -void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) +void qdio_setup_debug_entries(struct qdio_irq *irq_ptr) { struct qdio_q *q; int i; - irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), + irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev), debugfs_root); debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); - debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, cdev, + debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev, &ssqd_fops); for_each_input_queue(irq_ptr, q, i) diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index f85f5fa7cefc..122450ba6b90 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -66,8 +66,7 @@ static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, int qdio_allocate_dbf(struct qdio_initialize *init_data, struct qdio_irq *irq_ptr); -void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, - struct ccw_device *cdev); +void qdio_setup_debug_entries(struct qdio_irq *irq_ptr); void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr); int qdio_debug_init(void); void qdio_debug_exit(void); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 2886b95f4741..e93155dbe887 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1229,10 +1229,11 @@ EXPORT_SYMBOL_GPL(qdio_free); */ int qdio_allocate(struct qdio_initialize *init_data) { + struct ccw_device *cdev = init_data->cdev; struct subchannel_id schid; struct qdio_irq *irq_ptr; - ccw_device_get_schid(init_data->cdev, &schid); + ccw_device_get_schid(cdev, &schid); DBF_EVENT("qallocate:%4x", schid.sch_no); if ((init_data->no_input_qs && !init_data->input_handler) || @@ -1252,6 +1253,7 @@ int qdio_allocate(struct qdio_initialize *init_data) if (!irq_ptr) goto out_err; + irq_ptr->cdev = cdev; mutex_init(&irq_ptr->setup_mutex); if (qdio_allocate_dbf(init_data, irq_ptr)) goto out_rel; @@ -1276,7 +1278,7 @@ int qdio_allocate(struct qdio_initialize *init_data) goto out_rel; INIT_LIST_HEAD(&irq_ptr->entry); - init_data->cdev->private->qdio_data = irq_ptr; + cdev->private->qdio_data = irq_ptr; qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); return 0; out_rel: @@ -1372,8 +1374,8 @@ int qdio_establish(struct qdio_initialize *init_data) qdio_init_buf_states(irq_ptr); mutex_unlock(&irq_ptr->setup_mutex); - qdio_print_subchannel_info(irq_ptr, cdev); - qdio_setup_debug_entries(irq_ptr, cdev); + qdio_print_subchannel_info(irq_ptr); + qdio_setup_debug_entries(irq_ptr); return 0; } EXPORT_SYMBOL_GPL(qdio_establish); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index ad04947a0032..e1b7a9118f9d 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -452,8 +452,8 @@ static void setup_qib(struct qdio_irq *irq_ptr, int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) { + struct ccw_device *cdev = irq_ptr->cdev; struct ciw *ciw; - struct ccw_device *cdev = init_data->cdev; memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); @@ -471,7 +471,6 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) irq_ptr->int_parm = init_data->int_parm; irq_ptr->nr_input_qs = init_data->no_input_qs; irq_ptr->nr_output_qs = init_data->no_output_qs; - irq_ptr->cdev = cdev; irq_ptr->scan_threshold = init_data->scan_threshold; ccw_device_get_schid(cdev, &irq_ptr->schid); setup_queues(irq_ptr, init_data); @@ -511,14 +510,13 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) return 0; } -void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, - struct ccw_device *cdev) +void qdio_print_subchannel_info(struct qdio_irq *irq_ptr) { char s[80]; snprintf(s, 80, "qdio: %s %s on SC %x using " "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s\n", - dev_name(&cdev->dev), + dev_name(&irq_ptr->cdev->dev), (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), irq_ptr->schid.sch_no, From 1f5bd6a2020178e90ccf50a05bccda9883c442ae Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Nov 2019 21:43:40 +0800 Subject: [PATCH 632/809] 9p: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Link: http://lkml.kernel.org/r/20191120134340.16770-1-krzk@kernel.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dominique Martinet --- fs/9p/Kconfig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/9p/Kconfig b/fs/9p/Kconfig index ac2ec4543fe1..09fd4a185fd2 100644 --- a/fs/9p/Kconfig +++ b/fs/9p/Kconfig @@ -32,13 +32,13 @@ endif config 9P_FS_SECURITY - bool "9P Security Labels" - depends on 9P_FS - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the 9P filesystem. + bool "9P Security Labels" + depends on 9P_FS + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the 9P filesystem. - If you are not using a security module that requires using - extended attributes for file security labels, say N. + If you are not using a security module that requires using + extended attributes for file security labels, say N. From 51958817391d0d45ca0533bf31f05248cb6c5933 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Thu, 19 Dec 2019 18:48:37 +0800 Subject: [PATCH 633/809] 9p: Remove unneeded semicolon Fixes coccicheck warning: fs/9p/vfs_inode.c:146:3-4: Unneeded semicolon Link: http://lkml.kernel.org/r/1576752517-58292-1-git-send-email-zhengbin13@huawei.com Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Dominique Martinet --- fs/9p/vfs_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index b82423a72f68..c9255d399917 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -143,7 +143,7 @@ static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses, default: p9_debug(P9_DEBUG_ERROR, "Unknown special type %c %s\n", type, stat->extension); - }; + } *rdev = MKDEV(major, minor); } else res |= S_IFREG; From 388f6966b05746e80e809984231b06e93aa5d891 Mon Sep 17 00:00:00 2001 From: Sergey Alirzaev Date: Wed, 5 Feb 2020 23:40:53 +0300 Subject: [PATCH 634/809] 9pnet: allow making incomplete read requests A user doesn't necessarily want to wait for all the requested data to be available, since the waiting time for each request is unbounded. The new method permits sending one read request at a time and getting the response ASAP, allowing to use 9pnet with synthetic file systems representing arbitrary data streams. Link: http://lkml.kernel.org/r/20200205204053.12751-1-l29ah@cock.li Signed-off-by: Sergey Alirzaev Signed-off-by: Dominique Martinet --- include/net/9p/client.h | 2 + net/9p/client.c | 144 ++++++++++++++++++++++------------------ 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/include/net/9p/client.h b/include/net/9p/client.h index acc60d8a3b3b..f6c890e94f87 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -200,6 +200,8 @@ int p9_client_fsync(struct p9_fid *fid, int datasync); int p9_client_remove(struct p9_fid *fid); int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err); +int p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + int *err); int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err); int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset); int p9dirent_read(struct p9_client *clnt, char *buf, int len, diff --git a/net/9p/client.c b/net/9p/client.c index 1d48afc7033c..fc1f3635e5dd 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1549,83 +1549,95 @@ EXPORT_SYMBOL(p9_client_unlinkat); int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err) { - struct p9_client *clnt = fid->clnt; - struct p9_req_t *req; int total = 0; *err = 0; - p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", - fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); - while (iov_iter_count(to)) { - int count = iov_iter_count(to); - int rsize, non_zc = 0; - char *dataptr; + int count; - rsize = fid->iounit; - if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) - rsize = clnt->msize - P9_IOHDRSZ; - - if (count < rsize) - rsize = count; - - /* Don't bother zerocopy for small IO (< 1024) */ - if (clnt->trans_mod->zc_request && rsize > 1024) { - /* - * response header len is 11 - * PDU Header(7) + IO Size (4) - */ - req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize, - 0, 11, "dqd", fid->fid, - offset, rsize); - } else { - non_zc = 1; - req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, - rsize); - } - if (IS_ERR(req)) { - *err = PTR_ERR(req); + count = p9_client_read_once(fid, offset, to, err); + if (!count || *err) break; - } - - *err = p9pdu_readf(&req->rc, clnt->proto_version, - "D", &count, &dataptr); - if (*err) { - trace_9p_protocol_dump(clnt, &req->rc); - p9_tag_remove(clnt, req); - break; - } - if (rsize < count) { - pr_err("bogus RREAD count (%d > %d)\n", count, rsize); - count = rsize; - } - - p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); - if (!count) { - p9_tag_remove(clnt, req); - break; - } - - if (non_zc) { - int n = copy_to_iter(dataptr, count, to); - total += n; - offset += n; - if (n != count) { - *err = -EFAULT; - p9_tag_remove(clnt, req); - break; - } - } else { - iov_iter_advance(to, count); - total += count; - offset += count; - } - p9_tag_remove(clnt, req); + offset += count; + total += count; } return total; } EXPORT_SYMBOL(p9_client_read); +int +p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + int *err) +{ + struct p9_client *clnt = fid->clnt; + struct p9_req_t *req; + int count = iov_iter_count(to); + int rsize, non_zc = 0; + char *dataptr; + + *err = 0; + p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", + fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); + + rsize = fid->iounit; + if (!rsize || rsize > clnt->msize - P9_IOHDRSZ) + rsize = clnt->msize - P9_IOHDRSZ; + + if (count < rsize) + rsize = count; + + /* Don't bother zerocopy for small IO (< 1024) */ + if (clnt->trans_mod->zc_request && rsize > 1024) { + /* response header len is 11 + * PDU Header(7) + IO Size (4) + */ + req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize, + 0, 11, "dqd", fid->fid, + offset, rsize); + } else { + non_zc = 1; + req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, + rsize); + } + if (IS_ERR(req)) { + *err = PTR_ERR(req); + return 0; + } + + *err = p9pdu_readf(&req->rc, clnt->proto_version, + "D", &count, &dataptr); + if (*err) { + trace_9p_protocol_dump(clnt, &req->rc); + p9_tag_remove(clnt, req); + return 0; + } + if (rsize < count) { + pr_err("bogus RREAD count (%d > %d)\n", count, rsize); + count = rsize; + } + + p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); + if (!count) { + p9_tag_remove(clnt, req); + return 0; + } + + if (non_zc) { + int n = copy_to_iter(dataptr, count, to); + + if (n != count) { + *err = -EFAULT; + p9_tag_remove(clnt, req); + return n; + } + } else { + iov_iter_advance(to, count); + } + p9_tag_remove(clnt, req); + return count; +} +EXPORT_SYMBOL(p9_client_read_once); + int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) { From 52cbee2a5768d1cf6051286490be43e1712674b3 Mon Sep 17 00:00:00 2001 From: Sergey Alirzaev Date: Wed, 5 Feb 2020 03:34:57 +0300 Subject: [PATCH 635/809] 9p: read only once on O_NONBLOCK A proper way to handle O_NONBLOCK would be making the requests and responses happen asynchronously, but this would require serious code refactoring. Link: http://lkml.kernel.org/r/20200205003457.24340-2-l29ah@cock.li Signed-off-by: Sergey Alirzaev Signed-off-by: Dominique Martinet --- fs/9p/vfs_file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index fe7f0bd2048e..92cd1d80218d 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -388,7 +388,10 @@ v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", iov_iter_count(to), iocb->ki_pos); - ret = p9_client_read(fid, iocb->ki_pos, to, &err); + if (iocb->ki_filp->f_flags & O_NONBLOCK) + ret = p9_client_read_once(fid, iocb->ki_pos, to, &err); + else + ret = p9_client_read(fid, iocb->ki_pos, to, &err); if (!ret) return err; From 43657496e46672fe63bccc1fcfb5b68de6e1e2f4 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 5 Feb 2020 23:19:12 +0100 Subject: [PATCH 636/809] net/9p: remove unused p9_req_t aux field The p9_req_t field 'aux' has not been used in a very long time, remove leftover field declaration Link: http://lkml.kernel.org/r/1580941152-12973-1-git-send-email-asmadeus@codewreck.org Signed-off-by: Dominique Martinet --- include/net/9p/client.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/net/9p/client.h b/include/net/9p/client.h index f6c890e94f87..dd5b5bd781a4 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -73,7 +73,6 @@ enum p9_req_status_t { * @wq: wait_queue for the client to block on for this request * @tc: the request fcall structure * @rc: the response fcall structure - * @aux: transport specific data (provided for trans_fd migration) * @req_list: link for higher level objects to chain requests */ struct p9_req_t { @@ -83,7 +82,6 @@ struct p9_req_t { wait_queue_head_t wq; struct p9_fcall tc; struct p9_fcall rc; - void *aux; struct list_head req_list; }; From 2ab73c6d8323fa1eb02c16c07c40ba2ed17da729 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 19 Mar 2020 13:27:29 +0100 Subject: [PATCH 637/809] gpio: Support GPIO controllers without pin-ranges Wake gpiochip_generic_request() call into the pinctrl helpers only if a GPIO controller had any pin-ranges assigned to it. This allows a driver to unconditionally use this helper if it supports multiple devices of which only a subset have pin-ranges assigned to them. Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20200319122737.3063291-2-thierry.reding@gmail.com Tested-by: Vidya Sagar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c7ee224bcb86..4a36164843d9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2745,7 +2745,10 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) */ int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset) { - return pinctrl_gpio_request(chip->gpiodev->base + offset); + if (!list_empty(&chip->gpiodev->pin_ranges)) + return pinctrl_gpio_request(chip->gpiodev->base + offset); + + return 0; } EXPORT_SYMBOL_GPL(gpiochip_generic_request); From b64d6c9a6a050d9a15c9e044db9ebc874aed6072 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 19 Mar 2020 13:27:30 +0100 Subject: [PATCH 638/809] gpio: tegra186: Add support for pin ranges Add support for Tegra SoC generations to specify a list of pin ranges that map GPIOs to ranges of pins in the pin controller. Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20200319122737.3063291-3-thierry.reding@gmail.com Tested-by: Vidya Sagar Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra186.c | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index de241263d4be..1086c1fcaf49 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -58,11 +58,20 @@ struct tegra_gpio_port { unsigned int pins; }; +struct tegra186_pin_range { + unsigned int offset; + const char *group; +}; + struct tegra_gpio_soc { const struct tegra_gpio_port *ports; unsigned int num_ports; const char *name; unsigned int instance; + + const struct tegra186_pin_range *pin_ranges; + unsigned int num_pin_ranges; + const char *pinmux; }; struct tegra_gpio { @@ -254,6 +263,50 @@ static int tegra186_gpio_set_config(struct gpio_chip *chip, return 0; } +static int tegra186_gpio_add_pin_ranges(struct gpio_chip *chip) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + struct pinctrl_dev *pctldev; + struct device_node *np; + unsigned int i, j; + int err; + + if (!gpio->soc->pinmux || gpio->soc->num_pin_ranges == 0) + return 0; + + np = of_find_compatible_node(NULL, NULL, gpio->soc->pinmux); + if (!np) + return -ENODEV; + + pctldev = of_pinctrl_get(np); + of_node_put(np); + if (!pctldev) + return -EPROBE_DEFER; + + for (i = 0; i < gpio->soc->num_pin_ranges; i++) { + unsigned int pin = gpio->soc->pin_ranges[i].offset, port; + const char *group = gpio->soc->pin_ranges[i].group; + + port = pin / 8; + pin = pin % 8; + + if (port >= gpio->soc->num_ports) { + dev_warn(chip->parent, "invalid port %u for %s\n", + port, group); + continue; + } + + for (j = 0; j < port; j++) + pin += gpio->soc->ports[j].pins; + + err = gpiochip_add_pingroup_range(chip, pctldev, pin, group); + if (err < 0) + return err; + } + + return 0; +} + static int tegra186_gpio_of_xlate(struct gpio_chip *chip, const struct of_phandle_args *spec, u32 *flags) @@ -578,12 +631,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.label = gpio->soc->name; gpio->gpio.parent = &pdev->dev; + gpio->gpio.request = gpiochip_generic_request; + gpio->gpio.free = gpiochip_generic_free; gpio->gpio.get_direction = tegra186_gpio_get_direction; gpio->gpio.direction_input = tegra186_gpio_direction_input; gpio->gpio.direction_output = tegra186_gpio_direction_output; gpio->gpio.get = tegra186_gpio_get, gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set_config = tegra186_gpio_set_config; + gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; gpio->gpio.base = -1; From ffa91e7ca1426a89eec1b3101286d82785760767 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 19 Mar 2020 13:27:31 +0100 Subject: [PATCH 639/809] gpio: tegra186: Add Tegra194 pin ranges for GG.0 and GG.1 The GG.0 and GG.1 GPIOs serve as CLKREQ and RST pins, respectively, for PCIe controller 5 on Tegra194. When this controller is configured in endpoint mode, these pins need to be used as GPIOs by the PCIe endpoint driver. Typically the mode programming of these pins (GPIO vs. SFIO) is performed by early boot firmware to ensure that the configuration is consistent. However, the GG.0 and GG.1 pins are part of a special power partition that is not enabled during early boot, and hence the early boot firmware cannot program these pins to be GPIOs (they are SFIO by default). Adding them as pin ranges for the pin controller allows the pin controller to be involved when these pins are requested as GPIOs and allows the proper programming to take place. Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20200319122737.3063291-4-thierry.reding@gmail.com Tested-by: Vidya Sagar Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra186.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 1086c1fcaf49..79b553dc39a3 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -839,11 +839,19 @@ static const struct tegra_gpio_port tegra194_main_ports[] = { TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2) }; +static const struct tegra186_pin_range tegra194_main_pin_ranges[] = { + { TEGRA194_MAIN_GPIO(GG, 0), "pex_l5_clkreq_n_pgg0" }, + { TEGRA194_MAIN_GPIO(GG, 1), "pex_l5_rst_n_pgg1" }, +}; + static const struct tegra_gpio_soc tegra194_main_soc = { .num_ports = ARRAY_SIZE(tegra194_main_ports), .ports = tegra194_main_ports, .name = "tegra194-gpio", .instance = 0, + .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), + .pin_ranges = tegra194_main_pin_ranges, + .pinmux = "nvidia,tegra194-pinmux", }; #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ From 315a4af8cd2469fcf5dacc58b5e73944b4f0c561 Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Tue, 4 Feb 2020 09:14:24 -0800 Subject: [PATCH 640/809] x86/insn: Add Control-flow Enforcement (CET) instructions to the opcode map Add the following CET instructions to the opcode map: INCSSP: Increment Shadow Stack pointer (SSP). RDSSP: Read SSP into a GPR. SAVEPREVSSP: Use "previous ssp" token at top of current Shadow Stack (SHSTK) to create a "restore token" on the previous (outgoing) SHSTK. RSTORSSP: Restore from a "restore token" to SSP. WRSS: Write to kernel-mode SHSTK (kernel-mode instruction). WRUSS: Write to user-mode SHSTK (kernel-mode instruction). SETSSBSY: Verify the "supervisor token" pointed by MSR_IA32_PL0_SSP, set the token busy, and set then Shadow Stack pointer(SSP) to the value of MSR_IA32_PL0_SSP. CLRSSBSY: Verify the "supervisor token" and clear its busy bit. ENDBR64/ENDBR32: Mark a valid 64/32 bit control transfer endpoint. Detailed information of CET instructions can be found in Intel Software Developer's Manual. Signed-off-by: Yu-cheng Yu Reviewed-by: Adrian Hunter Reviewed-by: Tony Luck Acked-by: Masami Hiramatsu Cc: Andi Kleen Cc: Borislav Petkov Cc: Dave Hansen Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Ravi v. Shankar Cc: Thomas Gleixner Cc: x86@kernel.org Link: http://lore.kernel.org/lkml/20200204171425.28073-2-yu-cheng.yu@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 17 +++++++++++------ tools/arch/x86/lib/x86-opcode-map.txt | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 53adc1762ec0..ec31f5b60323 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -366,7 +366,7 @@ AVXcode: 1 1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 1c: Grp20 (1A),(1C) 1d: -1e: +1e: Grp21 (1A) 1f: NOP Ev # 0x0f 0x20-0x2f 20: MOV Rd,Cd @@ -803,8 +803,8 @@ f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) f2: ANDN Gy,By,Ey (v) f3: Grp17 (1A) -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) +f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) | WRUSSD/Q My,Gy (66) +f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) | WRSSD/Q My,Gy f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) f8: MOVDIR64B Gv,Mdqq (66) | ENQCMD Gv,Mdqq (F2) | ENQCMDS Gv,Mdqq (F3) f9: MOVDIRI My,Gy @@ -970,7 +970,7 @@ GrpTable: Grp7 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B) 3: LIDT Ms 4: SMSW Mw/Rv -5: rdpkru (110),(11B) | wrpkru (111),(11B) +5: rdpkru (110),(11B) | wrpkru (111),(11B) | SAVEPREVSSP (F3),(010),(11B) | RSTORSSP Mq (F3) | SETSSBSY (F3),(000),(11B) 6: LMSW Ew 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) EndTable @@ -1041,8 +1041,8 @@ GrpTable: Grp15 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 4: XSAVE | ptwrite Ey (F3),(11B) -5: XRSTOR | lfence (11B) -6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B) +5: XRSTOR | lfence (11B) | INCSSPD/Q Ry (F3),(11B) +6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B) | CLRSSBSY Mq (F3) 7: clflush | clflushopt (66) | sfence (11B) EndTable @@ -1077,6 +1077,11 @@ GrpTable: Grp20 0: cldemote Mb EndTable +GrpTable: Grp21 +1: RDSSPD/Q Ry (F3),(11B) +7: ENDBR64 (F3),(010),(11B) | ENDBR32 (F3),(011),(11B) +EndTable + # AMD's Prefetch Group GrpTable: GrpP 0: PREFETCH diff --git a/tools/arch/x86/lib/x86-opcode-map.txt b/tools/arch/x86/lib/x86-opcode-map.txt index 53adc1762ec0..ec31f5b60323 100644 --- a/tools/arch/x86/lib/x86-opcode-map.txt +++ b/tools/arch/x86/lib/x86-opcode-map.txt @@ -366,7 +366,7 @@ AVXcode: 1 1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 1c: Grp20 (1A),(1C) 1d: -1e: +1e: Grp21 (1A) 1f: NOP Ev # 0x0f 0x20-0x2f 20: MOV Rd,Cd @@ -803,8 +803,8 @@ f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) f2: ANDN Gy,By,Ey (v) f3: Grp17 (1A) -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) +f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) | WRUSSD/Q My,Gy (66) +f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) | WRSSD/Q My,Gy f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) f8: MOVDIR64B Gv,Mdqq (66) | ENQCMD Gv,Mdqq (F2) | ENQCMDS Gv,Mdqq (F3) f9: MOVDIRI My,Gy @@ -970,7 +970,7 @@ GrpTable: Grp7 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B) 3: LIDT Ms 4: SMSW Mw/Rv -5: rdpkru (110),(11B) | wrpkru (111),(11B) +5: rdpkru (110),(11B) | wrpkru (111),(11B) | SAVEPREVSSP (F3),(010),(11B) | RSTORSSP Mq (F3) | SETSSBSY (F3),(000),(11B) 6: LMSW Ew 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) EndTable @@ -1041,8 +1041,8 @@ GrpTable: Grp15 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 4: XSAVE | ptwrite Ey (F3),(11B) -5: XRSTOR | lfence (11B) -6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B) +5: XRSTOR | lfence (11B) | INCSSPD/Q Ry (F3),(11B) +6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B) | CLRSSBSY Mq (F3) 7: clflush | clflushopt (66) | sfence (11B) EndTable @@ -1077,6 +1077,11 @@ GrpTable: Grp20 0: cldemote Mb EndTable +GrpTable: Grp21 +1: RDSSPD/Q Ry (F3),(11B) +7: ENDBR64 (F3),(010),(11B) | ENDBR32 (F3),(011),(11B) +EndTable + # AMD's Prefetch Group GrpTable: GrpP 0: PREFETCH From 26cec7480e7edaa9dead4912055078b98c1d192e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Feb 2020 09:14:25 -0800 Subject: [PATCH 641/809] perf test x86: Add CET instructions to the new instructions test Add to the "x86 instruction decoder - new instructions" test the following instructions: incsspd incsspq rdsspd rdsspq saveprevssp rstorssp wrssd wrssq wrussd wrussq setssbsy clrssbsy endbr32 endbr64 And the "notrack" prefix for indirect calls and jumps. For information about the instructions, refer Intel Control-flow Enforcement Technology Specification May 2019 (334525-003). Committer testing: $ perf test instr 67: x86 instruction decoder - new instructions : Ok $ Then use verbose mode and check one of those new instructions: $ perf test -v instr |& grep saveprevssp Decoded ok: f3 0f 01 ea saveprevssp Decoded ok: f3 0f 01 ea saveprevssp $ Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Borislav Petkov Cc: Dave Hansen Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Ravi v. Shankar Cc: Thomas Gleixner Cc: Tony Luck Cc: x86@kernel.org Link: http://lore.kernel.org/lkml/20200204171425.28073-3-yu-cheng.yu@intel.com Signed-off-by: Yu-cheng Yu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/tests/insn-x86-dat-32.c | 112 +++++++++ tools/perf/arch/x86/tests/insn-x86-dat-64.c | 196 +++++++++++++++ tools/perf/arch/x86/tests/insn-x86-dat-src.c | 236 +++++++++++++++++++ 3 files changed, 544 insertions(+) diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index e6461abc9e7b..9708ae892061 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c @@ -2085,6 +2085,118 @@ "67 f3 0f 38 f8 1c \tenqcmds (%si),%bx",}, {{0x67, 0xf3, 0x0f, 0x38, 0xf8, 0x8c, 0x34, 0x12, }, 8, 0, "", "", "67 f3 0f 38 f8 8c 34 12 \tenqcmds 0x1234(%si),%cx",}, +{{0xf3, 0x0f, 0xae, 0xe8, }, 4, 0, "", "", +"f3 0f ae e8 \tincsspd %eax",}, +{{0x0f, 0xae, 0x28, }, 3, 0, "", "", +"0f ae 28 \txrstor (%eax)",}, +{{0x0f, 0xae, 0x2d, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f ae 2d 78 56 34 12 \txrstor 0x12345678",}, +{{0x0f, 0xae, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f ae ac c8 78 56 34 12 \txrstor 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0xae, 0xe8, }, 3, 0, "", "", +"0f ae e8 \tlfence ",}, +{{0xf3, 0x0f, 0x1e, 0xc8, }, 4, 0, "", "", +"f3 0f 1e c8 \trdsspd %eax",}, +{{0xf3, 0x0f, 0x01, 0xea, }, 4, 0, "", "", +"f3 0f 01 ea \tsaveprevssp ",}, +{{0xf3, 0x0f, 0x01, 0x28, }, 4, 0, "", "", +"f3 0f 01 28 \trstorssp (%eax)",}, +{{0xf3, 0x0f, 0x01, 0x2d, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 01 2d 78 56 34 12 \trstorssp 0x12345678",}, +{{0xf3, 0x0f, 0x01, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 01 ac c8 78 56 34 12 \trstorssp 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0x38, 0xf6, 0x08, }, 4, 0, "", "", +"0f 38 f6 08 \twrssd %ecx,(%eax)",}, +{{0x0f, 0x38, 0xf6, 0x15, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 f6 15 78 56 34 12 \twrssd %edx,0x12345678",}, +{{0x0f, 0x38, 0xf6, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 f6 94 c8 78 56 34 12 \twrssd %edx,0x12345678(%eax,%ecx,8)",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x08, }, 5, 0, "", "", +"66 0f 38 f5 08 \twrussd %ecx,(%eax)",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x15, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 38 f5 15 78 56 34 12 \twrussd %edx,0x12345678",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"66 0f 38 f5 94 c8 78 56 34 12 \twrussd %edx,0x12345678(%eax,%ecx,8)",}, +{{0xf3, 0x0f, 0x01, 0xe8, }, 4, 0, "", "", +"f3 0f 01 e8 \tsetssbsy ",}, +{{0x0f, 0x01, 0xee, }, 3, 0, "", "", +"0f 01 ee \trdpkru ",}, +{{0x0f, 0x01, 0xef, }, 3, 0, "", "", +"0f 01 ef \twrpkru ",}, +{{0xf3, 0x0f, 0xae, 0x30, }, 4, 0, "", "", +"f3 0f ae 30 \tclrssbsy (%eax)",}, +{{0xf3, 0x0f, 0xae, 0x35, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f ae 35 78 56 34 12 \tclrssbsy 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae b4 c8 78 56 34 12 \tclrssbsy 0x12345678(%eax,%ecx,8)",}, +{{0xf3, 0x0f, 0x1e, 0xfb, }, 4, 0, "", "", +"f3 0f 1e fb \tendbr32 ",}, +{{0xf3, 0x0f, 0x1e, 0xfa, }, 4, 0, "", "", +"f3 0f 1e fa \tendbr64 ",}, +{{0xff, 0xd0, }, 2, 0, "call", "indirect", +"ff d0 \tcall *%eax",}, +{{0xff, 0x10, }, 2, 0, "call", "indirect", +"ff 10 \tcall *(%eax)",}, +{{0xff, 0x15, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "call", "indirect", +"ff 15 78 56 34 12 \tcall *0x12345678",}, +{{0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "call", "indirect", +"ff 94 c8 78 56 34 12 \tcall *0x12345678(%eax,%ecx,8)",}, +{{0xf2, 0xff, 0xd0, }, 3, 0, "call", "indirect", +"f2 ff d0 \tbnd call *%eax",}, +{{0xf2, 0xff, 0x10, }, 3, 0, "call", "indirect", +"f2 ff 10 \tbnd call *(%eax)",}, +{{0xf2, 0xff, 0x15, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "call", "indirect", +"f2 ff 15 78 56 34 12 \tbnd call *0x12345678",}, +{{0xf2, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"f2 ff 94 c8 78 56 34 12 \tbnd call *0x12345678(%eax,%ecx,8)",}, +{{0x3e, 0xff, 0xd0, }, 3, 0, "call", "indirect", +"3e ff d0 \tnotrack call *%eax",}, +{{0x3e, 0xff, 0x10, }, 3, 0, "call", "indirect", +"3e ff 10 \tnotrack call *(%eax)",}, +{{0x3e, 0xff, 0x15, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "call", "indirect", +"3e ff 15 78 56 34 12 \tnotrack call *0x12345678",}, +{{0x3e, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"3e ff 94 c8 78 56 34 12 \tnotrack call *0x12345678(%eax,%ecx,8)",}, +{{0x3e, 0xf2, 0xff, 0xd0, }, 4, 0, "call", "indirect", +"3e f2 ff d0 \tnotrack bnd call *%eax",}, +{{0x3e, 0xf2, 0xff, 0x10, }, 4, 0, "call", "indirect", +"3e f2 ff 10 \tnotrack bnd call *(%eax)",}, +{{0x3e, 0xf2, 0xff, 0x15, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"3e f2 ff 15 78 56 34 12 \tnotrack bnd call *0x12345678",}, +{{0x3e, 0xf2, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "call", "indirect", +"3e f2 ff 94 c8 78 56 34 12 \tnotrack bnd call *0x12345678(%eax,%ecx,8)",}, +{{0xff, 0xe0, }, 2, 0, "jmp", "indirect", +"ff e0 \tjmp *%eax",}, +{{0xff, 0x20, }, 2, 0, "jmp", "indirect", +"ff 20 \tjmp *(%eax)",}, +{{0xff, 0x25, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "jmp", "indirect", +"ff 25 78 56 34 12 \tjmp *0x12345678",}, +{{0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "jmp", "indirect", +"ff a4 c8 78 56 34 12 \tjmp *0x12345678(%eax,%ecx,8)",}, +{{0xf2, 0xff, 0xe0, }, 3, 0, "jmp", "indirect", +"f2 ff e0 \tbnd jmp *%eax",}, +{{0xf2, 0xff, 0x20, }, 3, 0, "jmp", "indirect", +"f2 ff 20 \tbnd jmp *(%eax)",}, +{{0xf2, 0xff, 0x25, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "jmp", "indirect", +"f2 ff 25 78 56 34 12 \tbnd jmp *0x12345678",}, +{{0xf2, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"f2 ff a4 c8 78 56 34 12 \tbnd jmp *0x12345678(%eax,%ecx,8)",}, +{{0x3e, 0xff, 0xe0, }, 3, 0, "jmp", "indirect", +"3e ff e0 \tnotrack jmp *%eax",}, +{{0x3e, 0xff, 0x20, }, 3, 0, "jmp", "indirect", +"3e ff 20 \tnotrack jmp *(%eax)",}, +{{0x3e, 0xff, 0x25, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "jmp", "indirect", +"3e ff 25 78 56 34 12 \tnotrack jmp *0x12345678",}, +{{0x3e, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"3e ff a4 c8 78 56 34 12 \tnotrack jmp *0x12345678(%eax,%ecx,8)",}, +{{0x3e, 0xf2, 0xff, 0xe0, }, 4, 0, "jmp", "indirect", +"3e f2 ff e0 \tnotrack bnd jmp *%eax",}, +{{0x3e, 0xf2, 0xff, 0x20, }, 4, 0, "jmp", "indirect", +"3e f2 ff 20 \tnotrack bnd jmp *(%eax)",}, +{{0x3e, 0xf2, 0xff, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"3e f2 ff 25 78 56 34 12 \tnotrack bnd jmp *0x12345678",}, +{{0x3e, 0xf2, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "jmp", "indirect", +"3e f2 ff a4 c8 78 56 34 12 \tnotrack bnd jmp *0x12345678(%eax,%ecx,8)",}, {{0x0f, 0x01, 0xcf, }, 3, 0, "", "", "0f 01 cf \tencls ",}, {{0x0f, 0x01, 0xd7, }, 3, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index 567ecccfad7c..5da17d41d302 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c @@ -2263,6 +2263,202 @@ "67 f3 0f 38 f8 18 \tenqcmds (%eax),%ebx",}, {{0x67, 0xf3, 0x0f, 0x38, 0xf8, 0x88, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", "67 f3 0f 38 f8 88 78 56 34 12 \tenqcmds 0x12345678(%eax),%ecx",}, +{{0xf3, 0x0f, 0xae, 0xe8, }, 4, 0, "", "", +"f3 0f ae e8 \tincsspd %eax",}, +{{0xf3, 0x41, 0x0f, 0xae, 0xe8, }, 5, 0, "", "", +"f3 41 0f ae e8 \tincsspd %r8d",}, +{{0xf3, 0x48, 0x0f, 0xae, 0xe8, }, 5, 0, "", "", +"f3 48 0f ae e8 \tincsspq %rax",}, +{{0xf3, 0x49, 0x0f, 0xae, 0xe8, }, 5, 0, "", "", +"f3 49 0f ae e8 \tincsspq %r8",}, +{{0x0f, 0xae, 0x28, }, 3, 0, "", "", +"0f ae 28 \txrstor (%rax)",}, +{{0x41, 0x0f, 0xae, 0x28, }, 4, 0, "", "", +"41 0f ae 28 \txrstor (%r8)",}, +{{0x0f, 0xae, 0x2c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f ae 2c 25 78 56 34 12 \txrstor 0x12345678",}, +{{0x0f, 0xae, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f ae ac c8 78 56 34 12 \txrstor 0x12345678(%rax,%rcx,8)",}, +{{0x41, 0x0f, 0xae, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"41 0f ae ac c8 78 56 34 12 \txrstor 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0xae, 0xe8, }, 3, 0, "", "", +"0f ae e8 \tlfence ",}, +{{0xf3, 0x0f, 0x1e, 0xc8, }, 4, 0, "", "", +"f3 0f 1e c8 \trdsspd %eax",}, +{{0xf3, 0x41, 0x0f, 0x1e, 0xc8, }, 5, 0, "", "", +"f3 41 0f 1e c8 \trdsspd %r8d",}, +{{0xf3, 0x48, 0x0f, 0x1e, 0xc8, }, 5, 0, "", "", +"f3 48 0f 1e c8 \trdsspq %rax",}, +{{0xf3, 0x49, 0x0f, 0x1e, 0xc8, }, 5, 0, "", "", +"f3 49 0f 1e c8 \trdsspq %r8",}, +{{0xf3, 0x0f, 0x01, 0xea, }, 4, 0, "", "", +"f3 0f 01 ea \tsaveprevssp ",}, +{{0xf3, 0x0f, 0x01, 0x28, }, 4, 0, "", "", +"f3 0f 01 28 \trstorssp (%rax)",}, +{{0xf3, 0x41, 0x0f, 0x01, 0x28, }, 5, 0, "", "", +"f3 41 0f 01 28 \trstorssp (%r8)",}, +{{0xf3, 0x0f, 0x01, 0x2c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 01 2c 25 78 56 34 12 \trstorssp 0x12345678",}, +{{0xf3, 0x0f, 0x01, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 01 ac c8 78 56 34 12 \trstorssp 0x12345678(%rax,%rcx,8)",}, +{{0xf3, 0x41, 0x0f, 0x01, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 41 0f 01 ac c8 78 56 34 12 \trstorssp 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0x38, 0xf6, 0x08, }, 4, 0, "", "", +"0f 38 f6 08 \twrssd %ecx,(%rax)",}, +{{0x41, 0x0f, 0x38, 0xf6, 0x10, }, 5, 0, "", "", +"41 0f 38 f6 10 \twrssd %edx,(%r8)",}, +{{0x0f, 0x38, 0xf6, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 f6 14 25 78 56 34 12 \twrssd %edx,0x12345678",}, +{{0x0f, 0x38, 0xf6, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 f6 94 c8 78 56 34 12 \twrssd %edx,0x12345678(%rax,%rcx,8)",}, +{{0x41, 0x0f, 0x38, 0xf6, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"41 0f 38 f6 94 c8 78 56 34 12 \twrssd %edx,0x12345678(%r8,%rcx,8)",}, +{{0x48, 0x0f, 0x38, 0xf6, 0x08, }, 5, 0, "", "", +"48 0f 38 f6 08 \twrssq %rcx,(%rax)",}, +{{0x49, 0x0f, 0x38, 0xf6, 0x10, }, 5, 0, "", "", +"49 0f 38 f6 10 \twrssq %rdx,(%r8)",}, +{{0x48, 0x0f, 0x38, 0xf6, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"48 0f 38 f6 14 25 78 56 34 12 \twrssq %rdx,0x12345678",}, +{{0x48, 0x0f, 0x38, 0xf6, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"48 0f 38 f6 94 c8 78 56 34 12 \twrssq %rdx,0x12345678(%rax,%rcx,8)",}, +{{0x49, 0x0f, 0x38, 0xf6, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"49 0f 38 f6 94 c8 78 56 34 12 \twrssq %rdx,0x12345678(%r8,%rcx,8)",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x08, }, 5, 0, "", "", +"66 0f 38 f5 08 \twrussd %ecx,(%rax)",}, +{{0x66, 0x41, 0x0f, 0x38, 0xf5, 0x10, }, 6, 0, "", "", +"66 41 0f 38 f5 10 \twrussd %edx,(%r8)",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"66 0f 38 f5 14 25 78 56 34 12 \twrussd %edx,0x12345678",}, +{{0x66, 0x0f, 0x38, 0xf5, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"66 0f 38 f5 94 c8 78 56 34 12 \twrussd %edx,0x12345678(%rax,%rcx,8)",}, +{{0x66, 0x41, 0x0f, 0x38, 0xf5, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "", +"66 41 0f 38 f5 94 c8 78 56 34 12 \twrussd %edx,0x12345678(%r8,%rcx,8)",}, +{{0x66, 0x48, 0x0f, 0x38, 0xf5, 0x08, }, 6, 0, "", "", +"66 48 0f 38 f5 08 \twrussq %rcx,(%rax)",}, +{{0x66, 0x49, 0x0f, 0x38, 0xf5, 0x10, }, 6, 0, "", "", +"66 49 0f 38 f5 10 \twrussq %rdx,(%r8)",}, +{{0x66, 0x48, 0x0f, 0x38, 0xf5, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "", +"66 48 0f 38 f5 14 25 78 56 34 12 \twrussq %rdx,0x12345678",}, +{{0x66, 0x48, 0x0f, 0x38, 0xf5, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "", +"66 48 0f 38 f5 94 c8 78 56 34 12 \twrussq %rdx,0x12345678(%rax,%rcx,8)",}, +{{0x66, 0x49, 0x0f, 0x38, 0xf5, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "", +"66 49 0f 38 f5 94 c8 78 56 34 12 \twrussq %rdx,0x12345678(%r8,%rcx,8)",}, +{{0xf3, 0x0f, 0x01, 0xe8, }, 4, 0, "", "", +"f3 0f 01 e8 \tsetssbsy ",}, +{{0x0f, 0x01, 0xee, }, 3, 0, "", "", +"0f 01 ee \trdpkru ",}, +{{0x0f, 0x01, 0xef, }, 3, 0, "", "", +"0f 01 ef \twrpkru ",}, +{{0xf3, 0x0f, 0xae, 0x30, }, 4, 0, "", "", +"f3 0f ae 30 \tclrssbsy (%rax)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0x30, }, 5, 0, "", "", +"f3 41 0f ae 30 \tclrssbsy (%r8)",}, +{{0xf3, 0x0f, 0xae, 0x34, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae 34 25 78 56 34 12 \tclrssbsy 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae b4 c8 78 56 34 12 \tclrssbsy 0x12345678(%rax,%rcx,8)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 41 0f ae b4 c8 78 56 34 12 \tclrssbsy 0x12345678(%r8,%rcx,8)",}, +{{0xf3, 0x0f, 0x1e, 0xfb, }, 4, 0, "", "", +"f3 0f 1e fb \tendbr32 ",}, +{{0xf3, 0x0f, 0x1e, 0xfa, }, 4, 0, "", "", +"f3 0f 1e fa \tendbr64 ",}, +{{0xff, 0xd0, }, 2, 0, "call", "indirect", +"ff d0 \tcallq *%rax",}, +{{0xff, 0x10, }, 2, 0, "call", "indirect", +"ff 10 \tcallq *(%rax)",}, +{{0x41, 0xff, 0x10, }, 3, 0, "call", "indirect", +"41 ff 10 \tcallq *(%r8)",}, +{{0xff, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "call", "indirect", +"ff 14 25 78 56 34 12 \tcallq *0x12345678",}, +{{0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "call", "indirect", +"ff 94 c8 78 56 34 12 \tcallq *0x12345678(%rax,%rcx,8)",}, +{{0x41, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"41 ff 94 c8 78 56 34 12 \tcallq *0x12345678(%r8,%rcx,8)",}, +{{0xf2, 0xff, 0xd0, }, 3, 0, "call", "indirect", +"f2 ff d0 \tbnd callq *%rax",}, +{{0xf2, 0xff, 0x10, }, 3, 0, "call", "indirect", +"f2 ff 10 \tbnd callq *(%rax)",}, +{{0xf2, 0x41, 0xff, 0x10, }, 4, 0, "call", "indirect", +"f2 41 ff 10 \tbnd callq *(%r8)",}, +{{0xf2, 0xff, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"f2 ff 14 25 78 56 34 12 \tbnd callq *0x12345678",}, +{{0xf2, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"f2 ff 94 c8 78 56 34 12 \tbnd callq *0x12345678(%rax,%rcx,8)",}, +{{0xf2, 0x41, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "call", "indirect", +"f2 41 ff 94 c8 78 56 34 12 \tbnd callq *0x12345678(%r8,%rcx,8)",}, +{{0x3e, 0xff, 0xd0, }, 3, 0, "call", "indirect", +"3e ff d0 \tnotrack callq *%rax",}, +{{0x3e, 0xff, 0x10, }, 3, 0, "call", "indirect", +"3e ff 10 \tnotrack callq *(%rax)",}, +{{0x3e, 0x41, 0xff, 0x10, }, 4, 0, "call", "indirect", +"3e 41 ff 10 \tnotrack callq *(%r8)",}, +{{0x3e, 0xff, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"3e ff 14 25 78 56 34 12 \tnotrack callq *0x12345678",}, +{{0x3e, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "call", "indirect", +"3e ff 94 c8 78 56 34 12 \tnotrack callq *0x12345678(%rax,%rcx,8)",}, +{{0x3e, 0x41, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "call", "indirect", +"3e 41 ff 94 c8 78 56 34 12 \tnotrack callq *0x12345678(%r8,%rcx,8)",}, +{{0x3e, 0xf2, 0xff, 0xd0, }, 4, 0, "call", "indirect", +"3e f2 ff d0 \tnotrack bnd callq *%rax",}, +{{0x3e, 0xf2, 0xff, 0x10, }, 4, 0, "call", "indirect", +"3e f2 ff 10 \tnotrack bnd callq *(%rax)",}, +{{0x3e, 0xf2, 0x41, 0xff, 0x10, }, 5, 0, "call", "indirect", +"3e f2 41 ff 10 \tnotrack bnd callq *(%r8)",}, +{{0x3e, 0xf2, 0xff, 0x14, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "call", "indirect", +"3e f2 ff 14 25 78 56 34 12 \tnotrack bnd callq *0x12345678",}, +{{0x3e, 0xf2, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "call", "indirect", +"3e f2 ff 94 c8 78 56 34 12 \tnotrack bnd callq *0x12345678(%rax,%rcx,8)",}, +{{0x3e, 0xf2, 0x41, 0xff, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "call", "indirect", +"3e f2 41 ff 94 c8 78 56 34 12 \tnotrack bnd callq *0x12345678(%r8,%rcx,8)",}, +{{0xff, 0xe0, }, 2, 0, "jmp", "indirect", +"ff e0 \tjmpq *%rax",}, +{{0xff, 0x20, }, 2, 0, "jmp", "indirect", +"ff 20 \tjmpq *(%rax)",}, +{{0x41, 0xff, 0x20, }, 3, 0, "jmp", "indirect", +"41 ff 20 \tjmpq *(%r8)",}, +{{0xff, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "jmp", "indirect", +"ff 24 25 78 56 34 12 \tjmpq *0x12345678",}, +{{0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "jmp", "indirect", +"ff a4 c8 78 56 34 12 \tjmpq *0x12345678(%rax,%rcx,8)",}, +{{0x41, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"41 ff a4 c8 78 56 34 12 \tjmpq *0x12345678(%r8,%rcx,8)",}, +{{0xf2, 0xff, 0xe0, }, 3, 0, "jmp", "indirect", +"f2 ff e0 \tbnd jmpq *%rax",}, +{{0xf2, 0xff, 0x20, }, 3, 0, "jmp", "indirect", +"f2 ff 20 \tbnd jmpq *(%rax)",}, +{{0xf2, 0x41, 0xff, 0x20, }, 4, 0, "jmp", "indirect", +"f2 41 ff 20 \tbnd jmpq *(%r8)",}, +{{0xf2, 0xff, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"f2 ff 24 25 78 56 34 12 \tbnd jmpq *0x12345678",}, +{{0xf2, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"f2 ff a4 c8 78 56 34 12 \tbnd jmpq *0x12345678(%rax,%rcx,8)",}, +{{0xf2, 0x41, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "jmp", "indirect", +"f2 41 ff a4 c8 78 56 34 12 \tbnd jmpq *0x12345678(%r8,%rcx,8)",}, +{{0x3e, 0xff, 0xe0, }, 3, 0, "jmp", "indirect", +"3e ff e0 \tnotrack jmpq *%rax",}, +{{0x3e, 0xff, 0x20, }, 3, 0, "jmp", "indirect", +"3e ff 20 \tnotrack jmpq *(%rax)",}, +{{0x3e, 0x41, 0xff, 0x20, }, 4, 0, "jmp", "indirect", +"3e 41 ff 20 \tnotrack jmpq *(%r8)",}, +{{0x3e, 0xff, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"3e ff 24 25 78 56 34 12 \tnotrack jmpq *0x12345678",}, +{{0x3e, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "jmp", "indirect", +"3e ff a4 c8 78 56 34 12 \tnotrack jmpq *0x12345678(%rax,%rcx,8)",}, +{{0x3e, 0x41, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "jmp", "indirect", +"3e 41 ff a4 c8 78 56 34 12 \tnotrack jmpq *0x12345678(%r8,%rcx,8)",}, +{{0x3e, 0xf2, 0xff, 0xe0, }, 4, 0, "jmp", "indirect", +"3e f2 ff e0 \tnotrack bnd jmpq *%rax",}, +{{0x3e, 0xf2, 0xff, 0x20, }, 4, 0, "jmp", "indirect", +"3e f2 ff 20 \tnotrack bnd jmpq *(%rax)",}, +{{0x3e, 0xf2, 0x41, 0xff, 0x20, }, 5, 0, "jmp", "indirect", +"3e f2 41 ff 20 \tnotrack bnd jmpq *(%r8)",}, +{{0x3e, 0xf2, 0xff, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "jmp", "indirect", +"3e f2 ff 24 25 78 56 34 12 \tnotrack bnd jmpq *0x12345678",}, +{{0x3e, 0xf2, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "jmp", "indirect", +"3e f2 ff a4 c8 78 56 34 12 \tnotrack bnd jmpq *0x12345678(%rax,%rcx,8)",}, +{{0x3e, 0xf2, 0x41, 0xff, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "jmp", "indirect", +"3e f2 41 ff a4 c8 78 56 34 12 \tnotrack bnd jmpq *0x12345678(%r8,%rcx,8)",}, {{0x0f, 0x01, 0xcf, }, 3, 0, "", "", "0f 01 cf \tencls ",}, {{0x0f, 0x01, 0xd7, }, 3, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index ddbf07c50bb8..c3808e94c46e 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c @@ -1771,6 +1771,145 @@ int main(void) asm volatile("enqcmds (%eax),%ebx"); asm volatile("enqcmds 0x12345678(%eax),%ecx"); + /* incsspd/q */ + + asm volatile("incsspd %eax"); + asm volatile("incsspd %r8d"); + asm volatile("incsspq %rax"); + asm volatile("incsspq %r8"); + /* Also check instructions in the same group encoding as incsspd/q */ + asm volatile("xrstor (%rax)"); + asm volatile("xrstor (%r8)"); + asm volatile("xrstor (0x12345678)"); + asm volatile("xrstor 0x12345678(%rax,%rcx,8)"); + asm volatile("xrstor 0x12345678(%r8,%rcx,8)"); + asm volatile("lfence"); + + /* rdsspd/q */ + + asm volatile("rdsspd %eax"); + asm volatile("rdsspd %r8d"); + asm volatile("rdsspq %rax"); + asm volatile("rdsspq %r8"); + + /* saveprevssp */ + + asm volatile("saveprevssp"); + + /* rstorssp */ + + asm volatile("rstorssp (%rax)"); + asm volatile("rstorssp (%r8)"); + asm volatile("rstorssp (0x12345678)"); + asm volatile("rstorssp 0x12345678(%rax,%rcx,8)"); + asm volatile("rstorssp 0x12345678(%r8,%rcx,8)"); + + /* wrssd/q */ + + asm volatile("wrssd %ecx,(%rax)"); + asm volatile("wrssd %edx,(%r8)"); + asm volatile("wrssd %edx,(0x12345678)"); + asm volatile("wrssd %edx,0x12345678(%rax,%rcx,8)"); + asm volatile("wrssd %edx,0x12345678(%r8,%rcx,8)"); + asm volatile("wrssq %rcx,(%rax)"); + asm volatile("wrssq %rdx,(%r8)"); + asm volatile("wrssq %rdx,(0x12345678)"); + asm volatile("wrssq %rdx,0x12345678(%rax,%rcx,8)"); + asm volatile("wrssq %rdx,0x12345678(%r8,%rcx,8)"); + + /* wrussd/q */ + + asm volatile("wrussd %ecx,(%rax)"); + asm volatile("wrussd %edx,(%r8)"); + asm volatile("wrussd %edx,(0x12345678)"); + asm volatile("wrussd %edx,0x12345678(%rax,%rcx,8)"); + asm volatile("wrussd %edx,0x12345678(%r8,%rcx,8)"); + asm volatile("wrussq %rcx,(%rax)"); + asm volatile("wrussq %rdx,(%r8)"); + asm volatile("wrussq %rdx,(0x12345678)"); + asm volatile("wrussq %rdx,0x12345678(%rax,%rcx,8)"); + asm volatile("wrussq %rdx,0x12345678(%r8,%rcx,8)"); + + /* setssbsy */ + + asm volatile("setssbsy"); + /* Also check instructions in the same group encoding as setssbsy */ + asm volatile("rdpkru"); + asm volatile("wrpkru"); + + /* clrssbsy */ + + asm volatile("clrssbsy (%rax)"); + asm volatile("clrssbsy (%r8)"); + asm volatile("clrssbsy (0x12345678)"); + asm volatile("clrssbsy 0x12345678(%rax,%rcx,8)"); + asm volatile("clrssbsy 0x12345678(%r8,%rcx,8)"); + + /* endbr32/64 */ + + asm volatile("endbr32"); + asm volatile("endbr64"); + + /* call with/without notrack prefix */ + + asm volatile("callq *%rax"); /* Expecting: call indirect 0 */ + asm volatile("callq *(%rax)"); /* Expecting: call indirect 0 */ + asm volatile("callq *(%r8)"); /* Expecting: call indirect 0 */ + asm volatile("callq *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("callq *0x12345678(%rax,%rcx,8)"); /* Expecting: call indirect 0 */ + asm volatile("callq *0x12345678(%r8,%rcx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("bnd callq *%rax"); /* Expecting: call indirect 0 */ + asm volatile("bnd callq *(%rax)"); /* Expecting: call indirect 0 */ + asm volatile("bnd callq *(%r8)"); /* Expecting: call indirect 0 */ + asm volatile("bnd callq *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("bnd callq *0x12345678(%rax,%rcx,8)"); /* Expecting: call indirect 0 */ + asm volatile("bnd callq *0x12345678(%r8,%rcx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("notrack callq *%rax"); /* Expecting: call indirect 0 */ + asm volatile("notrack callq *(%rax)"); /* Expecting: call indirect 0 */ + asm volatile("notrack callq *(%r8)"); /* Expecting: call indirect 0 */ + asm volatile("notrack callq *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("notrack callq *0x12345678(%rax,%rcx,8)"); /* Expecting: call indirect 0 */ + asm volatile("notrack callq *0x12345678(%r8,%rcx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("notrack bnd callq *%rax"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd callq *(%rax)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd callq *(%r8)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd callq *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd callq *0x12345678(%rax,%rcx,8)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd callq *0x12345678(%r8,%rcx,8)"); /* Expecting: call indirect 0 */ + + /* jmp with/without notrack prefix */ + + asm volatile("jmpq *%rax"); /* Expecting: jmp indirect 0 */ + asm volatile("jmpq *(%rax)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmpq *(%r8)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmpq *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmpq *0x12345678(%rax,%rcx,8)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmpq *0x12345678(%r8,%rcx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("bnd jmpq *%rax"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmpq *(%rax)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmpq *(%r8)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmpq *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmpq *0x12345678(%rax,%rcx,8)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmpq *0x12345678(%r8,%rcx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("notrack jmpq *%rax"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmpq *(%rax)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmpq *(%r8)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmpq *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmpq *0x12345678(%rax,%rcx,8)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmpq *0x12345678(%r8,%rcx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("notrack bnd jmpq *%rax"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmpq *(%rax)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmpq *(%r8)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmpq *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmpq *0x12345678(%rax,%rcx,8)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmpq *0x12345678(%r8,%rcx,8)"); /* Expecting: jmp indirect 0 */ + #else /* #ifdef __x86_64__ */ /* bound r32, mem (same op code as EVEX prefix) */ @@ -3434,6 +3573,103 @@ int main(void) asm volatile("enqcmds (%si),%bx"); asm volatile("enqcmds 0x1234(%si),%cx"); + /* incsspd */ + + asm volatile("incsspd %eax"); + /* Also check instructions in the same group encoding as incsspd */ + asm volatile("xrstor (%eax)"); + asm volatile("xrstor (0x12345678)"); + asm volatile("xrstor 0x12345678(%eax,%ecx,8)"); + asm volatile("lfence"); + + /* rdsspd */ + + asm volatile("rdsspd %eax"); + + /* saveprevssp */ + + asm volatile("saveprevssp"); + + /* rstorssp */ + + asm volatile("rstorssp (%eax)"); + asm volatile("rstorssp (0x12345678)"); + asm volatile("rstorssp 0x12345678(%eax,%ecx,8)"); + + /* wrssd */ + + asm volatile("wrssd %ecx,(%eax)"); + asm volatile("wrssd %edx,(0x12345678)"); + asm volatile("wrssd %edx,0x12345678(%eax,%ecx,8)"); + + /* wrussd */ + + asm volatile("wrussd %ecx,(%eax)"); + asm volatile("wrussd %edx,(0x12345678)"); + asm volatile("wrussd %edx,0x12345678(%eax,%ecx,8)"); + + /* setssbsy */ + + asm volatile("setssbsy"); + /* Also check instructions in the same group encoding as setssbsy */ + asm volatile("rdpkru"); + asm volatile("wrpkru"); + + /* clrssbsy */ + + asm volatile("clrssbsy (%eax)"); + asm volatile("clrssbsy (0x12345678)"); + asm volatile("clrssbsy 0x12345678(%eax,%ecx,8)"); + + /* endbr32/64 */ + + asm volatile("endbr32"); + asm volatile("endbr64"); + + /* call with/without notrack prefix */ + + asm volatile("call *%eax"); /* Expecting: call indirect 0 */ + asm volatile("call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("call *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("call *0x12345678(%eax,%ecx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("bnd call *%eax"); /* Expecting: call indirect 0 */ + asm volatile("bnd call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("bnd call *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("bnd call *0x12345678(%eax,%ecx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("notrack call *%eax"); /* Expecting: call indirect 0 */ + asm volatile("notrack call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("notrack call *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("notrack call *0x12345678(%eax,%ecx,8)"); /* Expecting: call indirect 0 */ + + asm volatile("notrack bnd call *%eax"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd call *(0x12345678)"); /* Expecting: call indirect 0 */ + asm volatile("notrack bnd call *0x12345678(%eax,%ecx,8)"); /* Expecting: call indirect 0 */ + + /* jmp with/without notrack prefix */ + + asm volatile("jmp *%eax"); /* Expecting: jmp indirect 0 */ + asm volatile("jmp *(%eax)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmp *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("jmp *0x12345678(%eax,%ecx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("bnd jmp *%eax"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmp *(%eax)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmp *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jmp *0x12345678(%eax,%ecx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("notrack jmp *%eax"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmp *(%eax)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmp *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack jmp *0x12345678(%eax,%ecx,8)"); /* Expecting: jmp indirect 0 */ + + asm volatile("notrack bnd jmp *%eax"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmp *(%eax)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmp *(0x12345678)"); /* Expecting: jmp indirect 0 */ + asm volatile("notrack bnd jmp *0x12345678(%eax,%ecx,8)"); /* Expecting: jmp indirect 0 */ + #endif /* #ifndef __x86_64__ */ /* SGX */ From 26567ed79d13ec54b2c5661ce8a07fd149a23a9b Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Tue, 4 Feb 2020 18:37:09 +0100 Subject: [PATCH 642/809] perf script: Introduce --deltatime option For some kind of analysis a deltatime output is more human friendly and reduce the cognitive load for further analysis. The following output demonstrate the new option "deltatime": calculate the time difference in relation to the previous event. $ perf script --deltatime test 2525 [001] 0.000000: sdt_libev:ev_add: (5635e72a5ebd) test 2525 [001] 0.000091: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 1.000051: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 test 2525 [001] 0.000685: sdt_libev:ev_add: (5635e72a5ebd) test 2525 [001] 0.000048: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 1.000104: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 test 2525 [001] 0.003895: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 0.996034: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 test 2525 [001] 0.000058: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 1.000004: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 test 2525 [001] 0.000064: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 0.999934: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 test 2525 [001] 0.000056: sdt_libev:epoll_wait_enter: (5635e72a76a9) test 2525 [001] 0.999930: sdt_libev:epoll_wait_return: (5635e72a772e) arg1=1 Committer testing: So go from default output to --reltime and then this new --deltatime, to contrast the various timestamp presentation modes for a random perf.data file I had laying around: [root@five ~]# perf script --reltime | head perf 442394 [000] 0.000000: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000002: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000004: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000006: 128 cycles: ffffffff972415a1 perf_event_update_userpage+0x1 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000009: 2597 cycles: ffffffff97463785 cap_task_setscheduler+0x5 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000036: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000038: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000040: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000041: 224 cycles: ffffffff9700a53a perf_ibs_handle_irq+0x1da (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000044: 4439 cycles: ffffffff97120d85 put_prev_entity+0x45 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) [root@five ~]# perf script --deltatime | head perf 442394 [000] 0.000000: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000002: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000001: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000001: 128 cycles: ffffffff972415a1 perf_event_update_userpage+0x1 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 0.000002: 2597 cycles: ffffffff97463785 cap_task_setscheduler+0x5 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000027: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000002: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000001: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000001: 224 cycles: ffffffff9700a53a perf_ibs_handle_irq+0x1da (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 0.000002: 4439 cycles: ffffffff97120d85 put_prev_entity+0x45 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) [root@five ~]# perf script | head perf 442394 [000] 7600.157861: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 7600.157864: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 7600.157866: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 7600.157867: 128 cycles: ffffffff972415a1 perf_event_update_userpage+0x1 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [000] 7600.157870: 2597 cycles: ffffffff97463785 cap_task_setscheduler+0x5 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 7600.157897: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 7600.157900: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 7600.157901: 16 cycles: ffffffff9706e544 native_write_msr+0x4 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 7600.157903: 224 cycles: ffffffff9700a53a perf_ibs_handle_irq+0x1da (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) perf 442394 [001] 7600.157906: 4439 cycles: ffffffff97120d85 put_prev_entity+0x45 (/usr/lib/debug/lib/modules/5.5.10-200.fc31.x86_64/vmlinux) [root@five ~]# Andi suggested we better implement it as a new field, i.e. -F deltatime, like: [root@five ~]# perf script -F deltatime Invalid field requested. Usage: perf script [] or: perf script [] record