From ad37616e9048123ab664bf2064604888e25c539f Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Fri, 12 Jun 2015 19:01:07 +0300 Subject: iio: Documentation: Add additional *scale_available attributes Added some more *scale_available attributes to the list that are used in various drivers but were missiong from Documentation. Signed-off-by: Adriana Reus Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index bbed111c31b4..666a341b01b8 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -413,6 +413,11 @@ Description: to compute the calories burnt by the user. What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale_available +What: /sys/.../iio:deviceX/in_anglvel_scale_available +What: /sys/.../iio:deviceX/in_magn_scale_available +What: /sys/.../iio:deviceX/in_illuminance_scale_available +What: /sys/.../iio:deviceX/in_intensity_scale_available +What: /sys/.../iio:deviceX/in_proximity_scale_available What: /sys/.../iio:deviceX/in_voltageX_scale_available What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available What: /sys/.../iio:deviceX/out_voltageX_scale_available -- cgit v1.2.3-59-g8ed1b From 0760bacef728f6c980278188a5aac7f0fbe8bed8 Mon Sep 17 00:00:00 2001 From: Karsten Merker Date: Tue, 23 Jun 2015 19:02:29 +0200 Subject: devicetree: Add msi to the vendor-prefix list Document the the "msi" (Micro-Star International Co. Ltd.) vendor prefix which is used in sun6i-a31s-primo81.dts. Signed-off-by: Karsten Merker Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9e..c80e1173bbee 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -135,6 +135,7 @@ mitsubishi Mitsubishi Electric Corporation mosaixtech Mosaix Technologies, Inc. moxa Moxa mpl MPL AG +msi Micro-Star International Co. Ltd. mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) mundoreader Mundo Reader S.L. murata Murata Manufacturing Co., Ltd. -- cgit v1.2.3-59-g8ed1b From 859e42800bcfc4db9cefaa2c24d6e3a203fe961d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Jun 2015 08:17:03 +0200 Subject: dt-bindings: soc: Add documentation for the MediaTek SCPSYS unit This adds documentation for the MediaTek SCPSYS unit found in MT8173 SoCs. Signed-off-by: Sascha Hauer Reviewed-by: Daniel Kurtz Signed-off-by: Matthias Brugger --- .../devicetree/bindings/soc/mediatek/scpsys.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/mediatek/scpsys.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt new file mode 100644 index 000000000000..c0511142b39c --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt @@ -0,0 +1,41 @@ +MediaTek SCPSYS +=============== + +The System Control Processor System (SCPSYS) has several power management +related tasks in the system. The tasks include thermal measurement, dynamic +voltage frequency scaling (DVFS), interrupt filter and lowlevel sleep control. +The System Power Manager (SPM) inside the SCPSYS is for the MTCMOS power +domain control. + +The driver implements the Generic PM domain bindings described in +power/power_domain.txt. It provides the power domains defined in +include/dt-bindings/power/mt8173-power.h. + +Required properties: +- compatible: Must be "mediatek,mt8173-scpsys" +- #power-domain-cells: Must be 1 +- reg: Address range of the SCPSYS unit +- infracfg: must contain a phandle to the infracfg controller +- clock, clock-names: clocks according to the common clock binding. + The clocks needed "mm" and "mfg". These are the + clocks which hardware needs to be enabled before + enabling certain power domains. + +Example: + + scpsys: scpsys@10006000 { + #power-domain-cells = <1>; + compatible = "mediatek,mt8173-scpsys"; + reg = <0 0x10006000 0 0x1000>; + infracfg = <&infracfg>; + clocks = <&clk26m>, + <&topckgen CLK_TOP_MM_SEL>; + clock-names = "mfg", "mm"; + }; + +Example consumer: + + afe: mt8173-afe-pcm@11220000 { + compatible = "mediatek,mt8173-afe-pcm"; + power-domains = <&scpsys MT8173_POWER_DOMAIN_AUDIO>; + }; -- cgit v1.2.3-59-g8ed1b From e76ea35ae723013392a0f61fcc16026506c0aa7f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 5 Jul 2015 11:00:17 +0200 Subject: dt-bindings: add documentation of rk3668 clock controller Add the devicetree binding for the cru on the rk3368 which quite similar structured as previous clock controllers. Signed-off-by: Heiko Stuebner Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: devicetree@vger.kernel.org Signed-off-by: Stephen Boyd --- .../bindings/clock/rockchip,rk3368-cru.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt new file mode 100644 index 000000000000..7c8bbcfed8d2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3368 Clock and Reset Unit + +The RK3368 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3368-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing, pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3368-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_gmac" - external GMAC clock - optional + - "ext_hsadc" - external HSADC clock - optional, + - "ext_isp" - external ISP clock - optional, + - "ext_jtag" - external JTAG clock - optional + - "ext_vip" - external VIP clock - optional, + - "usbotg_out" - output clock of the pll in the otg phy + +Example: Clock controller node: + + cru: clock-controller@ff760000 { + compatible = "rockchip,rk3368-cru"; + reg = <0x0 0xff760000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; -- cgit v1.2.3-59-g8ed1b From 80eeb1f0f757c790b020d9f425bb0e824973d49c Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 28 Jun 2015 16:24:55 +0200 Subject: clk: add gpio controlled clock multiplexer Add a common clock driver for basic gpio controlled clock multiplexers. This driver can be used for devices like 5V41068A or 831721I from IDT or for discrete multiplexer circuits. The 'select' pin selects one of two parent clocks. Cc: Jyri Sarha Signed-off-by: Sergej Sawazki [sboyd@codeaurora.org: Fix error paths to free memory and do it in the correct order] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/gpio-mux-clock.txt | 19 ++ drivers/clk/clk-gpio-gate.c | 242 +++++++++++++++------ include/linux/clk-provider.h | 17 ++ 3 files changed, 214 insertions(+), 64 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/gpio-mux-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt new file mode 100644 index 000000000000..2be1e038ca62 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt @@ -0,0 +1,19 @@ +Binding for simple gpio clock multiplexer. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "gpio-mux-clock". +- clocks: list of two references to parent clocks. +- #clock-cells : from common clock binding; shall be set to 0. +- select-gpios : GPIO reference for selecting the parent clock. + +Example: + clock { + compatible = "gpio-mux-clock"; + clocks = <&parentclk1>, <&parentclk2>; + #clock-cells = <0>; + select-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index ef942daa955a..c0d202c24a97 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -1,12 +1,15 @@ /* * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com - * Author: Jyri Sarha + * + * Authors: + * Jyri Sarha + * Sergej Sawazki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Gpio gated clock implementation + * Gpio controlled clock implementation */ #include @@ -61,24 +64,55 @@ const struct clk_ops clk_gpio_gate_ops = { EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); /** - * clk_register_gpio - register a gpip clock with the clock framework - * @dev: device that is registering this clock - * @name: name of this clock - * @parent_name: name of this clock's parent - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock - * @flags: clock flags + * DOC: basic clock multiplexer which can be controlled with a gpio output + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * rate - rate is only affected by parent switching. No clk_set_rate support + * parent - parent is adjustable through clk_set_parent */ -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags) + +static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) { - struct clk_gpio *clk_gpio = NULL; - struct clk *clk = ERR_PTR(-EINVAL); - struct clk_init_data init = { NULL }; + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, index); + + return 0; +} + +const struct clk_ops clk_gpio_mux_ops = { + .get_parent = clk_gpio_mux_get_parent, + .set_parent = clk_gpio_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); + +static struct clk *clk_register_gpio(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags, + const struct clk_ops *clk_gpio_ops) +{ + struct clk_gpio *clk_gpio; + struct clk *clk; + struct clk_init_data init = {}; unsigned long gpio_flags; int err; + if (dev) + clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL); + else + clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL); + + if (!clk_gpio) + return ERR_PTR(-ENOMEM); + if (active_low) gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; else @@ -88,70 +122,108 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, err = devm_gpio_request_one(dev, gpio, gpio_flags, name); else err = gpio_request_one(gpio, gpio_flags, name); - if (err) { if (err != -EPROBE_DEFER) pr_err("%s: %s: Error requesting clock control gpio %u\n", __func__, name, gpio); - return ERR_PTR(err); - } - - if (dev) - clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio), - GFP_KERNEL); - else - clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL); + if (!dev) + kfree(clk_gpio); - if (!clk_gpio) { - clk = ERR_PTR(-ENOMEM); - goto clk_register_gpio_gate_err; + return ERR_PTR(err); } init.name = name; - init.ops = &clk_gpio_gate_ops; + init.ops = clk_gpio_ops; init.flags = flags | CLK_IS_BASIC; - init.parent_names = (parent_name ? &parent_name : NULL); - init.num_parents = (parent_name ? 1 : 0); + init.parent_names = parent_names; + init.num_parents = num_parents; clk_gpio->gpiod = gpio_to_desc(gpio); clk_gpio->hw.init = &init; - clk = clk_register(dev, &clk_gpio->hw); + if (dev) + clk = devm_clk_register(dev, &clk_gpio->hw); + else + clk = clk_register(NULL, &clk_gpio->hw); if (!IS_ERR(clk)) return clk; - if (!dev) + if (!dev) { + gpiod_put(clk_gpio->gpiod); kfree(clk_gpio); - -clk_register_gpio_gate_err: - if (!dev) - gpio_free(gpio); + } return clk; } + +/** + * clk_register_gpio_gate - register a gpio clock gate with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags) +{ + return clk_register_gpio(dev, name, + (parent_name ? &parent_name : NULL), + (parent_name ? 1 : 0), gpio, active_low, flags, + &clk_gpio_gate_ops); +} EXPORT_SYMBOL_GPL(clk_register_gpio_gate); +/** + * clk_register_gpio_mux - register a gpio clock mux with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_names: names of this clock's parents + * @num_parents: number of parents listed in @parent_names + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags) +{ + if (num_parents != 2) { + pr_err("mux-clock %s must have 2 parents\n", name); + return ERR_PTR(-EINVAL); + } + + return clk_register_gpio(dev, name, parent_names, num_parents, + gpio, active_low, flags, &clk_gpio_mux_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_mux); + #ifdef CONFIG_OF /** - * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER + * clk_register_get() has to be delayed, because -EPROBE_DEFER * can not be handled properly at of_clk_init() call time. */ -struct clk_gpio_gate_delayed_register_data { +struct clk_gpio_delayed_register_data { + const char *gpio_name; struct device_node *node; struct mutex lock; struct clk *clk; + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low); }; -static struct clk *of_clk_gpio_gate_delayed_register_get( - struct of_phandle_args *clkspec, - void *_data) +static struct clk *of_clk_gpio_delayed_register_get( + struct of_phandle_args *clkspec, void *_data) { - struct clk_gpio_gate_delayed_register_data *data = _data; + struct clk_gpio_delayed_register_data *data = _data; struct clk *clk; - const char *clk_name = data->node->name; - const char *parent_name; + const char **parent_names; + int i, num_parents; int gpio; enum of_gpio_flags of_flags; @@ -162,47 +234,89 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( return data->clk; } - gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, - &of_flags); + gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, + &of_flags); if (gpio < 0) { mutex_unlock(&data->lock); - if (gpio != -EPROBE_DEFER) - pr_err("%s: %s: Can't get 'enable-gpios' DT property\n", - __func__, clk_name); + if (gpio == -EPROBE_DEFER) + pr_debug("%s: %s: GPIOs not yet available, retry later\n", + data->node->name, __func__); + else + pr_err("%s: %s: Can't get '%s' DT property\n", + data->node->name, __func__, + data->gpio_name); return ERR_PTR(gpio); } - parent_name = of_clk_get_parent_name(data->node, 0); + num_parents = of_clk_get_parent_count(data->node); - clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio, - of_flags & OF_GPIO_ACTIVE_LOW, 0); - if (IS_ERR(clk)) { - mutex_unlock(&data->lock); - return clk; - } + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(data->node, i); + + clk = data->clk_register_get(data->node->name, parent_names, + num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + if (IS_ERR(clk)) + goto out; data->clk = clk; +out: mutex_unlock(&data->lock); + kfree(parent_names); return clk; } -/** - * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock - */ -static void __init of_gpio_gate_clk_setup(struct device_node *node) +static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low) +{ + return clk_register_gpio_gate(NULL, name, parent_names[0], + gpio, active_low, 0); +} + +static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low) +{ + return clk_register_gpio_mux(NULL, name, parent_names, num_parents, + gpio, active_low, 0); +} + +static void __init of_gpio_clk_setup(struct device_node *node, + const char *gpio_name, + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low)) { - struct clk_gpio_gate_delayed_register_data *data; + struct clk_gpio_delayed_register_data *data; - data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data), - GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return; data->node = node; + data->gpio_name = gpio_name; + data->clk_register_get = clk_register_get; mutex_init(&data->lock); - of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); + of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); +} + +static void __init of_gpio_gate_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "enable-gpios", + of_clk_gpio_gate_delayed_register_get); } CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); + +void __init of_gpio_mux_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "select-gpios", + of_clk_gpio_mux_delayed_register_get); +} +CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); #endif diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 78842f46f152..823d7f70878e 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -549,6 +549,23 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, void of_gpio_clk_gate_setup(struct device_node *node); +/** + * struct clk_gpio_mux - gpio controlled clock multiplexer + * + * @hw: see struct clk_gpio + * @gpiod: gpio descriptor to select the parent of this clock multiplexer + * + * Clock with a gpio control for selecting the parent clock. + * Implements .get_parent, .set_parent and .determine_rate + */ + +extern const struct clk_ops clk_gpio_mux_ops; +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags); + +void of_gpio_mux_clk_setup(struct device_node *node); + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock -- cgit v1.2.3-59-g8ed1b From 93e3a9e9993ef018522b7005d97d8124b7e73385 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 18 Jun 2015 13:27:12 +0100 Subject: spi: img-spfi: check for max speed supported by the spfi block Maximum speed supported by spfi is limited to 1/4 of the spfi clock. But in some SoCs the maximum speed supported by the spfi block can be limited to less than 1/4 of the spfi clock. In such cases we have to define the limit in the device tree so that the driver can pick it up. Signed-off-by: Sifan Naeem Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-img-spfi.txt | 1 + drivers/spi/spi-img-spfi.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt index e02fbf18c82c..494db6012d02 100644 --- a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt +++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt @@ -21,6 +21,7 @@ Required properties: Optional properties: - img,supports-quad-mode: Should be set if the interface supports quad mode SPI transfers. +- spfi-max-frequency: Maximum speed supported by the spfi block. Example: diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 788e2b176a4f..f31d792a4662 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -546,6 +546,7 @@ static int img_spfi_probe(struct platform_device *pdev) struct img_spfi *spfi; struct resource *res; int ret; + u32 max_speed_hz; master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); if (!master) @@ -610,6 +611,19 @@ static int img_spfi_probe(struct platform_device *pdev) master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; + /* + * Maximum speed supported by spfi is limited to the lower value + * between 1/4 of the SPFI clock or to "spfi-max-frequency" + * defined in the device tree. + * If no value is defined in the device tree assume the maximum + * speed supported to be 1/4 of the SPFI clock. + */ + if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency", + &max_speed_hz)) { + if (master->max_speed_hz > max_speed_hz) + master->max_speed_hz = max_speed_hz; + } + master->setup = img_spfi_setup; master->cleanup = img_spfi_cleanup; master->transfer_one = img_spfi_transfer_one; -- cgit v1.2.3-59-g8ed1b From 3692db3a904800445f8af249e1ac0f2b6496f31d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 1 Jul 2015 18:31:43 +0530 Subject: regulator: max8973: add support to configure ETR from DT The MAX8973/MAX77621 feature an Enhanced Transient Response(ETR) circuit that is enabled through software. The enhanced transient response reduces the voltage droop during large load steps by temporarily allowing all three phases to fire in unison, slewing total inductor current faster than would normally be possible if all three phases continued to operate 120deg out of phase. The enhanced transient response detector features two selectable sensitivity settings, which select the output voltage slew rate during load transients that triggers the ETR circuit. The sensitivity of the ETR detector is set by the CKADV[1:0] bits in the CONTROL2 register. Add support to configure the ETR through platform data from DT. Update the DT binding document accordingly. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- .../bindings/regulator/max8973-regulator.txt | 6 ++++++ drivers/regulator/max8973-regulator.c | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt index 55efb24e5683..f80ea2fe27e6 100644 --- a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt @@ -25,6 +25,12 @@ Optional properties: -maxim,enable-frequency-shift: boolean, enable 9% frequency shift. -maxim,enable-bias-control: boolean, enable bias control. By enabling this startup delay can be reduce to 20us from 220us. +-maxim,enable-etr: boolean, enable Enhanced Transient Response. +-maxim,enable-high-etr-sensitivity: boolean, Enhanced transient response + circuit is enabled and set for high sensitivity. If this + property is available then etr will be enable default. + +Enhanced transient response (ETR) will affect the configuration of CKADV. Example: diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index e94ddcf97722..a8fd7f4dd8d8 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -421,6 +421,8 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( struct device_node *np = dev->of_node; int ret; u32 pval; + bool etr_enable; + bool etr_sensitivity_high; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -452,6 +454,23 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( if (of_property_read_bool(np, "maxim,enable-bias-control")) pdata->control_flags |= MAX8973_CONTROL_BIAS_ENABLE; + etr_enable = of_property_read_bool(np, "maxim,enable-etr"); + etr_sensitivity_high = of_property_read_bool(np, + "maxim,enable-high-etr-sensitivity"); + if (etr_sensitivity_high) + etr_enable = true; + + if (etr_enable) { + if (etr_sensitivity_high) + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US; + else + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US; + } else { + pdata->control_flags |= MAX8973_CONTROL_CLKADV_TRIP_DISABLED; + } + return pdata; } -- cgit v1.2.3-59-g8ed1b From 02258b8bcbb98b28064cc829f7062455da398633 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:50 +0100 Subject: regulator: pwm-regulator: Re-write bindings * Add support for continuous-voltage mode * Put more meat on the bones with regards to voltage-table mode * Sort out formatting for ease of consumption Cc: devicetree@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- .../bindings/regulator/pwm-regulator.txt | 68 ++++++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index ce91f61feb12..892b36655b3d 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -1,27 +1,71 @@ -pwm regulator bindings +Bindings for the Generic PWM Regulator +====================================== + +Currently supports 2 modes of operation: + +voltage-table: When in this mode, a voltage table (See below) of + predefined voltage <=> duty-cycle values must be + provided via DT. Limitations are that the regulator can + only operate at the voltages supplied in the table. + Intermediary duty-cycle values which would normally + allow finer grained voltage selection are ignored and + rendered useless. Although more control is given to + the user if the assumptions made in continuous-voltage + mode do not reign true. + +continuous-voltage: This mode uses the regulator's maximum and minimum + supplied voltages specified in the + regulator-{min,max}-microvolt properties to calculate + appropriate duty-cycle values. This allows for a much + more fine grained solution when compared with + voltage-table mode above. This solution does make an + assumption that a %50 duty-cycle value will cause the + regulator voltage to run at half way between the + supplied max_uV and min_uV values. Required properties: -- compatible: Should be "pwm-regulator" -- pwms: OF device-tree PWM specification (see PWM binding pwm.txt) -- voltage-table: voltage and duty table, include 2 members in each set of - brackets, first one is voltage(unit: uv), the next is duty(unit: percent) +-------------------- +- compatible: Should be "pwm-regulator" + +- pwms: PWM specification (See: ../pwm/pwm.txt) + +One of these must be provided: +- voltage-table: Voltage and Duty-Cycle table consisting of 2 cells + First cell is voltage in microvolts (uV) + Second cell is duty-cycle in percent (%) + +- max-duty-cycle: Maximum Duty-Cycle value -- this will normally be + 255 (0xff) for an 8 bit PWM device -Any property defined as part of the core regulator binding defined in -regulator.txt can also be used. +If both are provided, the current default is voltage-table mode. -Example: +Any property defined as part of the core regulator binding can also be used. +(See: ../regulator/regulator.txt) + +Continuous Voltage Example: pwm_regulator { compatible = "pwm-regulator; pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + + max-duty-cycle = <255>; /* 8bit PWM */ + }; +Voltage Table Example: + pwm_regulator { + compatible = "pwm-regulator; + pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + + /* Voltage Duty-Cycle */ voltage-table = <1114000 0>, <1095000 10>, <1076000 20>, <1056000 30>, <1036000 40>, <1016000 50>; - - regulator-min-microvolt = <1016000>; - regulator-max-microvolt = <1114000>; - regulator-name = "vdd_logic"; }; -- cgit v1.2.3-59-g8ed1b From e54e4b1b622e534381b422b8a80a21453dd6f644 Mon Sep 17 00:00:00 2001 From: Roger Shimizu Date: Tue, 23 Jun 2015 00:00:16 +0900 Subject: ARM: dts: add buffalo linkstation ls-wxl/wsxl Add dts file to support Buffalo Linkstation LS-WXL and LS-WSXL, which are 2-bay NAS with 3.5" and 2.5" HDD respectively. Signed-off-by: Roger Shimizu Reviewed-by: Nobuhiro Iwamatsu Acked-by: Andrew Lunn Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- .../devicetree/bindings/arm/marvell,kirkwood.txt | 1 + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/kirkwood-lswxl.dts | 301 +++++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 arch/arm/boot/dts/kirkwood-lswxl.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt index 4f40ff3fee4b..b79212f60ac4 100644 --- a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt +++ b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt @@ -20,6 +20,7 @@ And in addition, the compatible shall be extended with the specific board. Currently known boards are: "buffalo,lschlv2" +"buffalo,lswxl" "buffalo,lsxhl" "buffalo,lsxl" "dlink,dns-320" diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 246473a244f6..9afd1c955c43 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -176,6 +176,7 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \ kirkwood-km_kirkwood.dtb \ kirkwood-laplug.dtb \ kirkwood-lschlv2.dtb \ + kirkwood-lswxl.dtb \ kirkwood-lsxhl.dtb \ kirkwood-mplcec4.dtb \ kirkwood-mv88f6281gtw-ge.dtb \ diff --git a/arch/arm/boot/dts/kirkwood-lswxl.dts b/arch/arm/boot/dts/kirkwood-lswxl.dts new file mode 100644 index 000000000000..f5db16a08597 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-lswxl.dts @@ -0,0 +1,301 @@ +/* + * Device Tree file for Buffalo Linkstation LS-WXL/WSXL + * + * Copyright (C) 2015, rogershimizu@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6281.dtsi" + +/ { + model = "Buffalo Linkstation LS-WXL/WSXL"; + compatible = "buffalo,lswxl", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; + }; + + mbus { + pcie-controller { + status = "okay"; + pcie@1,0 { + status = "okay"; + }; + }; + }; + + ocp@f1000000 { + pinctrl: pin-controller@10000 { + pmx_power_hdd0: pmx-power-hdd0 { + marvell,pins = "mpp28"; + marvell,function = "gpio"; + }; + pmx_power_hdd1: pmx-power-hdd1 { + marvell,pins = "mpp29"; + marvell,function = "gpio"; + }; + pmx_usb_vbus: pmx-usb-vbus { + marvell,pins = "mpp37"; + marvell,function = "gpio"; + }; + pmx_fan_high: pmx-fan-high { + marvell,pins = "mpp47"; + marvell,function = "gpio"; + }; + pmx_fan_low: pmx-fan-low { + marvell,pins = "mpp48"; + marvell,function = "gpio"; + }; + pmx_led_hdderr0: pmx-led-hdderr0 { + marvell,pins = "mpp8"; + marvell,function = "gpio"; + }; + pmx_led_hdderr1: pmx-led-hdderr1 { + marvell,pins = "mpp46"; + marvell,function = "gpio"; + }; + pmx_led_alarm: pmx-led-alarm { + marvell,pins = "mpp49"; + marvell,function = "gpio"; + }; + pmx_led_function_red: pmx-led-function-red { + marvell,pins = "mpp34"; + marvell,function = "gpio"; + }; + pmx_led_function_blue: pmx-led-function-blue { + marvell,pins = "mpp36"; + marvell,function = "gpio"; + }; + pmx_led_info: pmx-led-info { + marvell,pins = "mpp38"; + marvell,function = "gpio"; + }; + pmx_led_power: pmx-led-power { + marvell,pins = "mpp39"; + marvell,function = "gpio"; + }; + pmx_fan_lock: pmx-fan-lock { + marvell,pins = "mpp40"; + marvell,function = "gpio"; + }; + pmx_button_function: pmx-button-function { + marvell,pins = "mpp41"; + marvell,function = "gpio"; + }; + pmx_power_switch: pmx-power-switch { + marvell,pins = "mpp42"; + marvell,function = "gpio"; + }; + pmx_power_auto_switch: pmx-power-auto-switch { + marvell,pins = "mpp43"; + marvell,function = "gpio"; + }; + }; + + serial@12000 { + status = "okay"; + }; + + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + + spi@10600 { + status = "okay"; + + m25p40@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p40", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + mode = <0>; + + partition@0 { + reg = <0x0 0x60000>; + label = "uboot"; + read-only; + }; + + partition@60000 { + reg = <0x60000 0x10000>; + label = "dtb"; + read-only; + }; + + partition@70000 { + reg = <0x70000 0x10000>; + label = "uboot_env"; + }; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_button_function &pmx_power_switch + &pmx_power_auto_switch>; + pinctrl-names = "default"; + + button@1 { + label = "Function Button"; + linux,code = ; + gpios = <&gpio1 41 GPIO_ACTIVE_LOW>; + }; + + button@2 { + label = "Power-on Switch"; + linux,code = ; + linux,input-type = <5>; + gpios = <&gpio1 42 GPIO_ACTIVE_LOW>; + }; + + button@3 { + label = "Power-auto Switch"; + linux,code = ; + linux,input-type = <5>; + gpios = <&gpio1 43 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_leds { + compatible = "gpio-leds"; + pinctrl-0 = <&pmx_led_function_red &pmx_led_alarm + &pmx_led_info &pmx_led_power + &pmx_led_function_blue + &pmx_led_hdderr0 + &pmx_led_hdderr1>; + pinctrl-names = "default"; + + led@1 { + label = "lswxl:blue:func"; + gpios = <&gpio1 36 GPIO_ACTIVE_LOW>; + }; + + led@2 { + label = "lswxl:red:alarm"; + gpios = <&gpio1 49 GPIO_ACTIVE_LOW>; + }; + + led@3 { + label = "lswxl:amber:info"; + gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + }; + + led@4 { + label = "lswxl:blue:power"; + gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + }; + + led@5 { + label = "lswxl:red:func"; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + + led@6 { + label = "lswxl:red:hdderr0"; + gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + }; + + led@7 { + label = "lswxl:red:hdderr1"; + gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_fan { + compatible = "gpio-fan"; + pinctrl-0 = <&pmx_fan_low &pmx_fan_high &pmx_fan_lock>; + pinctrl-names = "default"; + + gpios = <&gpio0 47 GPIO_ACTIVE_LOW + &gpio0 48 GPIO_ACTIVE_LOW>; + + gpio-fan,speed-map = <0 3 + 1500 2 + 3250 1 + 5000 0>; + + alarm-gpios = <&gpio1 49 GPIO_ACTIVE_HIGH>; + }; + + restart_poweroff { + compatible = "restart-poweroff"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_power_hdd0 &pmx_power_hdd1 &pmx_usb_vbus>; + pinctrl-names = "default"; + + usb_power: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "USB Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 37 GPIO_ACTIVE_HIGH>; + }; + hdd_power0: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "HDD0 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 28 GPIO_ACTIVE_HIGH>; + }; + hdd_power1: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "HDD1 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&mdio { + status = "okay"; + + ethphy1: ethernet-phy@8 { + device_type = "ethernet-phy"; + reg = <8>; + }; +}; + +ð1 { + status = "okay"; + + ethernet1-port@0 { + phy-handle = <ðphy1>; + }; +}; -- cgit v1.2.3-59-g8ed1b From c43379e150aa335b447f14e55cefd8f1c405cb5f Mon Sep 17 00:00:00 2001 From: Roger Shimizu Date: Tue, 23 Jun 2015 00:02:30 +0900 Subject: ARM: dts: add buffalo linkstation ls-wvl/vl Add dts file to support Buffalo Linkstation LS-WVL and LS-VL, which are 3.5" HDD NAS in 2-bay and 1-bay respectively. [gregory.clement@free-electrons.com: fix typo in pmx-led-function-red] Signed-off-by: Roger Shimizu Reviewed-by: Nobuhiro Iwamatsu Acked-by: Andrew Lunn Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- .../devicetree/bindings/arm/marvell,kirkwood.txt | 1 + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/kirkwood-lswvl.dts | 301 +++++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 arch/arm/boot/dts/kirkwood-lswvl.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt index b79212f60ac4..5171ad8f48ff 100644 --- a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt +++ b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt @@ -20,6 +20,7 @@ And in addition, the compatible shall be extended with the specific board. Currently known boards are: "buffalo,lschlv2" +"buffalo,lswvl" "buffalo,lswxl" "buffalo,lsxhl" "buffalo,lsxl" diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 9afd1c955c43..0f354f590a25 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -176,6 +176,7 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \ kirkwood-km_kirkwood.dtb \ kirkwood-laplug.dtb \ kirkwood-lschlv2.dtb \ + kirkwood-lswvl.dtb \ kirkwood-lswxl.dtb \ kirkwood-lsxhl.dtb \ kirkwood-mplcec4.dtb \ diff --git a/arch/arm/boot/dts/kirkwood-lswvl.dts b/arch/arm/boot/dts/kirkwood-lswvl.dts new file mode 100644 index 000000000000..09eed3cea0af --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-lswvl.dts @@ -0,0 +1,301 @@ +/* + * Device Tree file for Buffalo Linkstation LS-WVL/VL + * + * Copyright (C) 2015, rogershimizu@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6282.dtsi" + +/ { + model = "Buffalo Linkstation LS-WVL/VL"; + compatible = "buffalo,lswvl", "buffalo,lsvl", "marvell,kirkwood-88f6282", "marvell,kirkwood"; + + memory { /* 256 MB */ + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; + }; + + mbus { + pcie-controller { + status = "okay"; + pcie@1,0 { + status = "okay"; + }; + }; + }; + + ocp@f1000000 { + pinctrl: pin-controller@10000 { + pmx_power_hdd0: pmx-power-hdd0 { + marvell,pins = "mpp8"; + marvell,function = "gpio"; + }; + pmx_power_hdd1: pmx-power-hdd1 { + marvell,pins = "mpp9"; + marvell,function = "gpio"; + }; + pmx_usb_vbus: pmx-usb-vbus { + marvell,pins = "mpp12"; + marvell,function = "gpio"; + }; + pmx_fan_high: pmx-fan-high { + marvell,pins = "mpp16"; + marvell,function = "gpio"; + }; + pmx_fan_low: pmx-fan-low { + marvell,pins = "mpp17"; + marvell,function = "gpio"; + }; + pmx_led_hdderr0: pmx-led-hdderr0 { + marvell,pins = "mpp34"; + marvell,function = "gpio"; + }; + pmx_led_hdderr1: pmx-led-hdderr1 { + marvell,pins = "mpp35"; + marvell,function = "gpio"; + }; + pmx_led_alarm: pmx-led-alarm { + marvell,pins = "mpp36"; + marvell,function = "gpio"; + }; + pmx_led_function_red: pmx-led-function-red { + marvell,pins = "mpp37"; + marvell,function = "gpio"; + }; + pmx_led_info: pmx-led-info { + marvell,pins = "mpp38"; + marvell,function = "gpio"; + }; + pmx_led_function_blue: pmx-led-function-blue { + marvell,pins = "mpp39"; + marvell,function = "gpio"; + }; + pmx_led_power: pmx-led-power { + marvell,pins = "mpp40"; + marvell,function = "gpio"; + }; + pmx_fan_lock: pmx-fan-lock { + marvell,pins = "mpp43"; + marvell,function = "gpio"; + }; + pmx_button_function: pmx-button-function { + marvell,pins = "mpp45"; + marvell,function = "gpio"; + }; + pmx_power_switch: pmx-power-switch { + marvell,pins = "mpp46"; + marvell,function = "gpio"; + }; + pmx_power_auto_switch: pmx-power-auto-switch { + marvell,pins = "mpp47"; + marvell,function = "gpio"; + }; + }; + + serial@12000 { + status = "okay"; + }; + + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + + spi@10600 { + status = "okay"; + + m25p40@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p40", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + mode = <0>; + + partition@0 { + reg = <0x0 0x60000>; + label = "uboot"; + read-only; + }; + + partition@60000 { + reg = <0x60000 0x10000>; + label = "dtb"; + read-only; + }; + + partition@70000 { + reg = <0x70000 0x10000>; + label = "uboot_env"; + }; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_button_function &pmx_power_switch + &pmx_power_auto_switch>; + pinctrl-names = "default"; + + button@1 { + label = "Function Button"; + linux,code = ; + gpios = <&gpio0 45 GPIO_ACTIVE_LOW>; + }; + + button@2 { + label = "Power-on Switch"; + linux,code = ; + linux,input-type = <5>; + gpios = <&gpio0 46 GPIO_ACTIVE_LOW>; + }; + + button@3 { + label = "Power-auto Switch"; + linux,code = ; + linux,input-type = <5>; + gpios = <&gpio0 47 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_leds { + compatible = "gpio-leds"; + pinctrl-0 = <&pmx_led_function_red &pmx_led_alarm + &pmx_led_info &pmx_led_power + &pmx_led_function_blue + &pmx_led_hdderr0 + &pmx_led_hdderr1>; + pinctrl-names = "default"; + + led@1 { + label = "lswvl:red:alarm"; + gpios = <&gpio0 36 GPIO_ACTIVE_LOW>; + }; + + led@2 { + label = "lswvl:red:func"; + gpios = <&gpio0 37 GPIO_ACTIVE_LOW>; + }; + + led@3 { + label = "lswvl:amber:info"; + gpios = <&gpio0 38 GPIO_ACTIVE_LOW>; + }; + + led@4 { + label = "lswvl:blue:func"; + gpios = <&gpio0 39 GPIO_ACTIVE_LOW>; + }; + + led@5 { + label = "lswvl:blue:power"; + gpios = <&gpio0 40 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + + led@6 { + label = "lswvl:red:hdderr0"; + gpios = <&gpio0 34 GPIO_ACTIVE_LOW>; + }; + + led@7 { + label = "lswvl:red:hdderr1"; + gpios = <&gpio0 35 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_fan { + compatible = "gpio-fan"; + pinctrl-0 = <&pmx_fan_low &pmx_fan_high &pmx_fan_lock>; + pinctrl-names = "default"; + + gpios = <&gpio0 17 GPIO_ACTIVE_LOW + &gpio0 16 GPIO_ACTIVE_LOW>; + + gpio-fan,speed-map = <0 3 + 1500 2 + 3250 1 + 5000 0>; + + alarm-gpios = <&gpio0 43 GPIO_ACTIVE_HIGH>; + }; + + restart_poweroff { + compatible = "restart-poweroff"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_power_hdd0 &pmx_power_hdd1 &pmx_usb_vbus>; + pinctrl-names = "default"; + + usb_power: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "USB Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + hdd_power0: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "HDD0 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 8 GPIO_ACTIVE_HIGH>; + }; + hdd_power1: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "HDD1 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 9 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&mdio { + status = "okay"; + + ethphy0: ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; +}; + +ð0 { + status = "okay"; + + ethernet0-port@0 { + phy-handle = <ðphy0>; + }; +}; -- cgit v1.2.3-59-g8ed1b From a505bfb10a0fc6f4342a2521b899d61ff2461e72 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:26 +0100 Subject: regulator: pwm-regulator: Ensure headings aren't confused with properties We're using capitalisation and removing the '-' to mitigate confusion. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/pwm-regulator.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index 892b36655b3d..23b47720b2e4 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -3,7 +3,7 @@ Bindings for the Generic PWM Regulator Currently supports 2 modes of operation: -voltage-table: When in this mode, a voltage table (See below) of +Voltage Table: When in this mode, a voltage table (See below) of predefined voltage <=> duty-cycle values must be provided via DT. Limitations are that the regulator can only operate at the voltages supplied in the table. @@ -13,7 +13,7 @@ voltage-table: When in this mode, a voltage table (See below) of the user if the assumptions made in continuous-voltage mode do not reign true. -continuous-voltage: This mode uses the regulator's maximum and minimum +Continuous Voltage: This mode uses the regulator's maximum and minimum supplied voltages specified in the regulator-{min,max}-microvolt properties to calculate appropriate duty-cycle values. This allows for a much -- cgit v1.2.3-59-g8ed1b From f747a1fe7848453957dbdf362a42d7a6735c6ff0 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:27 +0100 Subject: regulator: pwm-regulator: Remove obsoleted property In "[3d7ef30] regulator: pwm-regulator: Simplify voltage to duty-cycle call" we stopped using max_duty_cycle, so we can retire it from device data and DT. There is no need to deprecate this property, as it hasn't hit Mainline yet. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/pwm-regulator.txt | 11 ++++------- drivers/regulator/pwm-regulator.c | 9 --------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index 23b47720b2e4..ed936f0f34f2 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -29,15 +29,14 @@ Required properties: - pwms: PWM specification (See: ../pwm/pwm.txt) -One of these must be provided: +Only required for Voltage Table Mode: - voltage-table: Voltage and Duty-Cycle table consisting of 2 cells First cell is voltage in microvolts (uV) Second cell is duty-cycle in percent (%) -- max-duty-cycle: Maximum Duty-Cycle value -- this will normally be - 255 (0xff) for an 8 bit PWM device - -If both are provided, the current default is voltage-table mode. +NB: To be clear, if voltage-table is provided, then the device will be used +in Voltage Table Mode. If no voltage-table is provided, then the device will +be used in Continuous Voltage Mode. Any property defined as part of the core regulator binding can also be used. (See: ../regulator/regulator.txt) @@ -49,8 +48,6 @@ Continuous Voltage Example: regulator-min-microvolt = <1016000>; regulator-max-microvolt = <1114000>; regulator-name = "vdd_logic"; - - max-duty-cycle = <255>; /* 8bit PWM */ }; Voltage Table Example: diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index cb482089050b..d92e66772ec0 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -30,7 +30,6 @@ struct pwm_regulator_data { int state; /* Continuous voltage */ - u32 max_duty_cycle; int volt_uV; }; @@ -201,14 +200,6 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { struct device_node *np = pdev->dev.of_node; - int ret; - - ret = of_property_read_u32(np, "max-duty-cycle", - &drvdata->max_duty_cycle); - if (ret) { - dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n"); - return ret; - } pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; pwm_regulator_desc.continuous_voltage_range = true; -- cgit v1.2.3-59-g8ed1b From d6eff078e0bf9f24dcc2c7fcdbdf26b57148b197 Mon Sep 17 00:00:00 2001 From: Sébastien Hinderer Date: Wed, 8 Jul 2015 21:12:32 +0200 Subject: SubmittingPatches: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 7e0befc8e48a49e2ddf86bbd861027b14ea5a53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Hinderer?= Date: Wed, 8 Jul 2015 21:10:18 +0200 Subject: [PATCH] SubmittingPatches: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="utf-8" Signed-off-by: Sébastien Hinderer Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 27e7e5edeca8..e9395dfc4190 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -267,7 +267,7 @@ You should always copy the appropriate subsystem maintainer(s) on any patch to code that they maintain; look through the MAINTAINERS file and the source code revision history to see who those maintainers are. The script scripts/get_maintainer.pl can be very useful at this step. If you -cannot find a maintainer for the subsystem your are working on, Andrew +cannot find a maintainer for the subsystem you are working on, Andrew Morton (akpm@linux-foundation.org) serves as a maintainer of last resort. You should also normally choose at least one mailing list to receive a copy -- cgit v1.2.3-59-g8ed1b From bd760c498f009e2a6795952469af6f8e6edac05a Mon Sep 17 00:00:00 2001 From: Daniel Grimshaw Date: Wed, 8 Jul 2015 10:44:51 -0700 Subject: Documentation: filesystems: btrfs: Fixed typos and whitespace I am a high school student trying to become familiar with Linux kernel development. The btrfs documentation in Documentation/filesystems had a few typos and errors in whitespace. This patch corrects both of these. Signed-off-by: Daniel Grimshaw Signed-off-by: Jonathan Corbet --- Documentation/filesystems/btrfs.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/btrfs.txt b/Documentation/filesystems/btrfs.txt index d11cc2f8077b..c772b47e7ef0 100644 --- a/Documentation/filesystems/btrfs.txt +++ b/Documentation/filesystems/btrfs.txt @@ -61,7 +61,7 @@ Options with (*) are default options and will not show in the mount options. check_int enables the integrity checker module, which examines all block write requests to ensure on-disk consistency, at a large - memory and CPU cost. + memory and CPU cost. check_int_data includes extent data in the integrity checks, and implies the check_int option. @@ -113,7 +113,7 @@ Options with (*) are default options and will not show in the mount options. Disable/enable debugging option to be more verbose in some ENOSPC conditions. fatal_errors= - Action to take when encountering a fatal error: + Action to take when encountering a fatal error: "bug" - BUG() on a fatal error. This is the default. "panic" - panic() on a fatal error. @@ -132,10 +132,10 @@ Options with (*) are default options and will not show in the mount options. max_inline= Specify the maximum amount of space, in bytes, that can be inlined in - a metadata B-tree leaf. The value is specified in bytes, optionally + a metadata B-tree leaf. The value is specified in bytes, optionally with a K, M, or G suffix, case insensitive. In practice, this value is limited by the root sector size, with some space unavailable due - to leaf headers. For a 4k sectorsize, max inline data is ~3900 bytes. + to leaf headers. For a 4k sector size, max inline data is ~3900 bytes. metadata_ratio= Specify that 1 metadata chunk should be allocated after every @@ -170,7 +170,7 @@ Options with (*) are default options and will not show in the mount options. recovery Enable autorecovery attempts if a bad tree root is found at mount time. - Currently this scans a list of several previous tree roots and tries to + Currently this scans a list of several previous tree roots and tries to use the first readable. rescan_uuid_tree @@ -194,7 +194,7 @@ Options with (*) are default options and will not show in the mount options. ssd_spread Options to control ssd allocation schemes. By default, BTRFS will enable or disable ssd allocation heuristics depending on whether a - rotational or nonrotational disk is in use. The ssd and nossd options + rotational or non-rotational disk is in use. The ssd and nossd options can override this autodetection. The ssd_spread mount option attempts to allocate into big chunks @@ -216,13 +216,13 @@ Options with (*) are default options and will not show in the mount options. This allows mounting of subvolumes which are not in the root of the mounted filesystem. You can use "btrfs subvolume show " to see the object ID for a subvolume. - + thread_pool= The number of worker threads to allocate. The default number is equal to the number of CPUs + 2, or 8, whichever is smaller. user_subvol_rm_allowed - Allow subvolumes to be deleted by a non-root user. Use with caution. + Allow subvolumes to be deleted by a non-root user. Use with caution. MAILING LIST ============ -- cgit v1.2.3-59-g8ed1b From 32c1735c4091ef0de8e39f68a9d83a07450b959b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 8 Jul 2015 20:06:44 +0100 Subject: DocBook: Don't store mtime (or name) in compressed man pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mtime on a man page is the build time. As gzip stores the mtime and original name in the compressed file by default, this makes compressed man pages unreproducible. Neither of these are important metadata in this case, so turn this off. Reported-by: Jérémy Bobbio Signed-off-by: Ben Hutchings Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b6a6a2e0dd3b..11a41456b943 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -56,7 +56,7 @@ htmldocs: $(HTML) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) - find $(obj)/man -name '*.9' | xargs gzip -f + find $(obj)/man -name '*.9' | xargs gzip -nf installmandocs: mandocs mkdir -p /usr/local/man/man9/ -- cgit v1.2.3-59-g8ed1b From b48ed85145711b28f9024dcdaf6c0238d7b5042c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 8 Jul 2015 20:06:51 +0100 Subject: DocBook: Generate consistent IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, DocBook XSL uses a non-deterministic function to generate IDs for HTML elements where it can't take a name from the input document. However, it has the option to generate 'consistent' (deterministic) IDs instead. Enable this to make the HTML pages reproducible. Reported-by: Jérémy Bobbio Signed-off-by: Ben Hutchings Signed-off-by: Jonathan Corbet --- Documentation/DocBook/stylesheet.xsl | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl index 85b25275196f..3bf4ecf3d760 100644 --- a/Documentation/DocBook/stylesheet.xsl +++ b/Documentation/DocBook/stylesheet.xsl @@ -5,6 +5,7 @@ 80 0 +1 2 1 -- cgit v1.2.3-59-g8ed1b From b44158b17099ed5c7c8f4bfb7029942adbfbc318 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 8 Jul 2015 20:07:05 +0100 Subject: DocBook: Avoid building man pages repeatedly and inconsistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some kernel-doc sections are included in multiple DocBook files. This means the mandocs target will generate the same manual page multiple times with different metadata (author name/address and manual title, taken from the including DocBook file). If it's invoked in a parallel build, the output is nondeterminstic. For each section that is duplicated, mark the less specific manual's inclusion as 'extra' and exclude it during conversion to manual pages. Use xmlif for this, as that is bundled with xmlto which we already use. I would have preferred to use more conventional markup for this, but each of the following approaches failed: 1. Wrap the extra inclusions with a new element and add a template to the stylesheet to include/exclude them. Unfortunately DocBook XSL doesn't seem to support foreign elements at an intermediate level in the document tree. 2. Use DocBook profiling. This works but requires passing an absolute path to the profile stylesheet to xmlto, so it's not portable. 3. Use SGML marked sections. docbook2x can handle these but xmlto chokes on them. Reported-by: Jérémy Bobbio Signed-off-by: Ben Hutchings Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 10 +++++++++- Documentation/DocBook/device-drivers.tmpl | 6 ++++++ Documentation/DocBook/gadget.tmpl | 3 +++ Documentation/DocBook/kernel-api.tmpl | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 11a41456b943..83fcb6c2a00f 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -56,6 +56,13 @@ htmldocs: $(HTML) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) + @dups=$$(sed -n 's/.*\([^<]*\)<\/refname>.*/\1/p' \ + $(obj)/*.xml.noextra | sort | uniq -d); \ + if [ -n "$$dups" ]; then \ + echo >&2 "The following manual pages are generated more than once:"; \ + printf >&2 '%s\n' "$$dups"; \ + exit 1; \ + fi find $(obj)/man -name '*.9' | xargs gzip -nf installmandocs: mandocs @@ -150,7 +157,7 @@ quiet_cmd_db2html = HTML $@ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi quiet_cmd_db2man = MAN $@ - cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi + cmd_db2man = if grep -q refentry $<; then xmlif excludeextra=1 <$< >$<.noextra && xmlto man $(XMLTOFLAGS) -o $(obj)/man $<.noextra ; fi %.9 : %.xml @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ @@ -217,6 +224,7 @@ clean-files := $(DOCBOOKS) \ $(patsubst %.xml, %.ps, $(DOCBOOKS)) \ $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ $(patsubst %.xml, %.html, $(DOCBOOKS)) \ + $(patsubst %, %.noextra, $(DOCBOOKS)) \ $(patsubst %.xml, %.9, $(DOCBOOKS)) \ $(index) diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index faf09d4a0ea8..87853ea1f70b 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -194,8 +194,13 @@ X!Edrivers/pnp/system.c Sound Devices + + !Iinclude/sound/core.h + !Esound/sound_core.c + + !Iinclude/sound/pcm.h !Esound/core/pcm.c !Esound/core/device.c @@ -211,6 +216,7 @@ X!Edrivers/pnp/system.c !Esound/core/hwdep.c !Esound/core/pcm_native.c !Esound/core/memalloc.c + diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index 641629221176..e1b87bd63f82 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -488,7 +488,10 @@ These are the same types and constants used by host side drivers (and usbcore). + + !Iinclude/linux/usb/ch9.h + Core Objects and Methods diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index ecfd0ea40661..722249a0dbfe 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -58,8 +58,11 @@ String Conversions !Elib/vsprintf.c + + !Finclude/linux/kernel.h kstrtol !Finclude/linux/kernel.h kstrtoul + !Elib/kstrtox.c String Manipulation @@ -178,7 +181,10 @@ X!Ekernel/module.c Hardware Interfaces Interrupt Handling + + !Ekernel/irq/manage.c + DMA Channels -- cgit v1.2.3-59-g8ed1b From 4b10df7f2c8b3c6de12375b85456c6fd275af6d0 Mon Sep 17 00:00:00 2001 From: "Olivier C. Larocque" Date: Thu, 2 Jul 2015 21:33:23 -0400 Subject: Documentation: CodingStyle: remove broken links in the References section Remove 2 broken links for programming reference books in Appendix I. After a lookup on an Internet archives web site, it seems that these links have been broken for around 3 months. We can then assume that they will not be back up and safely remove them from the documentation. Signed-off-by: Olivier C. Larocque Signed-off-by: Jonathan Corbet --- Documentation/CodingStyle | 2 -- 1 file changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index b713c35f8543..c06f817b3091 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -929,13 +929,11 @@ The C Programming Language, Second Edition by Brian W. Kernighan and Dennis M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback). -URL: http://cm.bell-labs.com/cm/cs/cbook/ The Practice of Programming by Brian W. Kernighan and Rob Pike. Addison-Wesley, Inc., 1999. ISBN 0-201-61586-X. -URL: http://cm.bell-labs.com/cm/cs/tpop/ GNU manuals - where in compliance with K&R and this text - for cpp, gcc, gcc internals and indent, all available from http://www.gnu.org/manual/ -- cgit v1.2.3-59-g8ed1b From 60498bb58e9a614b9706f250667033f30632a25c Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 3 Jul 2015 16:22:11 +0100 Subject: SubmittingPatches: update CodingStyle reference Link to the internal up to date Coding Style document inside the Kernel sources instead of an external one. Signed-off-by: Luis de Bethencourt Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index e9395dfc4190..67cf50914bbd 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -796,7 +796,7 @@ NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people! Kernel Documentation/CodingStyle: - + Linus Torvalds's mail on the canonical patch format: -- cgit v1.2.3-59-g8ed1b From 9ba6e988c7208e3cb1f71862cc578397ae938159 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 5 Jul 2015 11:56:51 +0900 Subject: Documentation: ARM: EXYNOS: Extend boot loader interface documentation Extend the kernel-bootloader interface documentation with usage of register INFORM1 (0x0804) and different CPU resume address on Exynos542x family (with Multi-Cluster Power Management enabled). Additionally add glossary and reformat section titles. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Corbet --- Documentation/arm/Samsung/Bootloader-interface.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/arm/Samsung/Bootloader-interface.txt b/Documentation/arm/Samsung/Bootloader-interface.txt index b96ead9a6919..df8d4fb85939 100644 --- a/Documentation/arm/Samsung/Bootloader-interface.txt +++ b/Documentation/arm/Samsung/Bootloader-interface.txt @@ -15,6 +15,7 @@ executing kernel. 1. Non-Secure mode + Address: sysram_ns_base_addr Offset Value Purpose ============================================================================= @@ -28,6 +29,7 @@ Offset Value Purpose 2. Secure mode + Address: sysram_base_addr Offset Value Purpose ============================================================================= @@ -40,14 +42,25 @@ Offset Value Purpose Address: pmu_base_addr Offset Value Purpose ============================================================================= -0x0800 exynos_cpu_resume AFTR +0x0800 exynos_cpu_resume AFTR, suspend +0x0800 mcpm_entry_point (Exynos542x with MCPM) AFTR, suspend +0x0804 0xfcba0d10 (Magic cookie) AFTR +0x0804 0x00000bad (Magic cookie) System suspend 0x0814 exynos4_secondary_startup (Exynos4210 r1.1) Secondary CPU boot 0x0818 0xfcba0d10 (Magic cookie, Exynos4210 r1.1) AFTR 0x081C exynos_cpu_resume (Exynos4210 r1.1) AFTR 3. Other (regardless of secure/non-secure mode) + Address: pmu_base_addr Offset Value Purpose ============================================================================= 0x0908 Non-zero (only Exynos3250) Secondary CPU boot up indicator + + +4. Glossary + +AFTR - ARM Off Top Running, a low power mode, Cortex cores and many other +modules are power gated, except the TOP modules +MCPM - Multi-Cluster Power Management -- cgit v1.2.3-59-g8ed1b From dc12f20ba06f89bc60d4dfadaf2b03404858e205 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 6 Jul 2015 23:41:57 +0900 Subject: Doc: powerpc: Fix typos in Documentation/powerpc This patch fix some spelling typo found in Documentation/powerpc. Signed-off-by: Masanari Iida Acked-by: Ian Munsie Signed-off-by: Jonathan Corbet --- Documentation/powerpc/cxl.txt | 2 +- Documentation/powerpc/dscr.txt | 6 +++--- Documentation/powerpc/qe_firmware.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/powerpc/cxl.txt b/Documentation/powerpc/cxl.txt index 2a230d01cd8c..205c1b81625c 100644 --- a/Documentation/powerpc/cxl.txt +++ b/Documentation/powerpc/cxl.txt @@ -133,7 +133,7 @@ User API The following file operations are supported on both slave and master devices. - A userspace library libcxl is avaliable here: + A userspace library libcxl is available here: https://github.com/ibm-capi/libcxl This provides a C interface to this kernel API. diff --git a/Documentation/powerpc/dscr.txt b/Documentation/powerpc/dscr.txt index 1ff4400c57b3..ece300c64f76 100644 --- a/Documentation/powerpc/dscr.txt +++ b/Documentation/powerpc/dscr.txt @@ -4,7 +4,7 @@ DSCR register in powerpc allows user to have some control of prefetch of data stream in the processor. Please refer to the ISA documents or related manual for more detailed information regarding how to use this DSCR to attain this -control of the pefetches . This document here provides an overview of kernel +control of the prefetches . This document here provides an overview of kernel support for DSCR, related kernel objects, it's functionalities and exported user interface. @@ -44,7 +44,7 @@ user interface. value into every CPU's DSCR register right away and updates the current thread's DSCR value as well. - Changing the CPU specif DSCR default value in the sysfs does exactly + Changing the CPU specific DSCR default value in the sysfs does exactly the same thing as above but unlike the global one above, it just changes stuff for that particular CPU instead for all the CPUs on the system. @@ -62,7 +62,7 @@ user interface. Accessing DSCR through user level SPR (0x03) from user space will first create a facility unavailable exception. Inside this exception handler - all mfspr isntruction based read attempts will get emulated and returned + all mfspr instruction based read attempts will get emulated and returned where as the first mtspr instruction based write attempts will enable the DSCR facility for the next time around (both for read and write) by setting DSCR facility in the FSCR register. diff --git a/Documentation/powerpc/qe_firmware.txt b/Documentation/powerpc/qe_firmware.txt index 2031ddb33d09..e7ac24aec4ff 100644 --- a/Documentation/powerpc/qe_firmware.txt +++ b/Documentation/powerpc/qe_firmware.txt @@ -117,7 +117,7 @@ specific been defined. This table describes the structure. Extended Modes This is a double word bit array (64 bits) that defines special functionality -which has an impact on the softwarew drivers. Each bit has its own impact +which has an impact on the software drivers. Each bit has its own impact and has special instructions for the s/w associated with it. This structure is described in this table: -- cgit v1.2.3-59-g8ed1b From 03bc7523cb4241a7f4ad67d7ae38027d1884a3ee Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Wed, 8 Jul 2015 10:41:07 +0200 Subject: can-doc: Fix wrong chapter reference In f35f6c8f7 (can: update MAINTAINERS and Documentation) chapter 3.3 was removed. This patch fixes some old references to chapter 3.4 which no longer exists. Signed-off-by: Stefan Tatschner Signed-off-by: Jonathan Corbet --- Documentation/networking/can.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index b48d4a149411..fd1a1aad49a9 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -510,7 +510,7 @@ solution for a couple of reasons: 4.1.2 RAW socket option CAN_RAW_ERR_FILTER - As described in chapter 3.4 the CAN interface driver can generate so + As described in chapter 3.3 the CAN interface driver can generate so called Error Message Frames that can optionally be passed to the user application in the same way as other CAN frames. The possible errors are divided into different error classes that may be filtered @@ -1152,7 +1152,7 @@ solution for a couple of reasons: $ ip link set canX type can restart Note that a restart will also create a CAN error message frame (see - also chapter 3.4). + also chapter 3.3). 6.6 CAN FD (flexible data rate) driver support -- cgit v1.2.3-59-g8ed1b From 4245746037e379dc9f1388e422d52001cd431921 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 24 Jun 2015 14:14:21 +0200 Subject: regulator: da9210: Add optional interrupt support Add optional interrupt support to the da9210 regulator driver, to handle over-current, under- and over-voltage, and over-temperature events. Only the interrupt sources for which we handle events are unmasked, to avoid interrupts we cannot handle. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/da9210.txt | 4 ++ drivers/regulator/da9210-regulator.c | 75 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/da9210.txt b/Documentation/devicetree/bindings/regulator/da9210.txt index 3297c53cb915..7aa9b1fa6b21 100644 --- a/Documentation/devicetree/bindings/regulator/da9210.txt +++ b/Documentation/devicetree/bindings/regulator/da9210.txt @@ -5,6 +5,10 @@ Required properties: - compatible: must be "dlg,da9210" - reg: the i2c slave address of the regulator. It should be 0x68. +Optional properties: + +- interrupts: a reference to the DA9210 interrupt, if available. + Any standard regulator properties can be used to configure the single da9210 DCDC. diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0489cb9018b..8e39f7457bc3 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -120,6 +122,55 @@ static int da9210_get_current_limit(struct regulator_dev *rdev) return da9210_buck_limits[sel]; } +static irqreturn_t da9210_irq_handler(int irq, void *data) +{ + struct da9210 *chip = data; + unsigned int val, handled = 0; + int error, ret = IRQ_NONE; + + error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val); + if (error < 0) + goto error_i2c; + + if (val & DA9210_E_OVCURR) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_CURRENT, + NULL); + handled |= DA9210_E_OVCURR; + } + if (val & DA9210_E_NPWRGOOD) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + handled |= DA9210_E_NPWRGOOD; + } + if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_TEMP, NULL); + handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT); + } + if (val & DA9210_E_VMAX) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_REGULATION_OUT, + NULL); + handled |= DA9210_E_VMAX; + } + if (handled) { + /* Clear handled events */ + error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled); + if (error < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + return ret; + +error_i2c: + dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error); + return ret; +} + /* * I2C driver interface functions */ @@ -168,6 +219,30 @@ static int da9210_i2c_probe(struct i2c_client *i2c, } chip->rdev = rdev; + if (i2c->irq) { + error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + da9210_irq_handler, + IRQF_TRIGGER_LOW | + IRQF_ONESHOT | IRQF_SHARED, + "da9210", chip); + if (error) { + dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n", + i2c->irq, error); + return error; + } + + error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B, + DA9210_M_OVCURR | DA9210_M_NPWRGOOD | + DA9210_M_TEMP_WARN | + DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0); + if (error < 0) { + dev_err(&i2c->dev, "Failed to update mask reg: %d\n", + error); + return error; + } + } else { + dev_warn(&i2c->dev, "No IRQ configured\n"); + } i2c_set_clientdata(i2c, chip); -- cgit v1.2.3-59-g8ed1b From 7bd393543287b921f964a350166bf2866527a1b5 Mon Sep 17 00:00:00 2001 From: James Ban Date: Tue, 30 Jun 2015 13:39:39 +0900 Subject: regulator: da9211: support da9215 This is a patch for supporting da9215 buck converter. Signed-off-by: James Ban Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/da9211.txt | 32 +++++++++++++++-- drivers/regulator/Kconfig | 6 ++-- drivers/regulator/da9211-regulator.c | 40 ++++++++++++++++------ drivers/regulator/da9211-regulator.h | 18 +++++----- include/linux/regulator/da9211.h | 19 +++++----- 5 files changed, 81 insertions(+), 34 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt index eb618907c7de..c620493e8dbe 100644 --- a/Documentation/devicetree/bindings/regulator/da9211.txt +++ b/Documentation/devicetree/bindings/regulator/da9211.txt @@ -1,7 +1,7 @@ -* Dialog Semiconductor DA9211/DA9213 Voltage Regulator +* Dialog Semiconductor DA9211/DA9213/DA9215 Voltage Regulator Required properties: -- compatible: "dlg,da9211" or "dlg,da9213". +- compatible: "dlg,da9211" or "dlg,da9213" or "dlg,da9215" - reg: I2C slave address, usually 0x68. - interrupts: the interrupt outputs of the controller - regulators: A node that houses a sub-node for each regulator within the @@ -66,3 +66,31 @@ Example 2) DA9213 }; }; }; + + +Example 3) DA9215 + pmic: da9215@68 { + compatible = "dlg,da9215"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..23496da101de 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -209,13 +209,13 @@ config REGULATOR_DA9210 interface. config REGULATOR_DA9211 - tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator" + tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator" depends on I2C select REGMAP_I2C help Say y here to support for the Dialog Semiconductor DA9211/DA9212 - /DA9213/DA9214. - The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous + /DA9213/DA9214/DA9215. + The DA9211/DA9212/DA9213/DA9214/DA9215 is a multi-phase synchronous step down converter 12A or 16A DC-DC Buck controlled through an I2C interface. diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index df79e4b1946e..0858100d2d03 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,6 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,6 +32,7 @@ /* DEVICE IDs */ #define DA9211_DEVICE_ID 0x22 #define DA9213_DEVICE_ID 0x23 +#define DA9215_DEVICE_ID 0x24 #define DA9211_BUCK_MODE_SLEEP 1 #define DA9211_BUCK_MODE_SYNC 2 @@ -90,6 +91,13 @@ static const int da9213_current_limits[] = { 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 }; +/* Current limits for DA9215 buck (uA) indices + * corresponds with register values + */ +static const int da9215_current_limits[] = { + 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, + 5600000, 5800000, 6000000, 6200000, 6400000, 6600000, 6800000, 7000000 +}; static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) { @@ -157,6 +165,10 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, current_limits = da9213_current_limits; max_size = ARRAY_SIZE(da9213_current_limits)-1; break; + case DA9215: + current_limits = da9215_current_limits; + max_size = ARRAY_SIZE(da9215_current_limits)-1; + break; default: return -EINVAL; } @@ -189,6 +201,9 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) case DA9213: current_limits = da9213_current_limits; break; + case DA9215: + current_limits = da9215_current_limits; + break; default: return -EINVAL; } @@ -350,13 +365,11 @@ static int da9211_regulator_init(struct da9211 *chip) /* If configuration for 1/2 bucks is different between platform data * and the register, driver should exit. */ - if ((chip->pdata->num_buck == 2 && data == 0x40) - || (chip->pdata->num_buck == 1 && data == 0x00)) { - if (data == 0) - chip->num_regulator = 1; - else - chip->num_regulator = 2; - } else { + if (chip->pdata->num_buck == 1 && data == 0x00) + chip->num_regulator = 1; + else if (chip->pdata->num_buck == 2 && data != 0x00) + chip->num_regulator = 2; + else { dev_err(chip->dev, "Configuration is mismatched\n"); return -EINVAL; } @@ -438,6 +451,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, case DA9213_DEVICE_ID: chip->chip_id = DA9213; break; + case DA9215_DEVICE_ID: + chip->chip_id = DA9215; + break; default: dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); return -ENODEV; @@ -478,6 +494,7 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, {"da9213", DA9213}, + {"da9215", DA9215}, {}, }; MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); @@ -486,6 +503,7 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -504,5 +522,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban "); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index 93fa9df2721c..d6ad96fc64d3 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,16 +1,16 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DA9211_REGISTERS_H__ diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h index 5dd65acc2a69..a43a5ca1167b 100644 --- a/include/linux/regulator/da9211.h +++ b/include/linux/regulator/da9211.h @@ -1,16 +1,16 @@ /* - * da9211.h - Regulator device driver for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211.h - Regulator device driver for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __LINUX_REGULATOR_DA9211_H @@ -23,6 +23,7 @@ enum da9211_chip_id { DA9211, DA9213, + DA9215, }; struct da9211_pdata { -- cgit v1.2.3-59-g8ed1b From a8069fafe8a3ce1567e2394b8551902ede300445 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Sun, 21 Jun 2015 20:23:48 -0300 Subject: of: add vendor prefix for CIAA project CIAA stands for Argentine Open Industrial Computer. The CIAA project is an initiative sponsored by universities and private companies. Its main goal is to promote local embedded systems development. Among other devices, the project developed a NXP LPC4337-based reference design. Signed-off-by: Ezequiel Garcia Signed-off-by: Joachim Eastwood --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9e..c2f0af7b276d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -46,6 +46,7 @@ chipone ChipOne chipspark ChipSPARK chrp Common Hardware Reference Platform chunghwa Chunghwa Picture Tubes Ltd. +ciaa Computadora Industrial Abierta Argentina cirrus Cirrus Logic, Inc. cloudengines Cloud Engines, Inc. cnm Chips&Media, Inc. -- cgit v1.2.3-59-g8ed1b From cfa229b7b4232b23b77e059e19adf432bedd59a9 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 26 May 2015 21:49:05 +0200 Subject: dt-bindings: add vendor prefix for Netxeon Technology Signed-off-by: Heiko Stuebner Acked-by: Rob Herring Reviewed-by: Romain Perier --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9e..576f4ac7fb1a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -143,6 +143,7 @@ national National Semiconductor neonode Neonode Inc. netgear NETGEAR netlogic Broadcom Corporation (formerly NetLogic Microsystems) +netxeon Shenzhen Netxeon Technology CO., LTD newhaven Newhaven Display International nintendo Nintendo nokia Nokia -- cgit v1.2.3-59-g8ed1b From cde669fa71cfb6fdbd579c409b08a5cfa1863584 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 26 May 2015 21:50:09 +0200 Subject: ARM: dts: rockchip: add Netxeon R89 board This board is used in some TV-boxes like for example the Beelink R89 or Tronsmart R28. The board itself follows the reference design for the most part. But there are no schematics available it seems, so some things should be taken with a grain of salt. Signed-off-by: Heiko Stuebner Reviewed-by: Romain Perier --- Documentation/devicetree/bindings/arm/rockchip.txt | 4 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/rk3288-r89.dts | 412 +++++++++++++++++++++ 3 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/rk3288-r89.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index 60d4a1e0a9b5..b30bed1a10ad 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -26,3 +26,7 @@ Rockchip platforms device tree bindings - ChipSPARK PopMetal-RK3288 board: Required root node properties: - compatible = "chipspark,popmetal-rk3288", "rockchip,rk3288"; + +- Netxeon R89 board: + Required root node properties: + - compatible = "netxeon,r89", "rockchip,rk3288"; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 246473a244f6..f239007cffc9 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -488,7 +488,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-evb-act8846.dtb \ rk3288-evb-rk808.dtb \ rk3288-firefly-beta.dtb \ - rk3288-firefly.dtb + rk3288-firefly.dtb \ + rk3288-r89.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/arch/arm/boot/dts/rk3288-r89.dts b/arch/arm/boot/dts/rk3288-r89.dts new file mode 100644 index 000000000000..b1d9ca64003e --- /dev/null +++ b/arch/arm/boot/dts/rk3288-r89.dts @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2015 Heiko Stuebner + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include +#include "rk3288.dtsi" + +/ { + compatible = "netxeon,r89", "rockchip,rk3288"; + + memory { + reg = <0x0 0x80000000>; + }; + + ext_gmac: external-gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + #clock-cells = <0>; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + autorepeat; + + pinctrl-names = "default"; + pinctrl-0 = <&pwrbtn>; + + button@0 { + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + linux,code = <116>; + label = "GPIO Key Power"; + linux,input-type = <1>; + gpio-key,wakeup = <1>; + debounce-interval = <100>; + }; + }; + + vcc_host: vcc-host-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&host_vbus_drv>; + regulator-name = "vcc_host"; + regulator-always-on; + regulator-boot-on; + }; + + vcc_otg: vcc-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&otg_vbus_drv>; + regulator-name = "vcc_otg"; + regulator-always-on; + regulator-boot-on; + }; + + vcc_sdmmc: sdmmc-regulator { + compatible = "regulator-fixed"; + regulator-name = "sdmmc-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; + + vcc_sys: sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "sys-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +&cpu0 { + cpu0-supply = <&vdd_cpu>; +}; + +&gmac { + phy-supply = <&vcc_lan>; + phy-mode = "rgmii"; + clock_in_out = "input"; + snps,reset-gpio = <&gpio4 7 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 1000000>; + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + tx_delay = <0x30>; + rx_delay = <0x10>; + status = "ok"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + vdd_cpu: pmic@40 { + compatible = "silergy,syr827"; + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "VDD_CPU"; + regulator-enable-ramp-delay = <300>; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <8000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc_sys>; + }; + + vdd_gpu: pmic@41 { + compatible = "silergy,syr828"; + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "VDD_GPU"; + regulator-enable-ramp-delay = <300>; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <8000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc_sys>; + }; + + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "xin32k"; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int>; + }; + + act8846: pmic@5a { + compatible = "active-semi,act8846"; + reg = <0x5a>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_vsel>, <&pwr_hold>; + system-power-controller; + + regulators { + vcc_ddr: REG1 { + regulator-name = "VCC_DDR"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vcc_io: REG2 { + regulator-name = "VCC_IO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_log: REG3 { + regulator-name = "VDD_LOG"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + vcc_20: REG4 { + regulator-name = "VCC_20"; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-always-on; + }; + + vccio_sd: REG5 { + regulator-name = "VCCIO_SD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd10_lcd: REG6 { + regulator-name = "VDD10_LCD"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + vcc_wl: REG7 { + regulator-name = "VCC_WL"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vcca_33: REG8 { + regulator-name = "VCCA_33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vcc_lan: REG9 { + regulator-name = "VCC_LAN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_10: REG10 { + regulator-name = "VDD_10"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + vcc_18: REG11 { + regulator-name = "VCC_18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcc18_lcd: REG12 { + regulator-name = "VCC18_LCD"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + }; + }; +}; + +&i2c5 { + status = "okay"; +}; + +&pinctrl { + pcfg_output_high: pcfg-output-high { + output-high; + }; + + pcfg_output_low: pcfg-output-low { + output-low; + }; + + act8846 { + pmic_vsel: pmic-vsel { + rockchip,pins = <7 1 RK_FUNC_GPIO &pcfg_output_low>; + }; + + pwr_hold: pwr-hold { + rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_output_high>; + }; + }; + + buttons { + pwrbtn: pwrbtn { + rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + pmic { + pmic_int: pmic-int { + rockchip,pins = ; + }; + }; + + usb { + host_vbus_drv: host-vbus-drv { + rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + otg_vbus_drv: otg-vbus-drv { + rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm0 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_18>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + disable-wp; + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; + vmmc-supply = <&vcc_sdmmc>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host1 { + status = "okay"; +}; + +&usb_otg { + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; + +&vopb { + status = "okay"; +}; + +&vopb_mmu { + status = "okay"; +}; + +&vopl { + status = "okay"; +}; + +&vopl_mmu { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; -- cgit v1.2.3-59-g8ed1b From bdc89213710250d75fcbb86c2e623d1bbe8e3bb2 Mon Sep 17 00:00:00 2001 From: Sébastien Hinderer Date: Sun, 12 Jul 2015 17:44:15 +0200 Subject: SubmittingPatches: fix wrong wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Hinderer Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 67cf50914bbd..918c9727d3ec 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -340,7 +340,7 @@ on the changes you are submitting. It is important for a kernel developer to be able to "quote" your changes, using standard e-mail tools, so that they may comment on specific portions of your code. -For this reason, all patches should be submitting e-mail "inline". +For this reason, all patches should be submitted by e-mail "inline". WARNING: Be wary of your editor's word-wrap corrupting your patch, if you choose to cut-n-paste your patch. -- cgit v1.2.3-59-g8ed1b From 6e7ac7b4ab4d7b4486b4680ebbffbff3b1b0d775 Mon Sep 17 00:00:00 2001 From: Sébastien Hinderer Date: Sun, 12 Jul 2015 17:49:55 +0200 Subject: SubmittingPatches: fix wrong wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "facilitate easier reviewing" says the same thing twice. Signed-off-by: Sébastien Hinderer [jc: made it "easier review"] Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 918c9727d3ec..56ef2e6f79c2 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -94,7 +94,7 @@ generated it with diff(1), to ensure accuracy. If your changes produce a lot of deltas, you need to split them into individual patches which modify things in logical stages; see section -#3. This will facilitate easier reviewing by other kernel developers, +#3. This will facilitate review by other kernel developers, very important if you want your patch accepted. If you're using git, "git rebase -i" can help you with this process. If -- cgit v1.2.3-59-g8ed1b From 5d250eeb9d9d2237d49cd284ad35a6707694b88e Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 13 Jul 2015 12:29:11 +0900 Subject: Doc: pps: Fix file name in pps.txt This patch fix a file name of example code. Signed-off-by: Masanari Iida Acked-by: Rodolfo Giometti Signed-off-by: Jonathan Corbet --- Documentation/pps/pps.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt index c508cceeee7d..7cb7264ad598 100644 --- a/Documentation/pps/pps.txt +++ b/Documentation/pps/pps.txt @@ -125,7 +125,7 @@ The same function may also run the defined echo function (pps_ktimer_echo(), passing to it the "ptr" pointer) if the user asked for that... etc.. -Please see the file drivers/pps/clients/ktimer.c for example code. +Please see the file drivers/pps/clients/pps-ktimer.c for example code. SYSFS support -- cgit v1.2.3-59-g8ed1b From acc068d967a63aef163167a66a02966f42052b80 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Mon, 13 Jul 2015 22:02:48 +0200 Subject: Documenation: Update location of docproc.c docproc.c was moved in 2011 from scripts/basic to scripts -> updated the references accordingly Signed-off-by: Peter Huewe Signed-off-by: Jonathan Corbet --- Documentation/kernel-doc-nano-HOWTO.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt index acbc1a3d0d91..78f69cdc9b3f 100644 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ b/Documentation/kernel-doc-nano-HOWTO.txt @@ -128,7 +128,7 @@ are: special place-holders for where the extracted documentation should go. -- scripts/basic/docproc.c +- scripts/docproc.c This is a program for converting SGML template files into SGML files. When a file is referenced it is searched for symbols -- cgit v1.2.3-59-g8ed1b From 917d8e2d10f40e28aa9e0d824b2e5b8197d79fc2 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sat, 13 Jun 2015 03:21:58 +1000 Subject: cgroup: add documentation for the PIDs controller Add documentation derived from kernel/cgroup_pids.c to the relevant Documentation/ directory, along with a few examples of how to use the PIDs controller as well an explanation of its peculiarities. Signed-off-by: Aleksa Sarai Signed-off-by: Tejun Heo --- Documentation/cgroups/00-INDEX | 2 + Documentation/cgroups/pids.txt | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Documentation/cgroups/pids.txt (limited to 'Documentation') diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX index 96ce071a3633..3f5a40f57d4a 100644 --- a/Documentation/cgroups/00-INDEX +++ b/Documentation/cgroups/00-INDEX @@ -22,6 +22,8 @@ net_cls.txt - Network classifier cgroups details and usages. net_prio.txt - Network priority cgroups details and usages. +pids.txt + - Process number cgroups details and usages. resource_counter.txt - Resource Counter API. unified-hierarchy.txt diff --git a/Documentation/cgroups/pids.txt b/Documentation/cgroups/pids.txt new file mode 100644 index 000000000000..1a078b5d281a --- /dev/null +++ b/Documentation/cgroups/pids.txt @@ -0,0 +1,85 @@ + Process Number Controller + ========================= + +Abstract +-------- + +The process number controller is used to allow a cgroup hierarchy to stop any +new tasks from being fork()'d or clone()'d after a certain limit is reached. + +Since it is trivial to hit the task limit without hitting any kmemcg limits in +place, PIDs are a fundamental resource. As such, PID exhaustion must be +preventable in the scope of a cgroup hierarchy by allowing resource limiting of +the number of tasks in a cgroup. + +Usage +----- + +In order to use the `pids` controller, set the maximum number of tasks in +pids.max (this is not available in the root cgroup for obvious reasons). The +number of processes currently in the cgroup is given by pids.current. + +Organisational operations are not blocked by cgroup policies, so it is possible +to have pids.current > pids.max. This can be done by either setting the limit to +be smaller than pids.current, or attaching enough processes to the cgroup such +that pids.current > pids.max. However, it is not possible to violate a cgroup +policy through fork() or clone(). fork() and clone() will return -EAGAIN if the +creation of a new process would cause a cgroup policy to be violated. + +To set a cgroup to have no limit, set pids.max to "max". This is the default for +all new cgroups (N.B. that PID limits are hierarchical, so the most stringent +limit in the hierarchy is followed). + +pids.current tracks all child cgroup hierarchies, so parent/pids.current is a +superset of parent/child/pids.current. + +Example +------- + +First, we mount the pids controller: +# mkdir -p /sys/fs/cgroup/pids +# mount -t cgroup -o pids none /sys/fs/cgroup/pids + +Then we create a hierarchy, set limits and attach processes to it: +# mkdir -p /sys/fs/cgroup/pids/parent/child +# echo 2 > /sys/fs/cgroup/pids/parent/pids.max +# echo $$ > /sys/fs/cgroup/pids/parent/cgroup.procs +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# + +It should be noted that attempts to overcome the set limit (2 in this case) will +fail: + +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# ( /bin/echo "Here's some processes for you." | cat ) +sh: fork: Resource temporary unavailable +# + +Even if we migrate to a child cgroup (which doesn't have a set limit), we will +not be able to overcome the most stringent limit in the hierarchy (in this case, +parent's): + +# echo $$ > /sys/fs/cgroup/pids/parent/child/cgroup.procs +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# cat /sys/fs/cgroup/pids/parent/child/pids.current +2 +# cat /sys/fs/cgroup/pids/parent/child/pids.max +max +# ( /bin/echo "Here's some processes for you." | cat ) +sh: fork: Resource temporary unavailable +# + +We can set a limit that is smaller than pids.current, which will stop any new +processes from being forked at all (note that the shell itself counts towards +pids.current): + +# echo 1 > /sys/fs/cgroup/pids/parent/pids.max +# /bin/echo "We can't even spawn a single process now." +sh: fork: Resource temporary unavailable +# echo 0 > /sys/fs/cgroup/pids/parent/pids.max +# /bin/echo "We can't even spawn a single process now." +sh: fork: Resource temporary unavailable +# -- cgit v1.2.3-59-g8ed1b From 4fcb7dfd827d7d12ffc612fbc67769e002a482e4 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 27 May 2015 00:25:58 +0800 Subject: Document: dt: fsl: snvs: change support syscon snvs actually is multi fucntion driver. Change to use syscon to access register. Change snvs parent interrupt to option because single function may have seperated irq number. Signed-off-by: Frank Li Signed-off-by: Shawn Guo --- .../devicetree/bindings/crypto/fsl-sec4.txt | 42 +++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index e4022776ac6e..b21e7c2eef21 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -288,12 +288,13 @@ Secure Non-Volatile Storage (SNVS) Node Node defines address range and the associated interrupt for the SNVS function. This function monitors security state information & reports - security violations. + security violations. This also included rtc, + system power off and ON/OFF key. - compatible Usage: required Value type: - Definition: Must include "fsl,sec-v4.0-mon". + Definition: Must include "fsl,sec-v4.0-mon" and "syscon". - reg Usage: required @@ -324,7 +325,7 @@ Secure Non-Volatile Storage (SNVS) Node the child address, parent address, & length. - interrupts - Usage: required + Usage: optional Value type: Definition: Specifies the interrupts generated by this device. The value of the interrupts property @@ -341,7 +342,7 @@ Secure Non-Volatile Storage (SNVS) Node EXAMPLE sec_mon@314000 { - compatible = "fsl,sec-v4.0-mon"; + compatible = "fsl,sec-v4.0-mon", "syscon"; reg = <0x314000 0x1000>; ranges = <0 0x314000 0x1000>; interrupt-parent = <&mpic>; @@ -358,16 +359,31 @@ Secure Non-Volatile Storage (SNVS) Low Power (LP) RTC Node Value type: Definition: Must include "fsl,sec-v4.0-mon-rtc-lp". - - reg + - interrupts Usage: required - Value type: - Definition: A standard property. Specifies the physical - address and length of the SNVS LP configuration registers. + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - regmap + Usage: required + Value type: + Definition: this is phandle to the register map node. + + - offset + Usage: option + value type: + Definition: LP register offset. default it is 0x34. EXAMPLE - sec_mon_rtc_lp@314000 { + sec_mon_rtc_lp@1 { compatible = "fsl,sec-v4.0-mon-rtc-lp"; - reg = <0x34 0x58>; + interrupts = <93 2>; + regmap = <&snvs>; + offset = <0x34>; }; ===================================================================== @@ -443,12 +459,12 @@ FULL EXAMPLE compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; ranges = <0 0x314000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <93 2>; sec_mon_rtc_lp@34 { compatible = "fsl,sec-v4.0-mon-rtc-lp"; - reg = <0x34 0x58>; + regmap = <&sec_mon>; + offset = <0x34>; + interrupts = <93 2>; }; }; -- cgit v1.2.3-59-g8ed1b From cc28791d5ece61eaa78e7b9bbc3ac1d14f664683 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 27 May 2015 00:26:01 +0800 Subject: Document: devicetree: input: imx: i.mx snvs power device tree bindings The snvs-pwrkey is designed to enable POWER key function which controlled by SNVS ONOFF. the driver can report the status of POWER key and wakeup system if pressed after system suspend. Signed-off-by: Frank Li Signed-off-by: Robin Gong Signed-off-by: Shawn Guo --- .../devicetree/bindings/crypto/fsl-sec4.txt | 49 ++++++++++++++++++++++ .../devicetree/bindings/input/snvs-pwrkey.txt | 1 + 2 files changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/snvs-pwrkey.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index b21e7c2eef21..71a39c5bd486 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -386,6 +386,47 @@ EXAMPLE offset = <0x34>; }; +===================================================================== +System ON/OFF key driver + + The snvs-pwrkey is designed to enable POWER key function which controlled + by SNVS ONOFF, the driver can report the status of POWER key and wakeup + system if pressed after system suspend. + + - compatible: + Usage: required + Value type: + Definition: Mush include "fsl,sec-v4.0-pwrkey". + + - interrupts: + Usage: required + Value type: + Definition: The SNVS ON/OFF interrupt number to the CPU(s). + + - linux,keycode: + Usage: option + Value type: + Definition: Keycode to emit, KEY_POWER by default. + + - wakeup: + Usage: option + Value type: + Definition: Button can wake-up the system. + + - regmap: + Usage: required: + Value type: + Definition: this is phandle to the register map node. + +EXAMPLE: + snvs-pwrkey@0x020cc000 { + compatible = "fsl,sec-v4.0-pwrkey"; + regmap = <&snvs>; + interrupts = <0 4 0x4> + linux,keycode = <116>; /* KEY_POWER */ + wakeup; + }; + ===================================================================== FULL EXAMPLE @@ -466,6 +507,14 @@ FULL EXAMPLE offset = <0x34>; interrupts = <93 2>; }; + + snvs-pwrkey@0x020cc000 { + compatible = "fsl,sec-v4.0-pwrkey"; + regmap = <&sec_mon>; + interrupts = <0 4 0x4>; + linux,keycode = <116>; /* KEY_POWER */ + wakeup; + }; }; ===================================================================== diff --git a/Documentation/devicetree/bindings/input/snvs-pwrkey.txt b/Documentation/devicetree/bindings/input/snvs-pwrkey.txt new file mode 100644 index 000000000000..70c14250323b --- /dev/null +++ b/Documentation/devicetree/bindings/input/snvs-pwrkey.txt @@ -0,0 +1 @@ +See Documentation/devicetree/bindings/crypto/fsl-sec4.txt -- cgit v1.2.3-59-g8ed1b From 21b05de4c8fac08fff08cf84ef1d4fe5786f9608 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 14 May 2015 17:29:51 -0700 Subject: documentation: Bring rcutorture parameters up to date This commit changes the documentation of the rcutorture parameters to better match reality. Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d6f0459cd7b..01b5b68a237a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3135,22 +3135,35 @@ bytes respectively. Such letter suffixes can also be entirely omitted. in a given burst of a callback-flood test. rcutorture.fqs_duration= [KNL] - Set duration of force_quiescent_state bursts. + Set duration of force_quiescent_state bursts + in microseconds. rcutorture.fqs_holdoff= [KNL] - Set holdoff time within force_quiescent_state bursts. + Set holdoff time within force_quiescent_state bursts + in microseconds. rcutorture.fqs_stutter= [KNL] - Set wait time between force_quiescent_state bursts. + Set wait time between force_quiescent_state bursts + in seconds. + + rcutorture.gp_cond= [KNL] + Use conditional/asynchronous update-side + primitives, if available. rcutorture.gp_exp= [KNL] - Use expedited update-side primitives. + Use expedited update-side primitives, if available. rcutorture.gp_normal= [KNL] - Use normal (non-expedited) update-side primitives. - If both gp_exp and gp_normal are set, do both. - If neither gp_exp nor gp_normal are set, still - do both. + Use normal (non-expedited) asynchronous + update-side primitives, if available. + + rcutorture.gp_sync= [KNL] + Use normal (non-expedited) synchronous + update-side primitives, if available. If all + of rcutorture.gp_cond=, rcutorture.gp_exp=, + rcutorture.gp_normal=, and rcutorture.gp_sync= + are zero, rcutorture acts as if is interpreted + they are all non-zero. rcutorture.n_barrier_cbs= [KNL] Set callbacks/threads for rcu_barrier() testing. @@ -3177,9 +3190,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Set time (s) between CPU-hotplug operations, or zero to disable CPU-hotplug testing. - rcutorture.torture_runnable= [BOOT] - Start rcutorture running at boot time. - rcutorture.shuffle_interval= [KNL] Set task-shuffle interval (s). Shuffling tasks allows some CPUs to go into dyntick-idle mode @@ -3220,6 +3230,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Test RCU's dyntick-idle handling. See also the rcutorture.shuffle_interval parameter. + rcutorture.torture_runnable= [BOOT] + Start rcutorture running at boot time. + rcutorture.torture_type= [KNL] Specify the RCU implementation to test. -- cgit v1.2.3-59-g8ed1b From 297f739938908a4262603314576e32ee7375296c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 14 May 2015 17:31:07 -0700 Subject: documentation: Fix spelling of "operators" Reported-by: Mathieu Desnoyers Signed-off-by: Paul E. McKenney --- Documentation/RCU/rcu_dereference.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/RCU/rcu_dereference.txt b/Documentation/RCU/rcu_dereference.txt index 1e6c0da994f5..c0bf2441a2ba 100644 --- a/Documentation/RCU/rcu_dereference.txt +++ b/Documentation/RCU/rcu_dereference.txt @@ -28,7 +28,7 @@ o You must use one of the rcu_dereference() family of primitives o Avoid cancellation when using the "+" and "-" infix arithmetic operators. For example, for a given variable "x", avoid "(x-x)". There are similar arithmetic pitfalls from other - arithmetic operatiors, such as "(x*0)", "(x/(x+1))" or "(x%1)". + arithmetic operators, such as "(x*0)", "(x/(x+1))" or "(x%1)". The compiler is within its rights to substitute zero for all of these expressions, so that subsequent accesses no longer depend on the rcu_dereference(), again possibly resulting in bugs due -- cgit v1.2.3-59-g8ed1b From 57aecae950c55ef50934640794160cd118e73256 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 18 May 2015 18:27:42 -0700 Subject: documentation: Fix variable-name typo in memory-barriers.txt Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 13feb697271f..3d06f98b2ff2 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -746,7 +746,7 @@ You must also be careful not to rely too much on boolean short-circuit evaluation. Consider this example: q = READ_ONCE_CTRL(a); - if (a || 1 > 0) + if (q || 1 > 0) ACCESS_ONCE(b) = 1; Because the first condition cannot fault and the second condition is -- cgit v1.2.3-59-g8ed1b From 9af194cefc3c40e75a59df4cbb06e1c1064bee7f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 18 Jun 2015 14:33:24 -0700 Subject: documentation: Replace ACCESS_ONCE() by READ_ONCE() and WRITE_ONCE() Reported-by: Peter Zijlstra Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 346 +++++++++++++++++++------------------- 1 file changed, 177 insertions(+), 169 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 3d06f98b2ff2..470c07c868e4 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -194,22 +194,22 @@ There are some minimal guarantees that may be expected of a CPU: (*) On any given CPU, dependent memory accesses will be issued in order, with respect to itself. This means that for: - ACCESS_ONCE(Q) = P; smp_read_barrier_depends(); D = ACCESS_ONCE(*Q); + WRITE_ONCE(Q, P); smp_read_barrier_depends(); D = READ_ONCE(*Q); the CPU will issue the following memory operations: Q = LOAD P, D = LOAD *Q and always in that order. On most systems, smp_read_barrier_depends() - does nothing, but it is required for DEC Alpha. The ACCESS_ONCE() - is required to prevent compiler mischief. Please note that you - should normally use something like rcu_dereference() instead of - open-coding smp_read_barrier_depends(). + does nothing, but it is required for DEC Alpha. The READ_ONCE() + and WRITE_ONCE() are required to prevent compiler mischief. Please + note that you should normally use something like rcu_dereference() + instead of open-coding smp_read_barrier_depends(). (*) Overlapping loads and stores within a particular CPU will appear to be ordered within that CPU. This means that for: - a = ACCESS_ONCE(*X); ACCESS_ONCE(*X) = b; + a = READ_ONCE(*X); WRITE_ONCE(*X, b); the CPU will only issue the following sequence of memory operations: @@ -217,7 +217,7 @@ There are some minimal guarantees that may be expected of a CPU: And for: - ACCESS_ONCE(*X) = c; d = ACCESS_ONCE(*X); + WRITE_ONCE(*X, c); d = READ_ONCE(*X); the CPU will only issue: @@ -228,11 +228,11 @@ There are some minimal guarantees that may be expected of a CPU: And there are a number of things that _must_ or _must_not_ be assumed: - (*) It _must_not_ be assumed that the compiler will do what you want with - memory references that are not protected by ACCESS_ONCE(). Without - ACCESS_ONCE(), the compiler is within its rights to do all sorts - of "creative" transformations, which are covered in the Compiler - Barrier section. + (*) It _must_not_ be assumed that the compiler will do what you want + with memory references that are not protected by READ_ONCE() and + WRITE_ONCE(). Without them, the compiler is within its rights to + do all sorts of "creative" transformations, which are covered in + the Compiler Barrier section. (*) It _must_not_ be assumed that independent loads and stores will be issued in the order given. This means that for: @@ -520,8 +520,8 @@ following sequence of events: { A == 1, B == 2, C = 3, P == &A, Q == &C } B = 4; - ACCESS_ONCE(P) = &B - Q = ACCESS_ONCE(P); + WRITE_ONCE(P, &B) + Q = READ_ONCE(P); D = *Q; There's a clear data dependency here, and it would seem that by the end of the @@ -547,8 +547,8 @@ between the address load and the data load: { A == 1, B == 2, C = 3, P == &A, Q == &C } B = 4; - ACCESS_ONCE(P) = &B - Q = ACCESS_ONCE(P); + WRITE_ONCE(P, &B); + Q = READ_ONCE(P); D = *Q; @@ -574,8 +574,8 @@ access: { M[0] == 1, M[1] == 2, M[3] = 3, P == 0, Q == 3 } M[1] = 4; - ACCESS_ONCE(P) = 1 - Q = ACCESS_ONCE(P); + WRITE_ONCE(P, 1); + Q = READ_ONCE(P); D = M[Q]; @@ -596,10 +596,10 @@ A load-load control dependency requires a full read memory barrier, not simply a data dependency barrier to make it work correctly. Consider the following bit of code: - q = ACCESS_ONCE(a); + q = READ_ONCE(a); if (q) { /* BUG: No data dependency!!! */ - p = ACCESS_ONCE(b); + p = READ_ONCE(b); } This will not have the desired effect because there is no actual data @@ -608,10 +608,10 @@ by attempting to predict the outcome in advance, so that other CPUs see the load from b as having happened before the load from a. In such a case what's actually required is: - q = ACCESS_ONCE(a); + q = READ_ONCE(a); if (q) { - p = ACCESS_ONCE(b); + p = READ_ONCE(b); } However, stores are not speculated. This means that ordering -is- provided @@ -619,7 +619,7 @@ for load-store control dependencies, as in the following example: q = READ_ONCE_CTRL(a); if (q) { - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); } Control dependencies pair normally with other types of barriers. That @@ -647,11 +647,11 @@ branches of the "if" statement as follows: q = READ_ONCE_CTRL(a); if (q) { barrier(); - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something(); } else { barrier(); - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something_else(); } @@ -660,12 +660,12 @@ optimization levels: q = READ_ONCE_CTRL(a); barrier(); - ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */ + WRITE_ONCE(b, p); /* BUG: No ordering vs. load from a!!! */ if (q) { - /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */ + /* WRITE_ONCE(b, p); -- moved up, BUG!!! */ do_something(); } else { - /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */ + /* WRITE_ONCE(b, p); -- moved up, BUG!!! */ do_something_else(); } @@ -676,7 +676,7 @@ assembly code even after all compiler optimizations have been applied. Therefore, if you need ordering in this example, you need explicit memory barriers, for example, smp_store_release(): - q = ACCESS_ONCE(a); + q = READ_ONCE(a); if (q) { smp_store_release(&b, p); do_something(); @@ -690,10 +690,10 @@ ordering is guaranteed only when the stores differ, for example: q = READ_ONCE_CTRL(a); if (q) { - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something(); } else { - ACCESS_ONCE(b) = r; + WRITE_ONCE(b, r); do_something_else(); } @@ -706,10 +706,10 @@ the needed conditional. For example: q = READ_ONCE_CTRL(a); if (q % MAX) { - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something(); } else { - ACCESS_ONCE(b) = r; + WRITE_ONCE(b, r); do_something_else(); } @@ -718,7 +718,7 @@ equal to zero, in which case the compiler is within its rights to transform the above code into the following: q = READ_ONCE_CTRL(a); - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something_else(); Given this transformation, the CPU is not required to respect the ordering @@ -731,10 +731,10 @@ one, perhaps as follows: q = READ_ONCE_CTRL(a); BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */ if (q % MAX) { - ACCESS_ONCE(b) = p; + WRITE_ONCE(b, p); do_something(); } else { - ACCESS_ONCE(b) = r; + WRITE_ONCE(b, r); do_something_else(); } @@ -747,17 +747,17 @@ evaluation. Consider this example: q = READ_ONCE_CTRL(a); if (q || 1 > 0) - ACCESS_ONCE(b) = 1; + WRITE_ONCE(b, 1); Because the first condition cannot fault and the second condition is always true, the compiler can transform this example as following, defeating control dependency: q = READ_ONCE_CTRL(a); - ACCESS_ONCE(b) = 1; + WRITE_ONCE(b, 1); This example underscores the need to ensure that the compiler cannot -out-guess your code. More generally, although ACCESS_ONCE() does force +out-guess your code. More generally, although READ_ONCE() does force the compiler to actually emit code for a given load, it does not force the compiler to use the results. @@ -769,7 +769,7 @@ x and y both being zero: ======================= ======================= r1 = READ_ONCE_CTRL(x); r2 = READ_ONCE_CTRL(y); if (r1 > 0) if (r2 > 0) - ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1; + WRITE_ONCE(y, 1); WRITE_ONCE(x, 1); assert(!(r1 == 1 && r2 == 1)); @@ -779,7 +779,7 @@ then adding the following CPU would guarantee a related assertion: CPU 2 ===================== - ACCESS_ONCE(x) = 2; + WRITE_ONCE(x, 2); assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */ @@ -798,8 +798,7 @@ In summary: (*) Control dependencies must be headed by READ_ONCE_CTRL(). Or, as a much less preferable alternative, interpose - be headed by READ_ONCE() or an ACCESS_ONCE() read and must - have smp_read_barrier_depends() between this read and the + smp_read_barrier_depends() between a READ_ONCE() and the control-dependent write. (*) Control dependencies can order prior loads against later stores. @@ -815,15 +814,16 @@ In summary: (*) Control dependencies require at least one run-time conditional between the prior load and the subsequent store, and this - conditional must involve the prior load. If the compiler - is able to optimize the conditional away, it will have also - optimized away the ordering. Careful use of ACCESS_ONCE() can - help to preserve the needed conditional. + conditional must involve the prior load. If the compiler is able + to optimize the conditional away, it will have also optimized + away the ordering. Careful use of READ_ONCE_CTRL() READ_ONCE(), + and WRITE_ONCE() can help to preserve the needed conditional. (*) Control dependencies require that the compiler avoid reordering the - dependency into nonexistence. Careful use of ACCESS_ONCE() or - barrier() can help to preserve your control dependency. Please - see the Compiler Barrier section for more information. + dependency into nonexistence. Careful use of READ_ONCE_CTRL() + or smp_read_barrier_depends() can help to preserve your control + dependency. Please see the Compiler Barrier section for more + information. (*) Control dependencies pair normally with other types of barriers. @@ -848,11 +848,11 @@ barrier, an acquire barrier, a release barrier, or a general barrier: CPU 1 CPU 2 =============== =============== - ACCESS_ONCE(a) = 1; + WRITE_ONCE(a, 1); - ACCESS_ONCE(b) = 2; x = ACCESS_ONCE(b); + WRITE_ONCE(b, 2); x = READ_ONCE(b); - y = ACCESS_ONCE(a); + y = READ_ONCE(a); Or: @@ -860,7 +860,7 @@ Or: =============== =============================== a = 1; - ACCESS_ONCE(b) = &a; x = ACCESS_ONCE(b); + WRITE_ONCE(b, &a); x = READ_ONCE(b); y = *x; @@ -868,11 +868,11 @@ Or even: CPU 1 CPU 2 =============== =============================== - r1 = ACCESS_ONCE(y); + r1 = READ_ONCE(y); - ACCESS_ONCE(y) = 1; if (r2 = ACCESS_ONCE(x)) { + WRITE_ONCE(y, 1); if (r2 = READ_ONCE(x)) { - ACCESS_ONCE(y) = 1; + WRITE_ONCE(y, 1); } assert(r1 == 0 || r2 == 0); @@ -886,11 +886,11 @@ versa: CPU 1 CPU 2 =================== =================== - ACCESS_ONCE(a) = 1; }---- --->{ v = ACCESS_ONCE(c); - ACCESS_ONCE(b) = 2; } \ / { w = ACCESS_ONCE(d); + WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c); + WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d); \ - ACCESS_ONCE(c) = 3; } / \ { x = ACCESS_ONCE(a); - ACCESS_ONCE(d) = 4; }---- --->{ y = ACCESS_ONCE(b); + WRITE_ONCE(c, 3); } / \ { x = READ_ONCE(a); + WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b); EXAMPLES OF MEMORY BARRIER SEQUENCES @@ -1340,10 +1340,10 @@ compiler from moving the memory accesses either side of it to the other side: barrier(); -This is a general barrier -- there are no read-read or write-write variants -of barrier(). However, ACCESS_ONCE() can be thought of as a weak form -for barrier() that affects only the specific accesses flagged by the -ACCESS_ONCE(). +This is a general barrier -- there are no read-read or write-write +variants of barrier(). However, READ_ONCE() and WRITE_ONCE() can be +thought of as weak forms of barrier() that affect only the specific +accesses flagged by the READ_ONCE() or WRITE_ONCE(). The barrier() function has the following effects: @@ -1355,9 +1355,10 @@ The barrier() function has the following effects: (*) Within a loop, forces the compiler to load the variables used in that loop's conditional on each pass through that loop. -The ACCESS_ONCE() function can prevent any number of optimizations that, -while perfectly safe in single-threaded code, can be fatal in concurrent -code. Here are some examples of these sorts of optimizations: +The READ_ONCE() and WRITE_ONCE() functions can prevent any number of +optimizations that, while perfectly safe in single-threaded code, can +be fatal in concurrent code. Here are some examples of these sorts +of optimizations: (*) The compiler is within its rights to reorder loads and stores to the same variable, and in some cases, the CPU is within its @@ -1370,11 +1371,11 @@ code. Here are some examples of these sorts of optimizations: Might result in an older value of x stored in a[1] than in a[0]. Prevent both the compiler and the CPU from doing this as follows: - a[0] = ACCESS_ONCE(x); - a[1] = ACCESS_ONCE(x); + a[0] = READ_ONCE(x); + a[1] = READ_ONCE(x); - In short, ACCESS_ONCE() provides cache coherence for accesses from - multiple CPUs to a single variable. + In short, READ_ONCE() and WRITE_ONCE() provide cache coherence for + accesses from multiple CPUs to a single variable. (*) The compiler is within its rights to merge successive loads from the same variable. Such merging can cause the compiler to "optimize" @@ -1391,9 +1392,9 @@ code. Here are some examples of these sorts of optimizations: for (;;) do_something_with(tmp); - Use ACCESS_ONCE() to prevent the compiler from doing this to you: + Use READ_ONCE() to prevent the compiler from doing this to you: - while (tmp = ACCESS_ONCE(a)) + while (tmp = READ_ONCE(a)) do_something_with(tmp); (*) The compiler is within its rights to reload a variable, for example, @@ -1415,9 +1416,9 @@ code. Here are some examples of these sorts of optimizations: a was modified by some other CPU between the "while" statement and the call to do_something_with(). - Again, use ACCESS_ONCE() to prevent the compiler from doing this: + Again, use READ_ONCE() to prevent the compiler from doing this: - while (tmp = ACCESS_ONCE(a)) + while (tmp = READ_ONCE(a)) do_something_with(tmp); Note that if the compiler runs short of registers, it might save @@ -1437,21 +1438,21 @@ code. Here are some examples of these sorts of optimizations: do { } while (0); - This transformation is a win for single-threaded code because it gets - rid of a load and a branch. The problem is that the compiler will - carry out its proof assuming that the current CPU is the only one - updating variable 'a'. If variable 'a' is shared, then the compiler's - proof will be erroneous. Use ACCESS_ONCE() to tell the compiler - that it doesn't know as much as it thinks it does: + This transformation is a win for single-threaded code because it + gets rid of a load and a branch. The problem is that the compiler + will carry out its proof assuming that the current CPU is the only + one updating variable 'a'. If variable 'a' is shared, then the + compiler's proof will be erroneous. Use READ_ONCE() to tell the + compiler that it doesn't know as much as it thinks it does: - while (tmp = ACCESS_ONCE(a)) + while (tmp = READ_ONCE(a)) do_something_with(tmp); But please note that the compiler is also closely watching what you - do with the value after the ACCESS_ONCE(). For example, suppose you + do with the value after the READ_ONCE(). For example, suppose you do the following and MAX is a preprocessor macro with the value 1: - while ((tmp = ACCESS_ONCE(a)) % MAX) + while ((tmp = READ_ONCE(a)) % MAX) do_something_with(tmp); Then the compiler knows that the result of the "%" operator applied @@ -1475,12 +1476,12 @@ code. Here are some examples of these sorts of optimizations: surprise if some other CPU might have stored to variable 'a' in the meantime. - Use ACCESS_ONCE() to prevent the compiler from making this sort of + Use WRITE_ONCE() to prevent the compiler from making this sort of wrong guess: - ACCESS_ONCE(a) = 0; + WRITE_ONCE(a, 0); /* Code that does not store to variable a. */ - ACCESS_ONCE(a) = 0; + WRITE_ONCE(a, 0); (*) The compiler is within its rights to reorder memory accesses unless you tell it not to. For example, consider the following interaction @@ -1509,40 +1510,43 @@ code. Here are some examples of these sorts of optimizations: } If the interrupt occurs between these two statement, then - interrupt_handler() might be passed a garbled msg. Use ACCESS_ONCE() + interrupt_handler() might be passed a garbled msg. Use WRITE_ONCE() to prevent this as follows: void process_level(void) { - ACCESS_ONCE(msg) = get_message(); - ACCESS_ONCE(flag) = true; + WRITE_ONCE(msg, get_message()); + WRITE_ONCE(flag, true); } void interrupt_handler(void) { - if (ACCESS_ONCE(flag)) - process_message(ACCESS_ONCE(msg)); + if (READ_ONCE(flag)) + process_message(READ_ONCE(msg)); } - Note that the ACCESS_ONCE() wrappers in interrupt_handler() - are needed if this interrupt handler can itself be interrupted - by something that also accesses 'flag' and 'msg', for example, - a nested interrupt or an NMI. Otherwise, ACCESS_ONCE() is not - needed in interrupt_handler() other than for documentation purposes. - (Note also that nested interrupts do not typically occur in modern - Linux kernels, in fact, if an interrupt handler returns with - interrupts enabled, you will get a WARN_ONCE() splat.) - - You should assume that the compiler can move ACCESS_ONCE() past - code not containing ACCESS_ONCE(), barrier(), or similar primitives. - - This effect could also be achieved using barrier(), but ACCESS_ONCE() - is more selective: With ACCESS_ONCE(), the compiler need only forget - the contents of the indicated memory locations, while with barrier() - the compiler must discard the value of all memory locations that - it has currented cached in any machine registers. Of course, - the compiler must also respect the order in which the ACCESS_ONCE()s - occur, though the CPU of course need not do so. + Note that the READ_ONCE() and WRITE_ONCE() wrappers in + interrupt_handler() are needed if this interrupt handler can itself + be interrupted by something that also accesses 'flag' and 'msg', + for example, a nested interrupt or an NMI. Otherwise, READ_ONCE() + and WRITE_ONCE() are not needed in interrupt_handler() other than + for documentation purposes. (Note also that nested interrupts + do not typically occur in modern Linux kernels, in fact, if an + interrupt handler returns with interrupts enabled, you will get a + WARN_ONCE() splat.) + + You should assume that the compiler can move READ_ONCE() and + WRITE_ONCE() past code not containing READ_ONCE(), WRITE_ONCE(), + barrier(), or similar primitives. + + This effect could also be achieved using barrier(), but READ_ONCE() + and WRITE_ONCE() are more selective: With READ_ONCE() and + WRITE_ONCE(), the compiler need only forget the contents of the + indicated memory locations, while with barrier() the compiler must + discard the value of all memory locations that it has currented + cached in any machine registers. Of course, the compiler must also + respect the order in which the READ_ONCE()s and WRITE_ONCE()s occur, + though the CPU of course need not do so. (*) The compiler is within its rights to invent stores to a variable, as in the following example: @@ -1562,16 +1566,16 @@ code. Here are some examples of these sorts of optimizations: a branch. Unfortunately, in concurrent code, this optimization could cause some other CPU to see a spurious value of 42 -- even if variable 'a' was never zero -- when loading variable 'b'. - Use ACCESS_ONCE() to prevent this as follows: + Use WRITE_ONCE() to prevent this as follows: if (a) - ACCESS_ONCE(b) = a; + WRITE_ONCE(b, a); else - ACCESS_ONCE(b) = 42; + WRITE_ONCE(b, 42); The compiler can also invent loads. These are usually less damaging, but they can result in cache-line bouncing and thus in - poor performance and scalability. Use ACCESS_ONCE() to prevent + poor performance and scalability. Use READ_ONCE() to prevent invented loads. (*) For aligned memory locations whose size allows them to be accessed @@ -1590,9 +1594,9 @@ code. Here are some examples of these sorts of optimizations: This optimization can therefore be a win in single-threaded code. In fact, a recent bug (since fixed) caused GCC to incorrectly use this optimization in a volatile store. In the absence of such bugs, - use of ACCESS_ONCE() prevents store tearing in the following example: + use of WRITE_ONCE() prevents store tearing in the following example: - ACCESS_ONCE(p) = 0x00010002; + WRITE_ONCE(p, 0x00010002); Use of packed structures can also result in load and store tearing, as in this example: @@ -1609,22 +1613,23 @@ code. Here are some examples of these sorts of optimizations: foo2.b = foo1.b; foo2.c = foo1.c; - Because there are no ACCESS_ONCE() wrappers and no volatile markings, - the compiler would be well within its rights to implement these three - assignment statements as a pair of 32-bit loads followed by a pair - of 32-bit stores. This would result in load tearing on 'foo1.b' - and store tearing on 'foo2.b'. ACCESS_ONCE() again prevents tearing - in this example: + Because there are no READ_ONCE() or WRITE_ONCE() wrappers and no + volatile markings, the compiler would be well within its rights to + implement these three assignment statements as a pair of 32-bit + loads followed by a pair of 32-bit stores. This would result in + load tearing on 'foo1.b' and store tearing on 'foo2.b'. READ_ONCE() + and WRITE_ONCE() again prevent tearing in this example: foo2.a = foo1.a; - ACCESS_ONCE(foo2.b) = ACCESS_ONCE(foo1.b); + WRITE_ONCE(foo2.b, READ_ONCE(foo1.b)); foo2.c = foo1.c; -All that aside, it is never necessary to use ACCESS_ONCE() on a variable -that has been marked volatile. For example, because 'jiffies' is marked -volatile, it is never necessary to say ACCESS_ONCE(jiffies). The reason -for this is that ACCESS_ONCE() is implemented as a volatile cast, which -has no effect when its argument is already marked volatile. +All that aside, it is never necessary to use READ_ONCE() and +WRITE_ONCE() on a variable that has been marked volatile. For example, +because 'jiffies' is marked volatile, it is never necessary to +say READ_ONCE(jiffies). The reason for this is that READ_ONCE() and +WRITE_ONCE() are implemented as volatile casts, which has no effect when +its argument is already marked volatile. Please note that these compiler barriers have no direct effect on the CPU, which may then reorder things however it wishes. @@ -1646,14 +1651,15 @@ The Linux kernel has eight basic CPU memory barriers: All memory barriers except the data dependency barriers imply a compiler barrier. Data dependencies do not impose any additional compiler ordering. -Aside: In the case of data dependencies, the compiler would be expected to -issue the loads in the correct order (eg. `a[b]` would have to load the value -of b before loading a[b]), however there is no guarantee in the C specification -that the compiler may not speculate the value of b (eg. is equal to 1) and load -a before b (eg. tmp = a[1]; if (b != 1) tmp = a[b]; ). There is also the -problem of a compiler reloading b after having loaded a[b], thus having a newer -copy of b than a[b]. A consensus has not yet been reached about these problems, -however the ACCESS_ONCE macro is a good place to start looking. +Aside: In the case of data dependencies, the compiler would be expected +to issue the loads in the correct order (eg. `a[b]` would have to load +the value of b before loading a[b]), however there is no guarantee in +the C specification that the compiler may not speculate the value of b +(eg. is equal to 1) and load a before b (eg. tmp = a[1]; if (b != 1) +tmp = a[b]; ). There is also the problem of a compiler reloading b after +having loaded a[b], thus having a newer copy of b than a[b]. A consensus +has not yet been reached about these problems, however the READ_ONCE() +macro is a good place to start looking. SMP memory barriers are reduced to compiler barriers on uniprocessor compiled systems because it is assumed that a CPU will appear to be self-consistent, @@ -2126,12 +2132,12 @@ three CPUs; then should the following sequence of events occur: CPU 1 CPU 2 =============================== =============================== - ACCESS_ONCE(*A) = a; ACCESS_ONCE(*E) = e; + WRITE_ONCE(*A, a); WRITE_ONCE(*E, e); ACQUIRE M ACQUIRE Q - ACCESS_ONCE(*B) = b; ACCESS_ONCE(*F) = f; - ACCESS_ONCE(*C) = c; ACCESS_ONCE(*G) = g; + WRITE_ONCE(*B, b); WRITE_ONCE(*F, f); + WRITE_ONCE(*C, c); WRITE_ONCE(*G, g); RELEASE M RELEASE Q - ACCESS_ONCE(*D) = d; ACCESS_ONCE(*H) = h; + WRITE_ONCE(*D, d); WRITE_ONCE(*H, h); Then there is no guarantee as to what order CPU 3 will see the accesses to *A through *H occur in, other than the constraints imposed by the separate locks @@ -2151,18 +2157,18 @@ However, if the following occurs: CPU 1 CPU 2 =============================== =============================== - ACCESS_ONCE(*A) = a; + WRITE_ONCE(*A, a); ACQUIRE M [1] - ACCESS_ONCE(*B) = b; - ACCESS_ONCE(*C) = c; + WRITE_ONCE(*B, b); + WRITE_ONCE(*C, c); RELEASE M [1] - ACCESS_ONCE(*D) = d; ACCESS_ONCE(*E) = e; + WRITE_ONCE(*D, d); WRITE_ONCE(*E, e); ACQUIRE M [2] smp_mb__after_unlock_lock(); - ACCESS_ONCE(*F) = f; - ACCESS_ONCE(*G) = g; + WRITE_ONCE(*F, f); + WRITE_ONCE(*G, g); RELEASE M [2] - ACCESS_ONCE(*H) = h; + WRITE_ONCE(*H, h); CPU 3 might see: @@ -2881,11 +2887,11 @@ A programmer might take it for granted that the CPU will perform memory operations in exactly the order specified, so that if the CPU is, for example, given the following piece of code to execute: - a = ACCESS_ONCE(*A); - ACCESS_ONCE(*B) = b; - c = ACCESS_ONCE(*C); - d = ACCESS_ONCE(*D); - ACCESS_ONCE(*E) = e; + a = READ_ONCE(*A); + WRITE_ONCE(*B, b); + c = READ_ONCE(*C); + d = READ_ONCE(*D); + WRITE_ONCE(*E, e); they would then expect that the CPU will complete the memory operation for each instruction before moving on to the next one, leading to a definite sequence of @@ -2932,12 +2938,12 @@ However, it is guaranteed that a CPU will be self-consistent: it will see its _own_ accesses appear to be correctly ordered, without the need for a memory barrier. For instance with the following code: - U = ACCESS_ONCE(*A); - ACCESS_ONCE(*A) = V; - ACCESS_ONCE(*A) = W; - X = ACCESS_ONCE(*A); - ACCESS_ONCE(*A) = Y; - Z = ACCESS_ONCE(*A); + U = READ_ONCE(*A); + WRITE_ONCE(*A, V); + WRITE_ONCE(*A, W); + X = READ_ONCE(*A); + WRITE_ONCE(*A, Y); + Z = READ_ONCE(*A); and assuming no intervention by an external influence, it can be assumed that the final result will appear to be: @@ -2953,13 +2959,14 @@ accesses: U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A in that order, but, without intervention, the sequence may have almost any -combination of elements combined or discarded, provided the program's view of -the world remains consistent. Note that ACCESS_ONCE() is -not- optional -in the above example, as there are architectures where a given CPU might -reorder successive loads to the same location. On such architectures, -ACCESS_ONCE() does whatever is necessary to prevent this, for example, on -Itanium the volatile casts used by ACCESS_ONCE() cause GCC to emit the -special ld.acq and st.rel instructions that prevent such reordering. +combination of elements combined or discarded, provided the program's view +of the world remains consistent. Note that READ_ONCE() and WRITE_ONCE() +are -not- optional in the above example, as there are architectures +where a given CPU might reorder successive loads to the same location. +On such architectures, READ_ONCE() and WRITE_ONCE() do whatever is +necessary to prevent this, for example, on Itanium the volatile casts +used by READ_ONCE() and WRITE_ONCE() cause GCC to emit the special ld.acq +and st.rel instructions (respectively) that prevent such reordering. The compiler may also combine, discard or defer elements of the sequence before the CPU even sees them. @@ -2973,13 +2980,14 @@ may be reduced to: *A = W; -since, without either a write barrier or an ACCESS_ONCE(), it can be +since, without either a write barrier or an WRITE_ONCE(), it can be assumed that the effect of the storage of V to *A is lost. Similarly: *A = Y; Z = *A; -may, without a memory barrier or an ACCESS_ONCE(), be reduced to: +may, without a memory barrier or an READ_ONCE() and WRITE_ONCE(), be +reduced to: *A = Y; Z = Y; -- cgit v1.2.3-59-g8ed1b From 96d7744e0a5631a1b5fef2a97658150b165f02b6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 13 Jul 2015 15:55:52 -0700 Subject: doc: Call out smp_mb__after_unlock_lock() transitivity Although "full barrier" should be interpreted as providing transitivity, it is worth eliminating any possible confusion. This commit therefore adds "(including transitivity)" to eliminate any possible confusion. Reported-by: Peter Zijlstra Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 470c07c868e4..318523872db5 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1858,11 +1858,12 @@ Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not imply a full memory barrier. If it is necessary for a RELEASE-ACQUIRE pair to produce a full barrier, the ACQUIRE can be followed by an smp_mb__after_unlock_lock() invocation. This will produce a full barrier -if either (a) the RELEASE and the ACQUIRE are executed by the same -CPU or task, or (b) the RELEASE and ACQUIRE act on the same variable. -The smp_mb__after_unlock_lock() primitive is free on many architectures. -Without smp_mb__after_unlock_lock(), the CPU's execution of the critical -sections corresponding to the RELEASE and the ACQUIRE can cross, so that: +(including transitivity) if either (a) the RELEASE and the ACQUIRE are +executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on +the same variable. The smp_mb__after_unlock_lock() primitive is free +on many architectures. Without smp_mb__after_unlock_lock(), the CPU's +execution of the critical sections corresponding to the RELEASE and the +ACQUIRE can cross, so that: *A = a; RELEASE M -- cgit v1.2.3-59-g8ed1b From 0c59d26770333cf605d9119a78dd6c1ebebc6a61 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:35 +0300 Subject: clk: tegra: Add binding for the Tegra124 DFLL clocksource The DFLL is the main clocksource for the fast CPU cluster on Tegra124 and also provides automatic CPU rail voltage scaling as well. The DFLL is a separate IP block from the usual Tegra124 clock-and-reset controller, so it gets its own node in the device tree. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- .../bindings/clock/nvidia,tegra124-dfll.txt | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt new file mode 100644 index 000000000000..ee7e5fd4a50b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt @@ -0,0 +1,79 @@ +NVIDIA Tegra124 DFLL FCPU clocksource + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The DFLL IP block on Tegra is a root clocksource designed for clocking +the fast CPU cluster. It consists of a free-running voltage controlled +oscillator connected to the CPU voltage rail (VDD_CPU), and a closed loop +control module that will automatically adjust the VDD_CPU voltage by +communicating with an off-chip PMIC either via an I2C bus or via PWM signals. +Currently only the I2C mode is supported by these bindings. + +Required properties: +- compatible : should be "nvidia,tegra124-dfll" +- reg : Defines the following set of registers, in the order listed: + - registers for the DFLL control logic. + - registers for the I2C output logic. + - registers for the integrated I2C master controller. + - look-up table RAM for voltage register values. +- interrupts: Should contain the DFLL block interrupt. +- clocks: Must contain an entry for each entry in clock-names. + See clock-bindings.txt for details. +- clock-names: Must include the following entries: + - soc: Clock source for the DFLL control logic. + - ref: The closed loop reference clock + - i2c: Clock source for the integrated I2C master. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - dvco: Reset control for the DFLL DVCO. +- #clock-cells: Must be 0. +- clock-output-names: Name of the clock output. +- vdd-cpu-supply: Regulator for the CPU voltage rail that the DFLL + hardware will start controlling. The regulator will be queried for + the I2C register, control values and supported voltages. + +Required properties for the control loop parameters: +- nvidia,sample-rate: Sample rate of the DFLL control loop. +- nvidia,droop-ctrl: See the register CL_DVFS_DROOP_CTRL in the TRM. +- nvidia,force-mode: See the field DFLL_PARAMS_FORCE_MODE in the TRM. +- nvidia,cf: Numeric value, see the field DFLL_PARAMS_CF_PARAM in the TRM. +- nvidia,ci: Numeric value, see the field DFLL_PARAMS_CI_PARAM in the TRM. +- nvidia,cg: Numeric value, see the field DFLL_PARAMS_CG_PARAM in the TRM. + +Optional properties for the control loop parameters: +- nvidia,cg-scale: Boolean value, see the field DFLL_PARAMS_CG_SCALE in the TRM. + +Required properties for I2C mode: +- nvidia,i2c-fs-rate: I2C transfer rate, if using full speed mode. + +Example: + +clock@0,70110000 { + compatible = "nvidia,tegra124-dfll"; + reg = <0 0x70110000 0 0x100>, /* DFLL control */ + <0 0x70110000 0 0x100>, /* I2C output control */ + <0 0x70110100 0 0x100>, /* Integrated I2C controller */ + <0 0x70110200 0 0x100>; /* Look-up table RAM */ + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_DFLL_SOC>, + <&tegra_car TEGRA124_CLK_DFLL_REF>, + <&tegra_car TEGRA124_CLK_I2C5>; + clock-names = "soc", "ref", "i2c"; + resets = <&tegra_car TEGRA124_RST_DFLL_DVCO>; + reset-names = "dvco"; + #clock-cells = <0>; + clock-output-names = "dfllCPU_out"; + vdd-cpu-supply = <&vdd_cpu>; + status = "okay"; + + nvidia,sample-rate = <12500>; + nvidia,droop-ctrl = <0x00000f00>; + nvidia,force-mode = <1>; + nvidia,cf = <10>; + nvidia,ci = <0>; + nvidia,cg = <2>; + + nvidia,i2c-fs-rate = <400000>; +}; -- cgit v1.2.3-59-g8ed1b From 135796c9ccd3d6c53fbc3f6c4d73d8ba6820b739 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:46 +0300 Subject: cpufreq: tegra124: Add device tree bindings The cpufreq driver for Tegra124 will be a different one than the old Tegra20 cpufreq driver (tegra-cpufreq), which does not use the device tree. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Viresh Kumar Signed-off-by: Thierry Reding --- .../bindings/cpufreq/tegra124-cpufreq.txt | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt new file mode 100644 index 000000000000..b1669fbfb740 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt @@ -0,0 +1,44 @@ +Tegra124 CPU frequency scaling driver bindings +---------------------------------------------- + +Both required and optional properties listed below must be defined +under node /cpus/cpu@0. + +Required properties: +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - cpu_g: Clock mux for the fast CPU cluster. + - cpu_lp: Clock mux for the low-power CPU cluster. + - pll_x: Fast PLL clocksource. + - pll_p: Auxiliary PLL used during fast PLL rate changes. + - dfll: Fast DFLL clocksource that also automatically scales CPU voltage. +- vdd-cpu-supply: Regulator for CPU voltage + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. + +Example: +-------- +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + + clocks = <&tegra_car TEGRA124_CLK_CCLK_G>, + <&tegra_car TEGRA124_CLK_CCLK_LP>, + <&tegra_car TEGRA124_CLK_PLL_X>, + <&tegra_car TEGRA124_CLK_PLL_P>, + <&dfll>; + clock-names = "cpu_g", "cpu_lp", "pll_x", "pll_p", "dfll"; + clock-latency = <300000>; + vdd-cpu-supply: <&vdd_cpu>; + }; + + <...> +}; -- cgit v1.2.3-59-g8ed1b From 42a8679cf27439c5c9f1f9aa85854f0dec74687c Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Fri, 10 Apr 2015 23:35:58 +0200 Subject: ALSA: hda/tegra - Fix hda2codec_2x clock and reset names Fix hda2codec_2x clock and reset names in Tegra30 HDA controller device tree node documentation. While at it also fix coma vs. semicolon issue. Signed-off-by: Marcel Ziswiler Reviewed-by: Paul Walmsley Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt index 13e2ef496724..5032efa9ab64 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt @@ -8,10 +8,10 @@ Required properties: - interrupts : The interrupt from the HDA controller. - clocks : Must contain an entry for each required entry in clock-names. See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: hda, hdacodec_2x, hda2hdmi +- clock-names : Must include the following entries: hda, hda2codec_2x, hda2hdmi - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. -- reset-names : Must include the following entries: hda, hdacodec_2x, hda2hdmi +- reset-names : Must include the following entries: hda, hda2codec_2x, hda2hdmi Example: @@ -24,7 +24,7 @@ hda@0,70030000 { <&tegra_car TEGRA124_CLK_HDA2CODEC_2X>; clock-names = "hda", "hda2hdmi", "hda2codec_2x"; resets = <&tegra_car 125>, /* hda */ - <&tegra_car 128>; /* hda2hdmi */ - <&tegra_car 111>, /* hda2codec_2x */ + <&tegra_car 128>, /* hda2hdmi */ + <&tegra_car 111>; /* hda2codec_2x */ reset-names = "hda", "hda2hdmi", "hda2codec_2x"; }; -- cgit v1.2.3-59-g8ed1b From 5cf4af3bebb718b72a23b7e80fddfe8b4e8b0620 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 23 Jan 2015 09:34:44 +0100 Subject: ALSA: hda/tegra: Order clock and reset names consistently The example in the device tree binding documentation and the driver code list hda2codec_2x as the last entry in the clock-names and reset-names properties. Update the description of the properties to use the same order. Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt index 5032efa9ab64..275c6ea356f6 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt @@ -8,10 +8,10 @@ Required properties: - interrupts : The interrupt from the HDA controller. - clocks : Must contain an entry for each required entry in clock-names. See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: hda, hda2codec_2x, hda2hdmi +- clock-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. -- reset-names : Must include the following entries: hda, hda2codec_2x, hda2hdmi +- reset-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x Example: -- cgit v1.2.3-59-g8ed1b From f3ee390e4ef23a557b3519f6fb314a9e80d337c1 Mon Sep 17 00:00:00 2001 From: Alexandru M Stan Date: Tue, 7 Jul 2015 20:04:32 +0200 Subject: ARM: dts: rockchip: add veyron-jerry board The Hisense Chromebook C11, also named jerry. Signed-off-by: Alexandru M Stan Signed-off-by: Heiko Stuebner Reviewed-by: Doug Anderson --- Documentation/devicetree/bindings/arm/rockchip.txt | 7 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/rk3288-veyron-jerry.dts | 197 +++++++++++++++++++++ 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/rk3288-veyron-jerry.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index b30bed1a10ad..ab89f5089217 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -30,3 +30,10 @@ Rockchip platforms device tree bindings - Netxeon R89 board: Required root node properties: - compatible = "netxeon,r89", "rockchip,rk3288"; + +- Google Jerry (Hisense Chromebook C11 and more): + Required root node properties: + - compatible = "google,veyron-jerry-rev7", "google,veyron-jerry-rev6", + "google,veyron-jerry-rev5", "google,veyron-jerry-rev4", + "google,veyron-jerry-rev3", "google,veyron-jerry", + "google,veyron", "rockchip,rk3288"; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index f239007cffc9..b07ee6be757e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -489,7 +489,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-evb-rk808.dtb \ rk3288-firefly-beta.dtb \ rk3288-firefly.dtb \ - rk3288-r89.dtb + rk3288-r89.dtb \ + rk3288-veyron-jerry.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts new file mode 100644 index 000000000000..42d724559915 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts @@ -0,0 +1,197 @@ +/* + * Google Veyron Jerry Rev 3+ board device tree source + * + * Copyright 2015 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3288-veyron-chromebook.dtsi" +#include "cros-ec-sbs.dtsi" + +/ { + model = "Google Jerry"; + compatible = "google,veyron-jerry-rev7", "google,veyron-jerry-rev6", + "google,veyron-jerry-rev5", "google,veyron-jerry-rev4", + "google,veyron-jerry-rev3", "google,veyron-jerry", + "google,veyron", "rockchip,rk3288"; + + panel_regulator: panel-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_h>; + regulator-name = "panel_regulator"; + vin-supply = <&vcc33_sys>; + }; + + vcc18_lcd: vcc18-lcd { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&avdd_1v8_disp_en>; + regulator-name = "vcc18_lcd"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc18_wl>; + }; + + backlight_regulator: backlight-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_pwr_en>; + regulator-name = "backlight_regulator"; + vin-supply = <&vcc33_sys>; + startup-delay-us = <15000>; + }; +}; + +&rk808 { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + + regulators { + mic_vcc: LDO_REG2 { + regulator-name = "mic_vcc"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + }; +}; + +&sdmmc { + disable-wp; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio + &sdmmc_bus4>; +}; + +&vcc_5v { + enable-active-high; + gpio = <&gpio7 21 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&drv_5v>; +}; + +&vcc50_hdmi { + enable-active-high; + gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc50_hdmi_en>; +}; + +&pinctrl { + backlight { + bl_pwr_en: bl_pwr_en { + rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + buck-5v { + drv_5v: drv-5v { + rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hdmi { + vcc50_hdmi_en: vcc50-hdmi-en { + rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lcd { + lcd_enable_h: lcd-en { + rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + avdd_1v8_disp_en: avdd-1v8-disp-en { + rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + dvs_1: dvs-1 { + rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + dvs_2: dvs-2 { + rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +}; + +&i2c4 { + status = "okay"; + + /* + * Trackpad pin control is shared between Elan and Synaptics devices + * so we have to pull it up to the bus level. + */ + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_xfer &trackpad_int>; + + trackpad@15 { + /* + * Remove the inherited pinctrl settings to avoid clashing + * with bus-wide ones. + */ + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + }; + + trackpad@2c { + compatible = "hid-over-i2c"; + interrupt-parent = <&gpio7>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + reg = <0x2c>; + hid-descr-addr = <0x0020>; + vcc-supply = <&vcc33_io>; + wakeup-source; + }; +}; -- cgit v1.2.3-59-g8ed1b From 05ffc630627003c7bf275eec05b0eae81e0016b1 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 7 Jul 2015 20:09:34 +0200 Subject: ARM: dts: rockchip: add veyron-pinky board While pinky was one of the earlier development models, is on the list of endangered species today and nearly extinct, I want to keep mine around for the foreseeable future after spending all the time making a nice hole into the base below the dut-connector. Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.txt | 5 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/rk3288-veyron-pinky.dts | 128 +++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/rk3288-veyron-pinky.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index ab89f5089217..c112ffac382d 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -37,3 +37,8 @@ Rockchip platforms device tree bindings "google,veyron-jerry-rev5", "google,veyron-jerry-rev4", "google,veyron-jerry-rev3", "google,veyron-jerry", "google,veyron", "rockchip,rk3288"; + +- Google Pinky (dev-board): + Required root node properties: + - compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", + "google,veyron", "rockchip,rk3288"; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b07ee6be757e..ce7e1a821a23 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -490,7 +490,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-firefly-beta.dtb \ rk3288-firefly.dtb \ rk3288-r89.dtb \ - rk3288-veyron-jerry.dtb + rk3288-veyron-jerry.dtb \ + rk3288-veyron-pinky.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts new file mode 100644 index 000000000000..25eb4b0c1330 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts @@ -0,0 +1,128 @@ +/* + * Google Veyron Pinky Rev 2 board device tree source + * + * Copyright 2015 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3288-veyron-chromebook.dtsi" +#include "cros-ec-sbs.dtsi" + +/ { + model = "Google Pinky"; + compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", + "google,veyron", "rockchip,rk3288"; + + /delete-node/emmc-pwrseq; +}; + +&emmc { + /* + * Use a pullup instead of a drive since the output is 3.3V and + * really should be 1.8V (oops). The external pulldown will help + * bring the voltage down if we only drive with a pullup here. + * Therefore disable the powerseq (and actual reset) for pinky. + */ + /delete-property/mmc-pwrseq; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8 &emmc_reset>; +}; + +&gpio_keys { + pinctrl-0 = <&pwr_key_h &ap_lid_int_l>; + + power { + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + }; +}; + +/* Touchpad connector */ +&i2c3 { + status = "okay"; + + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; +}; + +&pinctrl { + buttons { + pwr_key_h: pwr-key-h { + rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + emmc { + emmc_reset: emmc-reset { + rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdmmc { + sdmmc_wp_gpio: sdmmc-wp-gpio { + rockchip,pins = <7 10 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&rk808 { + regulators { + vcc18_lcd: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc18_lcd"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + }; +}; + +&sdmmc { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio + &sdmmc_wp_gpio &sdmmc_bus4>; + wp-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>; +}; + +&tsadc { + /* Some connection is flaky making the tsadc hang the system */ + status = "disabled"; +}; -- cgit v1.2.3-59-g8ed1b From 4a01a64c8ee8d205bbe25adb40bb3922d0ebce70 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 25 Jun 2015 19:22:27 +0200 Subject: dt-bindings: document rk3368 R88 board from Rockchip The initial board containing the rk3368 ARM64 soc. Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index c112ffac382d..c7769400ef85 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -42,3 +42,7 @@ Rockchip platforms device tree bindings Required root node properties: - compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", "google,veyron", "rockchip,rk3288"; + +- Rockchip R88 board: + Required root node properties: + - compatible = "rockchip,r88", "rockchip,rk3368"; -- cgit v1.2.3-59-g8ed1b From 0034af036554c39eefd14d835a8ec3496ac46712 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 16 Jul 2015 09:14:26 -0600 Subject: block: make /sys/block//queue/discard_max_bytes writeable Lots of devices support huge discard sizes these days. Depending on how the device handles them internally, huge discards can introduce massive latencies (hundreds of msec) on the device side. We have a sysfs file, discard_max_bytes, that advertises the max hardware supported discard size. Make this writeable, and split the settings into a soft and hard limit. This can be set from 'discard_granularity' and up to the hardware limit. Add a new sysfs file, 'discard_max_hw_bytes', that shows the hw set limit. Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- Documentation/block/queue-sysfs.txt | 10 +++++++++- block/blk-settings.c | 4 ++++ block/blk-sysfs.c | 40 ++++++++++++++++++++++++++++++++++++- include/linux/blkdev.h | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index 3a29f8914df9..e5d914845be6 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -20,7 +20,7 @@ This shows the size of internal allocation of the device in bytes, if reported by the device. A value of '0' means device does not support the discard functionality. -discard_max_bytes (RO) +discard_max_hw_bytes (RO) ---------------------- Devices that support discard functionality may have internal limits on the number of bytes that can be trimmed or unmapped in a single operation. @@ -29,6 +29,14 @@ number of bytes that can be discarded in a single operation. Discard requests issued to the device must not exceed this limit. A discard_max_bytes value of 0 means that the device does not support discard functionality. +discard_max_bytes (RW) +---------------------- +While discard_max_hw_bytes is the hardware limit for the device, this +setting is the software limit. Some devices exhibit large latencies when +large discards are issued, setting this value lower will make Linux issue +smaller discards and potentially help reduce latencies induced by large +discard operations. + discard_zeroes_data (RO) ------------------------ When read, this file will show if the discarded block are zeroed by the diff --git a/block/blk-settings.c b/block/blk-settings.c index 12600bfffca9..b38d8d723276 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -116,6 +116,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->chunk_sectors = 0; lim->max_write_same_sectors = 0; lim->max_discard_sectors = 0; + lim->max_hw_discard_sectors = 0; lim->discard_granularity = 0; lim->discard_alignment = 0; lim->discard_misaligned = 0; @@ -303,6 +304,7 @@ EXPORT_SYMBOL(blk_queue_chunk_sectors); void blk_queue_max_discard_sectors(struct request_queue *q, unsigned int max_discard_sectors) { + q->limits.max_hw_discard_sectors = max_discard_sectors; q->limits.max_discard_sectors = max_discard_sectors; } EXPORT_SYMBOL(blk_queue_max_discard_sectors); @@ -641,6 +643,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_discard_sectors = min_not_zero(t->max_discard_sectors, b->max_discard_sectors); + t->max_hw_discard_sectors = min_not_zero(t->max_hw_discard_sectors, + b->max_hw_discard_sectors); t->discard_granularity = max(t->discard_granularity, b->discard_granularity); t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) % diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 6264b382d4d1..b1f34e463c0f 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -145,12 +145,43 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag return queue_var_show(q->limits.discard_granularity, page); } +static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page) +{ + unsigned long long val; + + val = q->limits.max_hw_discard_sectors << 9; + return sprintf(page, "%llu\n", val); +} + static ssize_t queue_discard_max_show(struct request_queue *q, char *page) { return sprintf(page, "%llu\n", (unsigned long long)q->limits.max_discard_sectors << 9); } +static ssize_t queue_discard_max_store(struct request_queue *q, + const char *page, size_t count) +{ + unsigned long max_discard; + ssize_t ret = queue_var_store(&max_discard, page, count); + + if (ret < 0) + return ret; + + if (max_discard & (q->limits.discard_granularity - 1)) + return -EINVAL; + + max_discard >>= 9; + if (max_discard > UINT_MAX) + return -EINVAL; + + if (max_discard > q->limits.max_hw_discard_sectors) + max_discard = q->limits.max_hw_discard_sectors; + + q->limits.max_discard_sectors = max_discard; + return ret; +} + static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) { return queue_var_show(queue_discard_zeroes_data(q), page); @@ -360,9 +391,15 @@ static struct queue_sysfs_entry queue_discard_granularity_entry = { .show = queue_discard_granularity_show, }; +static struct queue_sysfs_entry queue_discard_max_hw_entry = { + .attr = {.name = "discard_max_hw_bytes", .mode = S_IRUGO }, + .show = queue_discard_max_hw_show, +}; + static struct queue_sysfs_entry queue_discard_max_entry = { - .attr = {.name = "discard_max_bytes", .mode = S_IRUGO }, + .attr = {.name = "discard_max_bytes", .mode = S_IRUGO | S_IWUSR }, .show = queue_discard_max_show, + .store = queue_discard_max_store, }; static struct queue_sysfs_entry queue_discard_zeroes_data_entry = { @@ -421,6 +458,7 @@ static struct attribute *default_attrs[] = { &queue_io_opt_entry.attr, &queue_discard_granularity_entry.attr, &queue_discard_max_entry.attr, + &queue_discard_max_hw_entry.attr, &queue_discard_zeroes_data_entry.attr, &queue_write_same_max_entry.attr, &queue_nonrot_entry.attr, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d4068c17d0df..243f29e779ec 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -268,6 +268,7 @@ struct queue_limits { unsigned int io_min; unsigned int io_opt; unsigned int max_discard_sectors; + unsigned int max_hw_discard_sectors; unsigned int max_write_same_sectors; unsigned int discard_granularity; unsigned int discard_alignment; -- cgit v1.2.3-59-g8ed1b From 18eb5e9fb2936cb5d4b6899a102e97d84547f2f5 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Mon, 13 Jul 2015 23:20:12 +0200 Subject: doc: dt: add documentation for pl172 memory bindings Add documentation for configuration and timing setup of static memory devices on the ARM PL172 controller. Signed-off-by: Joachim Eastwood Signed-off-by: Olof Johansson --- .../bindings/memory-controllers/arm,pl172.txt | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt b/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt new file mode 100644 index 000000000000..e6df32f9986d --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt @@ -0,0 +1,125 @@ +* Device tree bindings for ARM PL172 MultiPort Memory Controller + +Required properties: + +- compatible: "arm,pl172", "arm,primecell" + +- reg: Must contains offset/length value for controller. + +- #address-cells: Must be 2. The partition number has to be encoded in the + first address cell and it may accept values 0..N-1 + (N - total number of partitions). The second cell is the + offset into the partition. + +- #size-cells: Must be set to 1. + +- ranges: Must contain one or more chip select memory regions. + +- clocks: Must contain references to controller clocks. + +- clock-names: Must contain "mpmcclk" and "apb_pclk". + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + See clock-bindings.txt + +Child chip-select (cs) nodes contain the memory devices nodes connected to +such as NOR (e.g. cfi-flash) and NAND. + +Required child cs node properties: + +- #address-cells: Must be 2. + +- #size-cells: Must be 1. + +- ranges: Empty property indicating that child nodes can inherit + memory layout. + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + +- mpmc,cs: Chip select number. Indicates to the pl0172 driver + which chipselect is used for accessing the memory. + +- mpmc,memory-width: Width of the chip select memory. Must be equal to + either 8, 16 or 32. + +Optional child cs node config properties: + +- mpmc,async-page-mode: Enable asynchronous page mode. + +- mpmc,cs-active-high: Set chip select polarity to active high. + +- mpmc,byte-lane-low: Set byte lane state to low. + +- mpmc,extended-wait: Enable extended wait. + +- mpmc,buffer-enable: Enable write buffer. + +- mpmc,write-protect: Enable write protect. + +Optional child cs node timing properties: + +- mpmc,write-enable-delay: Delay from chip select assertion to write + enable (WE signal) in nano seconds. + +- mpmc,output-enable-delay: Delay from chip select assertion to output + enable (OE signal) in nano seconds. + +- mpmc,write-access-delay: Delay from chip select assertion to write + access in nano seconds. + +- mpmc,read-access-delay: Delay from chip select assertion to read + access in nano seconds. + +- mpmc,page-mode-read-delay: Delay for asynchronous page mode sequential + accesses in nano seconds. + +- mpmc,turn-round-delay: Delay between access to memory banks in nano + seconds. + +If any of the above timing parameters are absent, current parameter value will +be taken from the corresponding HW reg. + +Example for pl172 with nor flash on chip select 0 shown below. + +emc: memory-controller@40005000 { + compatible = "arm,pl172", "arm,primecell"; + reg = <0x40005000 0x1000>; + clocks = <&ccu1 CLK_CPU_EMCDIV>, <&ccu1 CLK_CPU_EMC>; + clock-names = "mpmcclk", "apb_pclk"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x1c000000 0x1000000 + 1 0 0x1d000000 0x1000000 + 2 0 0x1e000000 0x1000000 + 3 0 0x1f000000 0x1000000>; + + cs0 { + #address-cells = <2>; + #size-cells = <1>; + ranges; + + mpmc,cs = <0>; + mpmc,memory-width = <16>; + mpmc,byte-lane-low; + mpmc,write-enable-delay = <0>; + mpmc,output-enable-delay = <0>; + mpmc,read-enable-delay = <70>; + mpmc,page-mode-read-delay = <70>; + + flash@0,0 { + compatible = "sst,sst39vf320", "cfi-flash"; + reg = <0 0 0x400000>; + bank-width = <2>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "data"; + reg = <0 0x400000>; + }; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 54e7ad47c94d26614acb4fcc577a79b3347c2d86 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Jul 2015 21:35:28 +0200 Subject: spi: mpc512x-psc: adapt mpc5121-psc document to reality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drivers support MPC5125 additionally to MPC5121, and there is an spi mode that is also supported. Additionally some minor corrections are done. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- .../bindings/powerpc/fsl/mpc5121-psc.txt | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt index 8832e8798912..647817527c88 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt @@ -6,14 +6,14 @@ PSC in UART mode For PSC in UART mode the needed PSC serial devices are specified by fsl,mpc5121-psc-uart nodes in the fsl,mpc5121-immr SoC node. Additionally the PSC FIFO -Controller node fsl,mpc5121-psc-fifo is requered there: +Controller node fsl,mpc5121-psc-fifo is required there: -fsl,mpc5121-psc-uart nodes +fsl,mpc512x-psc-uart nodes -------------------------- Required properties : - - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc" - - cell-index : Index of the PSC in hardware + - compatible : Should contain "fsl,-psc-uart" and "fsl,-psc" + Supported s: mpc5121, mpc5125 - reg : Offset and length of the register set for the PSC device - interrupts : where a is the interrupt number of the PSC FIFO Controller and b is a field that represents an @@ -25,12 +25,21 @@ Recommended properties : - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4) - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4) +PSC in SPI mode +--------------- -fsl,mpc5121-psc-fifo node +Similar to the UART mode a PSC can be operated in SPI mode. The compatible used +for that is fsl,mpc5121-psc-spi. It requires a fsl,mpc5121-psc-fifo as well. +The required and recommended properties are identical to the +fsl,mpc5121-psc-uart nodes, just use spi instead of uart in the compatible +string. + +fsl,mpc512x-psc-fifo node ------------------------- Required properties : - - compatible : Should be "fsl,mpc5121-psc-fifo" + - compatible : Should be "fsl,-psc-fifo" + Supported s: mpc5121, mpc5125 - reg : Offset and length of the register set for the PSC FIFO Controller - interrupts : where a is the interrupt number of the @@ -39,6 +48,9 @@ Required properties : - interrupt-parent : the phandle for the interrupt controller that services interrupts for this device. +Recommended properties : + - clocks : specifies the clock needed to operate the fifo controller + - clock-names : name(s) for the clock(s) listed in clocks Example for a board using PSC0 and PSC1 devices in serial mode: -- cgit v1.2.3-59-g8ed1b From 75c27f119b6475d95374bdad872c6938b5c26196 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 11 Jun 2015 15:22:43 -0700 Subject: rcu: Remove CONFIG_RCU_CPU_STALL_INFO The CONFIG_RCU_CPU_STALL_INFO has been default-y for a couple of releases with no complaints, so it is time to eliminate this Kconfig option entirely, so that the long-form RCU CPU stall warnings cannot be disabled. This commit does just that. Signed-off-by: Paul E. McKenney --- Documentation/RCU/stallwarn.txt | 12 +----- kernel/rcu/tree.h | 4 -- kernel/rcu/tree_plugin.h | 45 ---------------------- lib/Kconfig.debug | 14 ------- .../selftests/rcutorture/configs/rcu/TREE01 | 1 - .../selftests/rcutorture/configs/rcu/TREE02 | 1 - .../selftests/rcutorture/configs/rcu/TREE02-T | 1 - .../selftests/rcutorture/configs/rcu/TREE03 | 1 - .../selftests/rcutorture/configs/rcu/TREE04 | 1 - .../selftests/rcutorture/configs/rcu/TREE05 | 1 - .../selftests/rcutorture/configs/rcu/TREE06 | 1 - .../selftests/rcutorture/configs/rcu/TREE07 | 1 - .../selftests/rcutorture/configs/rcu/TREE08 | 1 - .../selftests/rcutorture/configs/rcu/TREE08-T | 1 - .../selftests/rcutorture/configs/rcu/TREE09 | 1 - .../selftests/rcutorture/doc/TREE_RCU-kconfig.txt | 1 - 16 files changed, 2 insertions(+), 85 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index b57c0c1cdac6..046f32637b95 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -26,12 +26,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT Stall-warning messages may be enabled and disabled completely via /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress. -CONFIG_RCU_CPU_STALL_INFO - - This kernel configuration parameter causes the stall warning to - print out additional per-CPU diagnostic information, including - information on scheduling-clock ticks and RCU's idle-CPU tracking. - RCU_STALL_DELAY_DELTA Although the lockdep facility is extremely useful, it does add @@ -101,15 +95,13 @@ interact. Please note that it is not possible to entirely eliminate this sort of false positive without resorting to things like stop_machine(), which is overkill for this sort of problem. -If the CONFIG_RCU_CPU_STALL_INFO kernel configuration parameter is set, -more information is printed with the stall-warning message, for example: +Recent kernels will print a long form of the stall-warning message: INFO: rcu_preempt detected stall on CPU 0: (63959 ticks this GP) idle=241/3fffffffffffffff/0 softirq=82/543 (t=65000 jiffies) -In kernels with CONFIG_RCU_FAST_NO_HZ, even more information is -printed: +In kernels with CONFIG_RCU_FAST_NO_HZ, more information is printed: INFO: rcu_preempt detected stall on CPU 0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 nonlazy_posted: 25 .D diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index faee5242d6ff..7c0b09d754a1 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -288,12 +288,10 @@ struct rcu_data { bool gpwrap; /* Possible gpnum/completed wrap. */ struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ unsigned long grpmask; /* Mask to apply to leaf qsmask. */ -#ifdef CONFIG_RCU_CPU_STALL_INFO unsigned long ticks_this_gp; /* The number of scheduling-clock */ /* ticks this CPU has handled */ /* during and after the last grace */ /* period it is aware of. */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ /* 2) batch handling */ /* @@ -388,9 +386,7 @@ struct rcu_data { #endif /* #ifdef CONFIG_RCU_NOCB_CPU */ /* 8) RCU CPU stall data. */ -#ifdef CONFIG_RCU_CPU_STALL_INFO unsigned int softirq_snap; /* Snapshot of softirq activity. */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ int cpu; struct rcu_state *rsp; diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 7234f03e0aa2..ef41c1b04ba6 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -82,8 +82,6 @@ static void __init rcu_bootup_announce_oddness(void) pr_info("\tRCU lockdep checking is enabled.\n"); if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_RUNNABLE)) pr_info("\tRCU torture testing starts during boot.\n"); - if (IS_ENABLED(CONFIG_RCU_CPU_STALL_INFO)) - pr_info("\tAdditional per-CPU info printed with stalls.\n"); if (RCU_NUM_LVLS >= 4) pr_info("\tFour(or more)-level hierarchy is enabled.\n"); if (RCU_FANOUT_LEAF != 16) @@ -418,8 +416,6 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp) rcu_print_detail_task_stall_rnp(rnp); } -#ifdef CONFIG_RCU_CPU_STALL_INFO - static void rcu_print_task_stall_begin(struct rcu_node *rnp) { pr_err("\tTasks blocked on level-%d rcu_node (CPUs %d-%d):", @@ -431,18 +427,6 @@ static void rcu_print_task_stall_end(void) pr_cont("\n"); } -#else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ - -static void rcu_print_task_stall_begin(struct rcu_node *rnp) -{ -} - -static void rcu_print_task_stall_end(void) -{ -} - -#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */ - /* * Scan the current list of tasks blocked within RCU read-side critical * sections, printing out the tid of each. @@ -1685,8 +1669,6 @@ early_initcall(rcu_register_oom_notifier); #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */ -#ifdef CONFIG_RCU_CPU_STALL_INFO - #ifdef CONFIG_RCU_FAST_NO_HZ static void print_cpu_stall_fast_no_hz(char *cp, int cpu) @@ -1775,33 +1757,6 @@ static void increment_cpu_stall_ticks(void) raw_cpu_inc(rsp->rda->ticks_this_gp); } -#else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ - -static void print_cpu_stall_info_begin(void) -{ - pr_cont(" {"); -} - -static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) -{ - pr_cont(" %d", cpu); -} - -static void print_cpu_stall_info_end(void) -{ - pr_cont("} "); -} - -static void zero_cpu_stall_ticks(struct rcu_data *rdp) -{ -} - -static void increment_cpu_stall_ticks(void) -{ -} - -#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */ - #ifdef CONFIG_RCU_NOCB_CPU /* diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e2894b23efb6..8a34205d6922 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1353,20 +1353,6 @@ config RCU_CPU_STALL_TIMEOUT RCU grace period persists, additional CPU stall warnings are printed at more widely spaced intervals. -config RCU_CPU_STALL_INFO - bool "Print additional diagnostics on RCU CPU stall" - depends on (TREE_RCU || PREEMPT_RCU) && DEBUG_KERNEL - default y - help - For each stalled CPU that is aware of the current RCU grace - period, print out additional per-CPU diagnostic information - regarding scheduling-clock ticks, idle state, and, - for RCU_FAST_NO_HZ kernels, idle-entry state. - - Say N if you are unsure. - - Say Y if you want to enable such diagnostics. - config RCU_TRACE bool "Enable tracing for RCU" depends on DEBUG_KERNEL diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 8e9137f66831..f572b873c620 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 @@ -13,7 +13,6 @@ CONFIG_MAXSMP=y CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ZERO=y CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index aeea6a204d14..ef6a22c44dea 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 @@ -17,7 +17,6 @@ CONFIG_RCU_FANOUT_LEAF=3 CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T index 2ac9e68ea3d1..917d2517b5b5 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T @@ -17,6 +17,5 @@ CONFIG_RCU_FANOUT_LEAF=3 CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index 72aa7d87ea99..7a17c503b382 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 @@ -13,7 +13,6 @@ CONFIG_RCU_FANOUT=2 CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=y CONFIG_RCU_KTHREAD_PRIO=2 CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 3f5112751cda..39a2c6d7d7ec 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 @@ -17,6 +17,5 @@ CONFIG_RCU_FANOUT=4 CONFIG_RCU_FANOUT_LEAF=4 CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 index c04dfea6fd21..1257d3227b1e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 @@ -17,6 +17,5 @@ CONFIG_RCU_NOCB_CPU_NONE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y #CHECK#CONFIG_PROVE_RCU=y -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 index f51d2c73a68e..d3e456b74cbe 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 @@ -18,6 +18,5 @@ CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y #CHECK#CONFIG_PROVE_RCU=y -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index f422af4ff5a3..3956b4131f72 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 @@ -17,6 +17,5 @@ CONFIG_RCU_FANOUT=2 CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index a24d2ca30646..bb9b0c1a23c2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 @@ -19,7 +19,6 @@ CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_PROVE_LOCKING=y #CHECK#CONFIG_PROVE_RCU=y -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T index b2b8cea69dc9..2ad13f0d29cc 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T @@ -17,6 +17,5 @@ CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 index aa4ed08d999d..6710e749d9de 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 @@ -13,7 +13,6 @@ CONFIG_SUSPEND=n CONFIG_HIBERNATION=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n #CHECK#CONFIG_RCU_EXPERT=n diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index b24c0004fc49..657f3a035488 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt @@ -16,7 +16,6 @@ CONFIG_PROVE_LOCKING -- Do several, covering CONFIG_DEBUG_LOCK_ALLOC=y and not. CONFIG_PROVE_RCU -- Hardwired to CONFIG_PROVE_LOCKING. CONFIG_RCU_BOOST -- one of PREEMPT_RCU. CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. -CONFIG_RCU_CPU_STALL_INFO -- Now default, avoid at least twice. CONFIG_RCU_FANOUT -- Cover hierarchy, but overlap with others. CONFIG_RCU_FANOUT_LEAF -- Do one non-default. CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL. -- cgit v1.2.3-59-g8ed1b From 99a930b0d2b018f31474d69137f311ce3581a4c2 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 30 Jun 2015 14:54:09 -0700 Subject: documentation: Describe new expedited stall warnings Signed-off-by: Paul E. McKenney --- Documentation/RCU/stallwarn.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'Documentation') diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 046f32637b95..efb9454875ab 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -163,6 +163,23 @@ message will be about three times the interval between the beginning of the stall and the first message. +Stall Warnings for Expedited Grace Periods + +If an expedited grace period detects a stall, it will place a message +like the following in dmesg: + + INFO: rcu_sched detected expedited stalls on CPUs: { 1 2 6 } 26009 jiffies s: 1043 + +This indicates that CPUs 1, 2, and 6 have failed to respond to a +reschedule IPI, that the expedited grace period has been going on for +26,009 jiffies, and that the expedited grace-period sequence counter is +1043. The fact that this last value is odd indicates that an expedited +grace period is in flight. + +It is entirely possible to see stall warnings from normal and from +expedited grace periods at about the same time from the same run. + + What Causes RCU CPU Stall Warnings? So your kernel printed an RCU CPU stall warning. The next question is -- cgit v1.2.3-59-g8ed1b From cdacbe1f91264687af956e810278030f2ab5a3d0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 11 Jul 2015 16:24:45 -0700 Subject: rcu: Add fastpath bypassing funnel locking In the common case, there will be only one expedited grace period in the system at a given time, in which case it is not helpful to use funnel locking. This commit therefore adds a fastpath that bypasses funnel locking when the root ->exp_funnel_mutex is not held. Signed-off-by: Paul E. McKenney --- Documentation/RCU/trace.txt | 36 ++++++++++-------------------------- kernel/rcu/tree.c | 16 ++++++++++++++++ kernel/rcu/tree.h | 2 +- kernel/rcu/tree_trace.c | 4 ++-- 4 files changed, 29 insertions(+), 29 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 08651da15448..97f17e9decda 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -237,42 +237,26 @@ o "ktl" is the low-order 16 bits (in hexadecimal) of the count of The output of "cat rcu/rcu_preempt/rcuexp" looks as follows: -s=21872 d=21872 w=0 tf=0 wd1=0 wd2=0 n=0 sc=21872 dt=21872 dl=0 dx=21872 +s=21872 wd0=0 wd1=0 wd2=0 wd3=5 n=0 enq=0 sc=21872 These fields are as follows: -o "s" is the starting sequence number. +o "s" is the sequence number, with an odd number indicating that + an expedited grace period is in progress. -o "d" is the ending sequence number. When the starting and ending - numbers differ, there is an expedited grace period in progress. - -o "w" is the number of times that the sequence numbers have been - in danger of wrapping. - -o "tf" is the number of times that contention has resulted in a - failure to begin an expedited grace period. - -o "wd1" and "wd2" are the number of times that an attempt to - start an expedited grace period found that someone else had - completed an expedited grace period that satisfies the +o "wd0", "wd1", "wd2", and "wd3" are the number of times that an + attempt to start an expedited grace period found that someone + else had completed an expedited grace period that satisfies the attempted request. "Our work is done." -o "n" is number of times that contention was so great that - the request was demoted from an expedited grace period to - a normal grace period. +o "n" is number of times that a concurrent CPU-hotplug operation + forced a fallback to a normal grace period. + +o "enq" is the number of quiescent states still outstanding. o "sc" is the number of times that the attempt to start a new expedited grace period succeeded. -o "dt" is the number of times that we attempted to update - the "d" counter. - -o "dl" is the number of times that we failed to update the "d" - counter. - -o "dx" is the number of times that we succeeded in updating - the "d" counter. - The output of "cat rcu/rcu_preempt/rcugp" looks as follows: diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index f66f6e7730bc..3af0dee2d045 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3355,6 +3355,22 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s) struct rcu_node *rnp0; struct rcu_node *rnp1 = NULL; + /* + * First try directly acquiring the root lock in order to reduce + * latency in the common case where expedited grace periods are + * rare. We check mutex_is_locked() to avoid pathological levels of + * memory contention on ->exp_funnel_mutex in the heavy-load case. + */ + rnp0 = rcu_get_root(rsp); + if (!mutex_is_locked(&rnp0->exp_funnel_mutex)) { + if (mutex_trylock(&rnp0->exp_funnel_mutex)) { + if (sync_exp_work_done(rsp, rnp0, NULL, + &rsp->expedited_workdone0, s)) + return NULL; + return rnp0; + } + } + /* * Each pass through the following loop works its way * up the rcu_node tree, returning if others have done the diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 543ba726396c..80d974df0ea0 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -493,7 +493,7 @@ struct rcu_state { /* End of fields guarded by barrier_mutex. */ unsigned long expedited_sequence; /* Take a ticket. */ - atomic_long_t expedited_tryfail; /* # acquisition failures. */ + atomic_long_t expedited_workdone0; /* # done by others #0. */ atomic_long_t expedited_workdone1; /* # done by others #1. */ atomic_long_t expedited_workdone2; /* # done by others #2. */ atomic_long_t expedited_workdone3; /* # done by others #3. */ diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c index ec62369f1b02..6fc4c5ff3bb5 100644 --- a/kernel/rcu/tree_trace.c +++ b/kernel/rcu/tree_trace.c @@ -185,9 +185,9 @@ static int show_rcuexp(struct seq_file *m, void *v) { struct rcu_state *rsp = (struct rcu_state *)m->private; - seq_printf(m, "t=%lu tf=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n", + seq_printf(m, "s=%lu wd0=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n", rsp->expedited_sequence, - atomic_long_read(&rsp->expedited_tryfail), + atomic_long_read(&rsp->expedited_workdone0), atomic_long_read(&rsp->expedited_workdone1), atomic_long_read(&rsp->expedited_workdone2), atomic_long_read(&rsp->expedited_workdone3), -- cgit v1.2.3-59-g8ed1b From 69a462b9532c906441ccbec52b62e4a8b5f26271 Mon Sep 17 00:00:00 2001 From: Mars Cheng Date: Tue, 14 Jul 2015 14:07:08 +0800 Subject: Document: DT: Add bindings for mediatek MT6580 SoC Platform This adds a DT binding documentation for the MT6580 SoC from Mediatek. Signed-off-by: Mars Cheng Signed-off-by: Matthias Brugger --- Documentation/devicetree/bindings/arm/mediatek.txt | 4 ++++ Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt | 1 + Documentation/devicetree/bindings/serial/mtk-uart.txt | 3 ++- Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt | 6 +++++- 4 files changed, 12 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt index dd7550a29db6..2daa424a13a4 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.txt +++ b/Documentation/devicetree/bindings/arm/mediatek.txt @@ -5,6 +5,7 @@ Boards with a MediaTek mt65xx/mt81xx SoC shall have the following property: Required root node property: compatible: Must contain one of + "mediatek,mt6580" "mediatek,mt6589" "mediatek,mt6592" "mediatek,mt8127" @@ -14,6 +15,9 @@ compatible: Must contain one of Supported boards: +- Evaluation board for MT6580: + Required root node properties: + - compatible = "mediatek,mt6580-evbp1", "mediatek,mt6580"; - bq Aquaris5 smart phone: Required root node properties: - compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589"; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt index 4f5a5352ccd8..3c9c3a7f3d25 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt @@ -11,6 +11,7 @@ Required properties: "mediatek,mt6592-sysirq" "mediatek,mt6589-sysirq" "mediatek,mt6582-sysirq" + "mediatek,mt6580-sysirq" "mediatek,mt6577-sysirq" - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Use the same format as specified by GIC in diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index 8d63f1da07aa..a875997f2062 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -7,8 +7,9 @@ Required properties: * "mediatek,mt8173-uart" for MT8173 compatible UARTS * "mediatek,mt6589-uart" for MT6589 compatible UARTS * "mediatek,mt6582-uart" for MT6582 compatible UARTS + * "mediatek,mt6580-uart" for MT6580 compatible UARTS * "mediatek,mt6577-uart" for all compatible UARTS (MT8173, MT6589, MT6582, - MT6577) + MT6580, MT6577) - reg: The base address of the UART register bank. diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt index 7c4408ff4b83..53a3029b7589 100644 --- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt +++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt @@ -2,7 +2,11 @@ Mediatek MT6577, MT6572 and MT6589 Timers --------------------------------------- Required properties: -- compatible: Should be "mediatek,mt6577-timer" +- compatible should contain: + * "mediatek,mt6589-timer" for MT6589 compatible timers + * "mediatek,mt6580-timer" for MT6580 compatible timers + * "mediatek,mt6577-timer" for all compatible timers (MT6589, MT6580, + MT6577) - reg: Should contain location and length for timers register. - clocks: Clocks driving the timer hardware. This list should include two clocks. The order is system clock and as second clock the RTC clock. -- cgit v1.2.3-59-g8ed1b From def56bba7a5c623fd887d1f4b4c864521d615a76 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 15 Jul 2015 10:36:37 +0800 Subject: input: snvs_pwrkey: use "wakeup-source" as deivce tree property name Instead of inventing a new property name, let's use "wakeup-source" to be consistent with other driver and subsystem bindings. Signed-off-by: Shawn Guo Acked-by: Dmitry Torokhov --- Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 2 +- drivers/input/keyboard/snvs_pwrkey.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index 71a39c5bd486..f16bbd6644b8 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -408,7 +408,7 @@ System ON/OFF key driver Value type: Definition: Keycode to emit, KEY_POWER by default. - - wakeup: + - wakeup-source: Usage: option Value type: Definition: Button can wake-up the system. diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 512a1fc2a864..78fd24ca3813 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -122,7 +122,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); } - pdata->wakeup = of_property_read_bool(np, "wakeup"); + pdata->wakeup = of_property_read_bool(np, "wakeup-source"); pdata->irq = platform_get_irq(pdev, 0); if (pdata->irq < 0) { -- cgit v1.2.3-59-g8ed1b From 1dcafd3aeb0a70dbdd11b10269da2afc454e2395 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Sun, 19 Jul 2015 01:33:55 +0300 Subject: iio: Documentation: Remove bytes_per_datum attribute Remove sysfs bytes_per_datum device attribute ABI documentation since the attribute is not present anymore. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 7 ------- 1 file changed, 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 666a341b01b8..400d23441a61 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1040,13 +1040,6 @@ Contact: linux-iio@vger.kernel.org Description: Number of scans contained by the buffer. -What: /sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Bytes per scan. Due to alignment fun, the scan may be larger - than implied directly by the scan_element parameters. - What: /sys/bus/iio/devices/iio:deviceX/buffer/enable KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From 07a4257e3d758af96cf98b1e9baadeb627475b03 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:41 +0000 Subject: iio: mxs-lradc: clarify supported devices At the beginning the driver supported only i.MX28 SoC, but now the whole MXS platform. So remove any confusing comments which apply only to i.MX28. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/staging/iio/adc/mxs-lradc.txt | 2 +- drivers/staging/iio/adc/mxs-lradc.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt index 307537787574..555fb117d4fa 100644 --- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -1,4 +1,4 @@ -* Freescale i.MX28 LRADC device driver +* Freescale MXS LRADC device driver Required properties: - compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc" diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index d7c5223f1c3e..1ccb3676f2e5 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1,5 +1,5 @@ /* - * Freescale i.MX28 LRADC driver + * Freescale MXS LRADC driver * * Copyright (c) 2012 DENX Software Engineering, GmbH. * Marek Vasut @@ -1392,7 +1392,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { MXS_ADC_CHAN(4, IIO_VOLTAGE), MXS_ADC_CHAN(5, IIO_VOLTAGE), MXS_ADC_CHAN(6, IIO_VOLTAGE), - MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */ + MXS_ADC_CHAN(7, IIO_VOLTAGE), /* Combined Temperature sensors */ { .type = IIO_TEMP, @@ -1411,12 +1411,12 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .scan_index = -1, .channel = 9, }, - MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ - MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ - MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ - MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */ - MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */ - MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */ + MXS_ADC_CHAN(10, IIO_VOLTAGE), + MXS_ADC_CHAN(11, IIO_VOLTAGE), + MXS_ADC_CHAN(12, IIO_VOLTAGE), + MXS_ADC_CHAN(13, IIO_VOLTAGE), + MXS_ADC_CHAN(14, IIO_VOLTAGE), + MXS_ADC_CHAN(15, IIO_VOLTAGE), }; static int mxs_lradc_hw_init(struct mxs_lradc *lradc) @@ -1707,6 +1707,6 @@ static struct platform_driver mxs_lradc_driver = { module_platform_driver(mxs_lradc_driver); MODULE_AUTHOR("Marek Vasut "); -MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); +MODULE_DESCRIPTION("Freescale MXS LRADC driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3-59-g8ed1b From 2563f7fc83d655792ec9999e2dda7a37172ae6aa Mon Sep 17 00:00:00 2001 From: Jandy Gou Date: Fri, 17 Jul 2015 16:34:36 +0800 Subject: iio: magnetometer: mmc35240: Add DT binding doc Signed-off-by: Jandy Gou Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/magnetometer/mmc35240.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt new file mode 100644 index 000000000000..a01235c7fa15 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt @@ -0,0 +1,13 @@ +* MEMSIC MMC35240 magnetometer sensor + +Required properties: + + - compatible : should be "memsic,mmc35240" + - reg : the I2C address of the magnetometer + +Example: + +mmc35240@30 { + compatible = "memsic,mmc35240"; + reg = <0x30>; +}; -- cgit v1.2.3-59-g8ed1b From e757d5c4c367e747ae15186b753788f9c2752753 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 17 Jul 2015 16:39:40 +0200 Subject: ARM: sun4i: dt: Add DT bindings documentation for SUN4I Security System This patch adds documentation for Device-Tree bindings for the Security System cryptographic accelerator driver. Signed-off-by: LABBE Corentin Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/sun4i-ss.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/sun4i-ss.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/sun4i-ss.txt b/Documentation/devicetree/bindings/crypto/sun4i-ss.txt new file mode 100644 index 000000000000..1e02d177fea6 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/sun4i-ss.txt @@ -0,0 +1,19 @@ +* Allwinner Security System found on A20 SoC + +Required properties: +- compatible : Should be "allwinner,sun4i-a10-crypto". +- reg: Should contain the Security System register location and length. +- interrupts: Should contain the IRQ line for the Security System. +- clocks : List of clock specifiers, corresponding to ahb and ss. +- clock-names : Name of the functional clock, should be + * "ahb" : AHB gating clock + * "mod" : SS controller clock + +Example: + crypto: crypto-engine@01c15000 { + compatible = "allwinner,sun4i-a10-crypto"; + reg = <0x01c15000 0x1000>; + interrupts = ; + clocks = <&ahb_gates 5>, <&ss_clk>; + clock-names = "ahb", "mod"; + }; -- cgit v1.2.3-59-g8ed1b From 1ae25d626cfe7e11adc2c3e71d0de1f882954ef3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 20 Jul 2015 17:32:05 +0800 Subject: power: reset: at91: add sama5d3 reset function This patch introduces a new compatible string: "atmel,sama5d3-rstc" and new reset function for sama5d3 and later chips. As in sama5d3 or later chips, we don't have to shutdown the DDR controller before reset. Shutdown the DDR controller before reset is a workaround to avoid DDR signal driving the bus, but since sama5d3 and later chips there is no such a conflict. So in this patch: 1. the sama5d3 reset function only need to write the rstc register and return. 2. we can remove the code related with sama5d3 DDR controller as we don't use it at all. Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/arm/atmel-at91.txt | 2 +- drivers/power/reset/at91-reset.c | 26 ++++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8cbfa08..dd998b9c0433 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -87,7 +87,7 @@ One interrupt per TC channel in a TC block: RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". - can be "at91sam9260" or "at91sam9g45" + can be "at91sam9260" or "at91sam9g45" or "sama5d3" - reg: Should contain registers location and length Example: diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 36dc52fb2ec8..c378d4ec826f 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -123,6 +123,15 @@ 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) +{ + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + at91_rstc_base); + + return NOTIFY_DONE; +} + static void __init at91_reset_status(struct platform_device *pdev) { u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); @@ -155,13 +164,13 @@ 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,sama5d3-ddramc", }, { /* sentinel */ } }; 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 }, { /* sentinel */ } }; @@ -181,13 +190,16 @@ static int at91_reset_of_probe(struct platform_device *pdev) return -ENODEV; } - for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { - dev_err(&pdev->dev, "Could not map ram controller address\n"); - return -ENODEV; + 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]) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return -ENODEV; + } + idx++; } - idx++; } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); -- cgit v1.2.3-59-g8ed1b From 0ec5f8bd9920fc1a7d0b0d2d4876ea80665a70fd Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Mon, 20 Jul 2015 17:23:52 +0800 Subject: regulator: rk808: add the description about dvs gpio for rk808 add the description about dvs1, dvs2, and add the example. Signed-off-by: Chris Zhong Reviewed-by: Doug Anderson Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/mfd/rk808.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/rk808.txt b/Documentation/devicetree/bindings/mfd/rk808.txt index 9e6e2592e5c8..4ca6aab4273a 100644 --- a/Documentation/devicetree/bindings/mfd/rk808.txt +++ b/Documentation/devicetree/bindings/mfd/rk808.txt @@ -24,6 +24,10 @@ Optional properties: - vcc10-supply: The input supply for LDO_REG6 - vcc11-supply: The input supply for LDO_REG8 - vcc12-supply: The input supply for SWITCH_REG2 +- dvs-gpios: buck1/2 can be controlled by gpio dvs, this is GPIO specifiers + for 2 host gpio's used for dvs. The format of the gpio specifier depends in + the gpio controller. If DVS GPIOs aren't present, voltage changes will happen + very quickly with no slow ramp time. Regulators: All the regulators of RK808 to be instantiated shall be listed in a child node named 'regulators'. Each regulator is represented @@ -55,7 +59,9 @@ Example: interrupt-parent = <&gpio0>; interrupts = <4 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; - pinctrl-0 = <&pmic_int>; + pinctrl-0 = <&pmic_int &dvs_1 &dvs_2>; + dvs-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>, + <&gpio7 15 GPIO_ACTIVE_HIGH>; reg = <0x1b>; rockchip,system-power-controller; wakeup-source; -- cgit v1.2.3-59-g8ed1b From f686a36b4b79782a94f07769fb1c0187d24ea8a8 Mon Sep 17 00:00:00 2001 From: Andrea Galbusera Date: Tue, 14 Jul 2015 15:36:21 +0200 Subject: iio: adc: mcp320x: Add support for mcp3301 This adds support for Microchip's 13 bit 1 channel AD converter MCP3301 Signed-off-by: Andrea Galbusera Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/mcp320x.txt | 1 + drivers/iio/adc/Kconfig | 4 ++-- drivers/iio/adc/mcp320x.c | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt index b85184391b78..2a1f3af30155 100644 --- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt +++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt @@ -18,6 +18,7 @@ Required properties: "mcp3202" "mcp3204" "mcp3208" + "mcp3301" Examples: diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index dace593b158b..2714f043fa6c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -229,8 +229,8 @@ config MCP320X depends on SPI help Say yes here to build support for Microchip Technology's - MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or - MCP3208 analog to digital converter. + MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, + MCP3208 or MCP3301 analog to digital converter. This driver can also be built as a module. If so, the module will be called mcp320x. diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 8d9c9b9215dd..72969c8a0a51 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -25,6 +25,7 @@ * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201 * http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202 * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08 + * http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -47,6 +48,7 @@ enum { mcp3202, mcp3204, mcp3208, + mcp3301, }; struct mcp320x_chip_info { @@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index, switch (device_index) { case mcp3001: case mcp3201: + case mcp3301: return 0; case mcp3002: case mcp3202: @@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel, differential); - if (device_index != mcp3001 && device_index != mcp3201) { + if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) { ret = spi_sync(adc->spi, &adc->msg); if (ret < 0) return ret; @@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, case mcp3204: case mcp3208: return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4); + case mcp3301: + return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12); default: return -EINVAL; } @@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = { .num_channels = ARRAY_SIZE(mcp3208_channels), .resolution = 12 }, + [mcp3301] = { + .channels = mcp3201_channels, + .num_channels = ARRAY_SIZE(mcp3201_channels), + .resolution = 13 + }, }; static int mcp320x_probe(struct spi_device *spi) @@ -366,6 +376,9 @@ static const struct of_device_id mcp320x_dt_ids[] = { }, { .compatible = "mcp3208", .data = &mcp320x_chip_infos[mcp3208], + }, { + .compatible = "mcp3301", + .data = &mcp320x_chip_infos[mcp3301], }, { } }; @@ -381,6 +394,7 @@ static const struct spi_device_id mcp320x_id[] = { { "mcp3202", mcp3202 }, { "mcp3204", mcp3204 }, { "mcp3208", mcp3208 }, + { "mcp3301", mcp3301 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); -- cgit v1.2.3-59-g8ed1b From 5e9972cd6f1a69ee8a8ee8664d3e4c4ea59c0901 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Tue, 14 Jul 2015 19:23:22 +0530 Subject: iio: adc: vf610: Determine sampling frequencies by using minimum sample time The driver currently does not take into account the minimum sample time as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics. We set a static amount of cycles instead of considering the sample time as a given value, which depends on hardware characteristics. Determine sampling frequencies by first reading the device tree property node and then calculating the required Long Sample Time Adder (LSTAdder) value, based on the ADC clock frequency and sample time value obtained from the device tree. This LSTAdder value is then used for calculating the sampling frequencies possible. In case the sample time property is not specified through the device tree, a safe default value of 1000ns is assumed. Signed-off-by: Sanchayan Maity Acked-by: Stefan Agner Acked-by: Fugang Duan Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/vf610-adc.txt | 5 ++ drivers/iio/adc/vf610_adc.c | 79 ++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt index 3eb40e20c143..1aad0514e647 100644 --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt @@ -17,6 +17,11 @@ Recommended properties: - Frequency in normal mode (ADLPC=0, ADHSC=0) - Frequency in high-speed mode (ADLPC=0, ADHSC=1) - Frequency in low-power mode (ADLPC=1, ADHSC=0) +- min-sample-time: Minimum sampling time in nanoseconds. This value has + to be chosen according to the conversion mode and the connected analog + source resistance (R_as) and capacitance (C_as). Refer the datasheet's + operating requirements. A safe default across a wide range of R_as and + C_as as well as conversion modes is 1000ns. Example: adc0: adc@4003b000 { diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 480f335a0f9f..23b8fb94ec09 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -68,6 +68,9 @@ #define VF610_ADC_CLK_DIV8 0x60 #define VF610_ADC_CLK_MASK 0x60 #define VF610_ADC_ADLSMP_LONG 0x10 +#define VF610_ADC_ADSTS_SHORT 0x100 +#define VF610_ADC_ADSTS_NORMAL 0x200 +#define VF610_ADC_ADSTS_LONG 0x300 #define VF610_ADC_ADSTS_MASK 0x300 #define VF610_ADC_ADLPC_EN 0x80 #define VF610_ADC_ADHSC_EN 0x400 @@ -98,6 +101,8 @@ #define VF610_ADC_CALF 0x2 #define VF610_ADC_TIMEOUT msecs_to_jiffies(100) +#define DEFAULT_SAMPLE_TIME 1000 + enum clk_sel { VF610_ADCIOC_BUSCLK_SET, VF610_ADCIOC_ALTCLK_SET, @@ -124,6 +129,17 @@ enum conversion_mode_sel { VF610_ADC_CONV_LOW_POWER, }; +enum lst_adder_sel { + VF610_ADCK_CYCLES_3, + VF610_ADCK_CYCLES_5, + VF610_ADCK_CYCLES_7, + VF610_ADCK_CYCLES_9, + VF610_ADCK_CYCLES_13, + VF610_ADCK_CYCLES_17, + VF610_ADCK_CYCLES_21, + VF610_ADCK_CYCLES_25, +}; + struct vf610_adc_feature { enum clk_sel clk_sel; enum vol_ref vol_ref; @@ -132,6 +148,8 @@ struct vf610_adc_feature { int clk_div; int sample_rate; int res_mode; + u32 lst_adder_index; + u32 default_sample_time; bool calibration; bool ovwren; @@ -155,11 +173,13 @@ struct vf610_adc { }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; static inline void vf610_adc_calculate_rates(struct vf610_adc *info) { struct vf610_adc_feature *adc_feature = &info->adc_feature; unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); + u32 adck_period, lst_addr_min; int divisor, i; adck_rate = info->max_adck_rate[adc_feature->conv_mode]; @@ -173,6 +193,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) adc_feature->clk_div = 8; } + /* + * Determine the long sample time adder value to be used based + * on the default minimum sample time provided. + */ + adck_period = NSEC_PER_SEC / adck_rate; + lst_addr_min = adc_feature->default_sample_time / adck_period; + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) { + if (vf610_lst_adder[i] > lst_addr_min) { + adc_feature->lst_adder_index = i; + break; + } + } + /* * Calculate ADC sample frequencies * Sample time unit is ADCK cycles. ADCK clk source is ipg clock, @@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) * SFCAdder: fixed to 6 ADCK cycles * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles */ adck_rate = ipg_rate / info->adc_feature.clk_div; for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) info->sample_freq_avail[i] = - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3)); + adck_rate / (6 + vf610_hw_avgs[i] * + (25 + vf610_lst_adder[adc_feature->lst_adder_index])); } static inline void vf610_adc_cfg_init(struct vf610_adc *info) @@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info) break; } - /* Use the short sample mode */ - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + /* + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value + * determined. + */ + switch (adc_feature->lst_adder_index) { + case VF610_ADCK_CYCLES_3: + break; + case VF610_ADCK_CYCLES_5: + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_7: + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_9: + cfg_data |= VF610_ADC_ADSTS_LONG; + break; + case VF610_ADCK_CYCLES_13: + cfg_data |= VF610_ADC_ADLSMP_LONG; + break; + case VF610_ADCK_CYCLES_17: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_21: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_25: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + default: + dev_err(info->dev, "error in sample time select\n"); + } /* update hardware average selection */ cfg_data &= ~VF610_ADC_AVGS_MASK; @@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev) of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency", info->max_adck_rate, 3); + ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time", + &info->adc_feature.default_sample_time); + if (ret) + info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME; + platform_set_drvdata(pdev, indio_dev); init_completion(&info->completion); -- cgit v1.2.3-59-g8ed1b From 949163015ce6fdb76a5e846a3582d3c40c23c001 Mon Sep 17 00:00:00 2001 From: Paolo Pisati Date: Mon, 20 Jul 2015 18:23:50 +0200 Subject: x86/boot: Obsolete the MCA sys_desc_table The kernel does not support the MCA bus anymroe, so mark sys_desc_table as obsolete: remove any reference from the code together with the remaining of MCA logic. bloat-o-meter output: add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-55 (-55) function old new delta i386_start_kernel 128 119 -9 setup_arch 1421 1375 -46 Signed-off-by: Paolo Pisati Cc: Josh Triplett Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1437409430-8491-1-git-send-email-p.pisati@gmail.com Signed-off-by: Ingo Molnar --- Documentation/x86/zero-page.txt | 3 ++- arch/x86/boot/Makefile | 2 +- arch/x86/boot/boot.h | 3 --- arch/x86/boot/compressed/eboot.c | 4 ---- arch/x86/boot/main.c | 3 --- arch/x86/boot/mca.c | 38 ----------------------------------- arch/x86/include/asm/processor.h | 8 -------- arch/x86/include/uapi/asm/bootparam.h | 2 +- arch/x86/kernel/kexec-bzimage64.c | 3 --- arch/x86/kernel/setup.c | 5 ----- 10 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 arch/x86/boot/mca.c (limited to 'Documentation') diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 82fbdbc1e0b0..95a4d34af3fd 100644 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt @@ -17,7 +17,8 @@ Offset Proto Name Meaning (struct ist_info) 080/010 ALL hd0_info hd0 disk parameter, OBSOLETE!! 090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!! -0A0/010 ALL sys_desc_table System description table (struct sys_desc_table) +0A0/010 ALL sys_desc_table System description table (struct sys_desc_table), + OBSOLETE!! 0B0/010 ALL olpc_ofw_header OLPC's OpenFirmware CIF and friends 0C0/004 ALL ext_ramdisk_image ramdisk_image high 32bits 0C4/004 ALL ext_ramdisk_size ramdisk_size high 32bits diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 57bbf2fb21f6..0d553e54171b 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -23,7 +23,7 @@ targets += fdimage fdimage144 fdimage288 image.iso mtools.conf subdir- := compressed setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o -setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o +setup-y += early_serial_console.o edd.o header.o main.o memory.o setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o setup-y += video-mode.o version.o setup-$(CONFIG_X86_APM_BOOT) += apm.o diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index bd49ec61255c..0033e96c3f09 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -307,9 +307,6 @@ void query_edd(void); /* header.S */ void __attribute__((noreturn)) die(void); -/* mca.c */ -int query_mca(void); - /* memory.c */ int detect_memory(void); diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 2c82bd150d43..e140bccf9cf3 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -1041,7 +1041,6 @@ void setup_graphics(struct boot_params *boot_params) struct boot_params *make_boot_params(struct efi_config *c) { struct boot_params *boot_params; - struct sys_desc_table *sdt; struct apm_bios_info *bi; struct setup_header *hdr; struct efi_info *efi; @@ -1089,7 +1088,6 @@ struct boot_params *make_boot_params(struct efi_config *c) hdr = &boot_params->hdr; efi = &boot_params->efi_info; bi = &boot_params->apm_bios_info; - sdt = &boot_params->sys_desc_table; /* Copy the second sector to boot_params */ memcpy(&hdr->jump, image->image_base + 512, 512); @@ -1118,8 +1116,6 @@ struct boot_params *make_boot_params(struct efi_config *c) /* Clear APM BIOS info */ memset(bi, 0, sizeof(*bi)); - memset(sdt, 0, sizeof(*sdt)); - status = efi_parse_options(cmdline_ptr); if (status != EFI_SUCCESS) goto fail2; diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index fd6c9f236996..9bcea386db65 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -161,9 +161,6 @@ void main(void) /* Set keyboard repeat rate (why?) and query the lock flags */ keyboard_init(); - /* Query MCA information */ - query_mca(); - /* Query Intel SpeedStep (IST) information */ query_ist(); diff --git a/arch/x86/boot/mca.c b/arch/x86/boot/mca.c deleted file mode 100644 index a95a531148ef..000000000000 --- a/arch/x86/boot/mca.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright 2007 rPath, Inc. - All Rights Reserved - * Copyright 2009 Intel Corporation; author H. Peter Anvin - * - * This file is part of the Linux kernel, and is made available under - * the terms of the GNU General Public License version 2. - * - * ----------------------------------------------------------------------- */ - -/* - * Get the MCA system description table - */ - -#include "boot.h" - -int query_mca(void) -{ - struct biosregs ireg, oreg; - u16 len; - - initregs(&ireg); - ireg.ah = 0xc0; - intcall(0x15, &ireg, &oreg); - - if (oreg.eflags & X86_EFLAGS_CF) - return -1; /* No MCA present */ - - set_fs(oreg.es); - len = rdfs16(oreg.bx); - - if (len > sizeof(boot_params.sys_desc_table)) - len = sizeof(boot_params.sys_desc_table); - - copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len); - return 0; -} diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 43e6519df0d5..3e15e1358f21 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -647,14 +647,6 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) extern void set_task_blockstep(struct task_struct *task, bool on); -/* - * from system description table in BIOS. Mostly for MCA use, but - * others may find it useful: - */ -extern unsigned int machine_id; -extern unsigned int machine_submodel_id; -extern unsigned int BIOS_revision; - /* Boot loader type from the setup header: */ extern int bootloader_type; extern int bootloader_version; diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index ab456dc233b5..329254373479 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -120,7 +120,7 @@ struct boot_params { __u8 _pad3[16]; /* 0x070 */ __u8 hd0_info[16]; /* obsolete! */ /* 0x080 */ __u8 hd1_info[16]; /* obsolete! */ /* 0x090 */ - struct sys_desc_table sys_desc_table; /* 0x0a0 */ + struct sys_desc_table sys_desc_table; /* obsolete! */ /* 0x0a0 */ struct olpc_ofw_header olpc_ofw_header; /* 0x0b0 */ __u32 ext_ramdisk_image; /* 0x0c0 */ __u32 ext_ramdisk_size; /* 0x0c4 */ diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index ca83f7ac388b..961e51e9c6f6 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -223,9 +223,6 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, memset(¶ms->hd0_info, 0, sizeof(params->hd0_info)); memset(¶ms->hd1_info, 0, sizeof(params->hd1_info)); - /* Default sysdesc table */ - params->sys_desc_table.length = 0; - if (image->type == KEXEC_TYPE_CRASH) { ret = crash_setup_memmap_entries(image, params); if (ret) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 80f874bf999e..b143c2d04420 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -916,11 +916,6 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_32 apm_info.bios = boot_params.apm_bios_info; ist_info = boot_params.ist_info; - if (boot_params.sys_desc_table.length != 0) { - machine_id = boot_params.sys_desc_table.table[0]; - machine_submodel_id = boot_params.sys_desc_table.table[1]; - BIOS_revision = boot_params.sys_desc_table.table[2]; - } #endif saved_video_mode = boot_params.hdr.vid_mode; bootloader_type = boot_params.hdr.type_of_loader; -- cgit v1.2.3-59-g8ed1b From 36bd1683559e23d4032defadbfbd3ccd5601b8c8 Mon Sep 17 00:00:00 2001 From: Teresa Remmet Date: Thu, 16 Jul 2015 10:30:49 +0200 Subject: ARM: dts: Add phyBOARD-WEGA-AM335x rdk phyBOARD-WEGA-AM335x represents a direct soldered combination of a phyCORE-AM335x SoM and carrier board. Different kind of SoM options can be connected to the wega carrier board. So we created a separate wega dtsi file. The final dts contains the actual SoM on the carrier board. WEGA carrier board features: * ETH phy on carrier board: 1x MII * 1x CAN * 2x UART * USB0 (device) * USB1 (host) * mSD slot Signed-off-by: Teresa Remmet Signed-off-by: Tony Lindgren --- .../devicetree/bindings/arm/omap/omap.txt | 3 + arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/am335x-wega-rdk.dts | 22 +++ arch/arm/boot/dts/am335x-wega.dtsi | 151 +++++++++++++++++++++ 4 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/am335x-wega-rdk.dts create mode 100644 arch/arm/boot/dts/am335x-wega.dtsi (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index 4f6a82cef1d1..9f4e5136e568 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -135,6 +135,9 @@ Boards: - AM335X OrionLXm : Substation Automation Platform compatible = "novatech,am335x-lxm", "ti,am33xx" +- AM335X phyBOARD-WEGA: Single Board Computer dev kit + compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx" + - OMAP5 EVM : Evaluation Module compatible = "ti,omap5-evm", "ti,omap5" diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 1c62928587e0..180846365081 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -442,7 +442,8 @@ dtb-$(CONFIG_SOC_AM33XX) += \ am335x-nano.dtb \ am335x-pepper.dtb \ am335x-lxm.dtb \ - am335x-chiliboard.dtb + am335x-chiliboard.dtb \ + am335x-wega-rdk.dtb dtb-$(CONFIG_ARCH_OMAP4) += \ omap4-duovero-parlor.dtb \ omap4-panda.dtb \ diff --git a/arch/arm/boot/dts/am335x-wega-rdk.dts b/arch/arm/boot/dts/am335x-wega-rdk.dts new file mode 100644 index 000000000000..6431b7db8109 --- /dev/null +++ b/arch/arm/boot/dts/am335x-wega-rdk.dts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015 Phytec Messtechnik GmbH + * Author: Teresa Remmet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include "am335x-phycore-som.dtsi" +#include "am335x-wega.dtsi" + +/* SoM */ +&i2c_eeprom { + status = "okay"; +}; + +&i2c_rtc { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/am335x-wega.dtsi b/arch/arm/boot/dts/am335x-wega.dtsi new file mode 100644 index 000000000000..5e541bd1b45a --- /dev/null +++ b/arch/arm/boot/dts/am335x-wega.dtsi @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015 Phytec Messtechnik GmbH + * Author: Teresa Remmet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/ { + model = "Phytec AM335x phyBOARD-WEGA"; + compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx"; + +}; + +/* CAN Busses */ +&am33xx_pinmux { + dcan1_pins: pinmux_dcan1 { + pinctrl-single,pins = < + 0x168 (PIN_OUTPUT_PULLUP | MUX_MODE2) /* uart0_ctsn.d_can1_tx */ + 0x16c (PIN_INPUT_PULLUP | MUX_MODE2) /* uart0_rtsn.d_can1_rx */ + >; + }; +}; + +&dcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&dcan1_pins>; + status = "okay"; +}; + +/* Ethernet */ +&am33xx_pinmux { + ethernet1_pins: pinmux_ethernet1 { + pinctrl-single,pins = < + 0x40 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a0.mii2_txen */ + 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a1.mii2_rxdv */ + 0x48 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a2.mii2_txd3 */ + 0x4c (PIN_OUTPUT | MUX_MODE1) /* gpmc_a3.mii2_txd2 */ + 0x50 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a4.mii2_txd1 */ + 0x54 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a5.mii2_txd0 */ + 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a6.mii2_txclk */ + 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a7.mii2_rxclk */ + 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a8.mii2_rxd3 */ + 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a9.mii2_rxd2 */ + 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a10.mii2_rxd1 */ + 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a11.mii2_rxd0 */ + 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_wpn.mii2_rxerr */ + 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_ben1.mii2_col */ + >; + }; +}; + +&cpsw_emac1 { + phy_id = <&davinci_mdio>, <1>; + phy-mode = "mii"; + dual_emac_res_vlan = <2>; +}; + +&mac { + slaves = <2>; + pinctrl-names = "default"; + pinctrl-0 = <ðernet0_pins ðernet1_pins>; + dual_emac = <1>; +}; + +/* MMC */ +&am33xx_pinmux { + mmc1_pins: pinmux_mmc1 { + pinctrl-single,pins = < + 0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */ + 0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */ + 0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */ + 0x0FC (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */ + 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */ + 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */ + 0x160 (PIN_INPUT_PULLUP | MUX_MODE7) /* spi0_cs1.mmc0_sdcd */ + >; + }; +}; + +&mmc1 { + vmmc-supply = <&vmmc_reg>; + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +/* UARTs */ +&am33xx_pinmux { + uart0_pins: pinmux_uart0 { + pinctrl-single,pins = < + 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */ + 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */ + >; + }; + + uart1_pins: pinmux_uart1_pins { + pinctrl-single,pins = < + 0x180 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */ + 0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */ + 0x178 (PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */ + 0x17c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */ + >; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; +}; + +/* USB */ +&cppi41dma { + status = "okay"; +}; + +&usb_ctrl_mod { + status = "okay"; +}; + +&usb { + status = "okay"; +}; + +&usb0 { + dr_mode = "peripheral"; + status = "okay"; +}; + +&usb0_phy { + status = "okay"; +}; + +&usb1 { + dr_mode = "host"; + status = "okay"; +}; + +&usb1_phy { + status = "okay"; +}; -- cgit v1.2.3-59-g8ed1b From 019d8817b1b064c2bacfbcf40fc68184438ad05a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jul 2015 14:40:06 +0200 Subject: PM / sleep: Allow devices without runtime PM to do direct-complete Don't unset the direct_complete flag on devices that have runtime PM disabled, if they are runtime suspended. This is needed because otherwise ancestor devices wouldn't be able to do direct_complete without adding runtime PM support to all its descendants. Also removes pm_runtime_suspended_if_enabled() because it's now unused. Signed-off-by: Tomeu Vizoso Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- Documentation/power/devices.txt | 7 +++++++ Documentation/power/runtime_pm.txt | 4 ---- drivers/base/power/main.c | 2 +- include/linux/pm_runtime.h | 6 ------ 4 files changed, 8 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index d172bce0fd49..8ba6625fdd63 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -341,6 +341,13 @@ the phases are: and is entirely responsible for bringing the device back to the functional state as appropriate. + Note that this direct-complete procedure applies even if the device is + disabled for runtime PM; only the runtime-PM status matters. It follows + that if a device has system-sleep callbacks but does not support runtime + PM, then its prepare callback must never return a positive value. This + is because all devices are initially set to runtime-suspended with + runtime PM disabled. + 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the appropriate low-power state, depending on the bus type the device is on, diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index e76dc0ad4d2b..0784bc3a2ab5 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -445,10 +445,6 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: bool pm_runtime_status_suspended(struct device *dev); - return true if the device's runtime PM status is 'suspended' - bool pm_runtime_suspended_if_enabled(struct device *dev); - - return true if the device's runtime PM status is 'suspended' and its - 'power.disable_depth' field is equal to 1 - void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 30b7bbfdc558..1710c26ba097 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1377,7 +1377,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.direct_complete) { if (pm_runtime_status_suspended(dev)) { pm_runtime_disable(dev); - if (pm_runtime_suspended_if_enabled(dev)) + if (pm_runtime_status_suspended(dev)) goto Complete; pm_runtime_enable(dev); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 30e84d48bfea..3bdbb4189780 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -98,11 +98,6 @@ static inline bool pm_runtime_status_suspended(struct device *dev) return dev->power.runtime_status == RPM_SUSPENDED; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) -{ - return pm_runtime_status_suspended(dev) && dev->power.disable_depth == 1; -} - static inline bool pm_runtime_enabled(struct device *dev) { return !dev->power.disable_depth; @@ -164,7 +159,6 @@ static inline void device_set_run_wake(struct device *dev, bool enable) {} static inline bool pm_runtime_suspended(struct device *dev) { return false; } static inline bool pm_runtime_active(struct device *dev) { return true; } static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) { return false; } static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline void pm_runtime_no_callbacks(struct device *dev) {} -- cgit v1.2.3-59-g8ed1b From 5eb26c60590983e11f567916a83d1f0a70986553 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Tue, 23 Jun 2015 16:09:00 +0200 Subject: ARM: STi: DT: Rename st_pll3200c32_407_c0_x into st_pll3200c32_cx_x Use a generic name for this kind of PLL Signed-off-by: Gabriel Fernandez Signed-off-by: Maxime Coquelin --- Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt | 4 ++-- arch/arm/boot/dts/stih407-clock.dtsi | 4 ++-- arch/arm/boot/dts/stih410-clock.dtsi | 4 ++-- arch/arm/boot/dts/stih418-clock.dtsi | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt index efb51cf0c845..d8b168ebd5f1 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt @@ -21,8 +21,8 @@ Required properties: "st,stih416-plls-c32-ddr", "st,clkgen-plls-c32" "st,stih407-plls-c32-a0", "st,clkgen-plls-c32" "st,stih407-plls-c32-a9", "st,clkgen-plls-c32" - "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32" - "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32" + "sst,plls-c32-cx_0", "st,clkgen-plls-c32" + "sst,plls-c32-cx_1", "st,clkgen-plls-c32" "st,stih415-gpu-pll-c32", "st,clkgengpu-pll-c32" "st,stih416-gpu-pll-c32", "st,clkgengpu-pll-c32" diff --git a/arch/arm/boot/dts/stih407-clock.dtsi b/arch/arm/boot/dts/stih407-clock.dtsi index e65744fc12ab..ad45f5e8fac7 100644 --- a/arch/arm/boot/dts/stih407-clock.dtsi +++ b/arch/arm/boot/dts/stih407-clock.dtsi @@ -134,7 +134,7 @@ clk_s_c0_pll0: clk-s-c0-pll0 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; @@ -143,7 +143,7 @@ clk_s_c0_pll1: clk-s-c0-pll1 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; diff --git a/arch/arm/boot/dts/stih410-clock.dtsi b/arch/arm/boot/dts/stih410-clock.dtsi index 6b5803a30096..d1f2acafc9b6 100644 --- a/arch/arm/boot/dts/stih410-clock.dtsi +++ b/arch/arm/boot/dts/stih410-clock.dtsi @@ -137,7 +137,7 @@ clk_s_c0_pll0: clk-s-c0-pll0 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; @@ -146,7 +146,7 @@ clk_s_c0_pll1: clk-s-c0-pll1 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; diff --git a/arch/arm/boot/dts/stih418-clock.dtsi b/arch/arm/boot/dts/stih418-clock.dtsi index 0ab23daa2829..148e1772465f 100644 --- a/arch/arm/boot/dts/stih418-clock.dtsi +++ b/arch/arm/boot/dts/stih418-clock.dtsi @@ -137,7 +137,7 @@ clk_s_c0_pll0: clk-s-c0-pll0 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; @@ -146,7 +146,7 @@ clk_s_c0_pll1: clk-s-c0-pll1 { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32"; + compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; -- cgit v1.2.3-59-g8ed1b From f78f5b90c4ffa559e400c3919a02236101f29f3f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 18 Jun 2015 15:50:02 -0700 Subject: rcu: Rename rcu_lockdep_assert() to RCU_LOCKDEP_WARN() This commit renames rcu_lockdep_assert() to RCU_LOCKDEP_WARN() for consistency with the WARN() series of macros. This also requires inverting the sense of the conditional, which this commit also does. Reported-by: Ingo Molnar Signed-off-by: Paul E. McKenney Reviewed-by: Ingo Molnar --- Documentation/RCU/whatisRCU.txt | 2 +- arch/x86/kernel/cpu/mcheck/mce.c | 6 ++-- arch/x86/kernel/traps.c | 2 +- drivers/base/power/opp.c | 4 +-- include/linux/fdtable.h | 4 +-- include/linux/rcupdate.h | 63 ++++++++++++++++++++++++++-------------- kernel/cgroup.c | 4 +-- kernel/pid.c | 5 ++-- kernel/rcu/srcu.c | 10 +++---- kernel/rcu/tiny.c | 8 ++--- kernel/rcu/tree.c | 28 +++++++++--------- kernel/rcu/tree_plugin.h | 8 ++--- kernel/rcu/update.c | 4 +-- kernel/sched/core.c | 8 ++--- kernel/workqueue.c | 20 ++++++------- security/device_cgroup.c | 6 ++-- 16 files changed, 101 insertions(+), 81 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 5746b0c77f3e..adc2184009c5 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -883,7 +883,7 @@ All: lockdep-checked RCU-protected pointer access rcu_access_pointer rcu_dereference_raw - rcu_lockdep_assert + RCU_LOCKDEP_WARN rcu_sleep_check RCU_NONIDLE diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index df919ff103c3..3d6b5269fb2e 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -54,9 +54,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex); #define rcu_dereference_check_mce(p) \ ({ \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&mce_chrdev_read_mutex), \ - "suspicious rcu_dereference_check_mce() usage"); \ + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&mce_chrdev_read_mutex), \ + "suspicious rcu_dereference_check_mce() usage"); \ smp_load_acquire(&(p)); \ }) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index f5791927aa64..c5a5231d1d11 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -136,7 +136,7 @@ enum ctx_state ist_enter(struct pt_regs *regs) preempt_count_add(HARDIRQ_OFFSET); /* This code is a bit fragile. Test it. */ - rcu_lockdep_assert(rcu_is_watching(), "ist_enter didn't work"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work"); return prev_state; } diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 677fb2843553..3b188f20b43f 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -110,8 +110,8 @@ static DEFINE_MUTEX(dev_opp_list_lock); #define opp_rcu_lockdep_assert() \ do { \ - rcu_lockdep_assert(rcu_read_lock_held() || \ - lockdep_is_held(&dev_opp_list_lock), \ + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \ + !lockdep_is_held(&dev_opp_list_lock), \ "Missing rcu_read_lock() or " \ "dev_opp_list_lock protection"); \ } while (0) diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index fbb88740634a..674e3e226465 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -86,8 +86,8 @@ static inline struct file *__fcheck_files(struct files_struct *files, unsigned i static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) { - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&files->file_lock), + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && + !lockdep_is_held(&files->file_lock), "suspicious rcu_dereference_check() usage"); return __fcheck_files(files, fd); } diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 33ec16b9c2ee..ff476515f716 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -536,6 +536,11 @@ static inline int rcu_read_lock_sched_held(void) #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +/* Deprecate rcu_lockdep_assert(): Use RCU_LOCKDEP_WARN() instead. */ +static inline void __attribute((deprecated)) deprecate_rcu_lockdep_assert(void) +{ +} + #ifdef CONFIG_PROVE_RCU /** @@ -546,17 +551,32 @@ static inline int rcu_read_lock_sched_held(void) #define rcu_lockdep_assert(c, s) \ do { \ static bool __section(.data.unlikely) __warned; \ + deprecate_rcu_lockdep_assert(); \ if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ __warned = true; \ lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ } \ } while (0) +/** + * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met + * @c: condition to check + * @s: informative message + */ +#define RCU_LOCKDEP_WARN(c, s) \ + do { \ + static bool __section(.data.unlikely) __warned; \ + if (debug_lockdep_rcu_enabled() && !__warned && (c)) { \ + __warned = true; \ + lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ + } \ + } while (0) + #if defined(CONFIG_PROVE_RCU) && !defined(CONFIG_PREEMPT_RCU) static inline void rcu_preempt_sleep_check(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_lock_map), - "Illegal context switch in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map), + "Illegal context switch in RCU read-side critical section"); } #else /* #ifdef CONFIG_PROVE_RCU */ static inline void rcu_preempt_sleep_check(void) @@ -567,15 +587,16 @@ static inline void rcu_preempt_sleep_check(void) #define rcu_sleep_check() \ do { \ rcu_preempt_sleep_check(); \ - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), \ - "Illegal context switch in RCU-bh read-side critical section"); \ - rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), \ - "Illegal context switch in RCU-sched read-side critical section"); \ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), \ + "Illegal context switch in RCU-bh read-side critical section"); \ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), \ + "Illegal context switch in RCU-sched read-side critical section"); \ } while (0) #else /* #ifdef CONFIG_PROVE_RCU */ -#define rcu_lockdep_assert(c, s) do { } while (0) +#define rcu_lockdep_assert(c, s) deprecate_rcu_lockdep_assert() +#define RCU_LOCKDEP_WARN(c, s) do { } while (0) #define rcu_sleep_check() do { } while (0) #endif /* #else #ifdef CONFIG_PROVE_RCU */ @@ -606,13 +627,13 @@ static inline void rcu_preempt_sleep_check(void) ({ \ /* Dependency order vs. p above. */ \ typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ + RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(________p1)); \ }) #define __rcu_dereference_protected(p, c, space) \ ({ \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \ + RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_protected() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(p)); \ }) @@ -836,8 +857,8 @@ static inline void rcu_read_lock(void) __rcu_read_lock(); __acquire(RCU); rcu_lock_acquire(&rcu_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock() used illegally while idle"); } /* @@ -887,8 +908,8 @@ static inline void rcu_read_lock(void) */ static inline void rcu_read_unlock(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock() used illegally while idle"); __release(RCU); __rcu_read_unlock(); rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ @@ -916,8 +937,8 @@ static inline void rcu_read_lock_bh(void) local_bh_disable(); __acquire(RCU_BH); rcu_lock_acquire(&rcu_bh_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock_bh() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock_bh() used illegally while idle"); } /* @@ -927,8 +948,8 @@ static inline void rcu_read_lock_bh(void) */ static inline void rcu_read_unlock_bh(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock_bh() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock_bh() used illegally while idle"); rcu_lock_release(&rcu_bh_lock_map); __release(RCU_BH); local_bh_enable(); @@ -952,8 +973,8 @@ static inline void rcu_read_lock_sched(void) preempt_disable(); __acquire(RCU_SCHED); rcu_lock_acquire(&rcu_sched_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock_sched() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock_sched() used illegally while idle"); } /* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ @@ -970,8 +991,8 @@ static inline notrace void rcu_read_lock_sched_notrace(void) */ static inline void rcu_read_unlock_sched(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock_sched() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock_sched() used illegally while idle"); rcu_lock_release(&rcu_sched_lock_map); __release(RCU_SCHED); preempt_enable(); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f89d9292eee6..b89f3168411b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -107,8 +107,8 @@ static DEFINE_SPINLOCK(release_agent_path_lock); struct percpu_rw_semaphore cgroup_threadgroup_rwsem; #define cgroup_assert_mutex_or_rcu_locked() \ - rcu_lockdep_assert(rcu_read_lock_held() || \ - lockdep_is_held(&cgroup_mutex), \ + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \ + !lockdep_is_held(&cgroup_mutex), \ "cgroup_mutex or RCU read lock required"); /* diff --git a/kernel/pid.c b/kernel/pid.c index 4fd07d5b7baf..ca368793808e 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -451,9 +451,8 @@ EXPORT_SYMBOL(pid_task); */ struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) { - rcu_lockdep_assert(rcu_read_lock_held(), - "find_task_by_pid_ns() needs rcu_read_lock()" - " protection"); + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "find_task_by_pid_ns() needs rcu_read_lock() protection"); return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID); } diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index de35087c92a5..d3fcb2ec8536 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -415,11 +415,11 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount) struct rcu_head *head = &rcu.head; bool done = false; - rcu_lockdep_assert(!lock_is_held(&sp->dep_map) && - !lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&sp->dep_map) || + lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section"); might_sleep(); init_completion(&rcu.completion); diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index c291bd65d2cb..d0471056d0af 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -191,10 +191,10 @@ static void rcu_process_callbacks(struct softirq_action *unused) */ void synchronize_sched(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_sched() in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_sched() in RCU read-side critical section"); cond_resched(); } EXPORT_SYMBOL_GPL(synchronize_sched); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index cb64d7e13d24..0a73d26357a2 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -649,12 +649,12 @@ static void rcu_eqs_enter_common(long long oldval, bool user) * It is illegal to enter an extended quiescent state while * in an RCU read-side critical section. */ - rcu_lockdep_assert(!lock_is_held(&rcu_lock_map), - "Illegal idle entry in RCU read-side critical section."); - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), - "Illegal idle entry in RCU-bh read-side critical section."); - rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), - "Illegal idle entry in RCU-sched read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map), + "Illegal idle entry in RCU read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), + "Illegal idle entry in RCU-bh read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), + "Illegal idle entry in RCU-sched read-side critical section."); } /* @@ -3161,10 +3161,10 @@ static inline int rcu_blocking_is_gp(void) */ void synchronize_sched(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_sched() in RCU-sched read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_sched() in RCU-sched read-side critical section"); if (rcu_blocking_is_gp()) return; if (rcu_gp_is_expedited()) @@ -3188,10 +3188,10 @@ EXPORT_SYMBOL_GPL(synchronize_sched); */ void synchronize_rcu_bh(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section"); if (rcu_blocking_is_gp()) return; if (rcu_gp_is_expedited()) diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index a983bc68a146..9e922f111d63 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -538,10 +538,10 @@ EXPORT_SYMBOL_GPL(call_rcu); */ void synchronize_rcu(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_rcu() in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu() in RCU read-side critical section"); if (!rcu_scheduler_active) return; if (rcu_gp_is_expedited()) diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index a0a0dd03c73a..47268fb1d27b 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -589,8 +589,8 @@ EXPORT_SYMBOL_GPL(call_rcu_tasks); void synchronize_rcu_tasks(void) { /* Complain if the scheduler has not started. */ - rcu_lockdep_assert(!rcu_scheduler_active, - "synchronize_rcu_tasks called too soon"); + RCU_LOCKDEP_WARN(rcu_scheduler_active, + "synchronize_rcu_tasks called too soon"); /* Wait for the grace period. */ wait_rcu_gp(call_rcu_tasks); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 78b4bad10081..5e73c79fadd0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2200,8 +2200,8 @@ unsigned long to_ratio(u64 period, u64 runtime) #ifdef CONFIG_SMP inline struct dl_bw *dl_bw_of(int i) { - rcu_lockdep_assert(rcu_read_lock_sched_held(), - "sched RCU must be held"); + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), + "sched RCU must be held"); return &cpu_rq(i)->rd->dl_bw; } @@ -2210,8 +2210,8 @@ static inline int dl_bw_cpus(int i) struct root_domain *rd = cpu_rq(i)->rd; int cpus = 0; - rcu_lockdep_assert(rcu_read_lock_sched_held(), - "sched RCU must be held"); + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), + "sched RCU must be held"); for_each_cpu_and(i, rd->span, cpu_active_mask) cpus++; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4c4f06176f74..cb91c63b4f4a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -338,20 +338,20 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq); #include #define assert_rcu_or_pool_mutex() \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq_pool_mutex), \ - "sched RCU or wq_pool_mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq_pool_mutex), \ + "sched RCU or wq_pool_mutex should be held") #define assert_rcu_or_wq_mutex(wq) \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq->mutex), \ - "sched RCU or wq->mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq->mutex), \ + "sched RCU or wq->mutex should be held") #define assert_rcu_or_wq_mutex_or_pool_mutex(wq) \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq->mutex) || \ - lockdep_is_held(&wq_pool_mutex), \ - "sched RCU, wq->mutex or wq_pool_mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq->mutex) && \ + !lockdep_is_held(&wq_pool_mutex), \ + "sched RCU, wq->mutex or wq_pool_mutex should be held") #define for_each_cpu_worker_pool(pool, cpu) \ for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0]; \ diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 188c1d26393b..73455089feef 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -400,9 +400,9 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup, { bool match = false; - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&devcgroup_mutex), - "device_cgroup:verify_new_ex called without proper synchronization"); + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && + lockdep_is_held(&devcgroup_mutex), + "device_cgroup:verify_new_ex called without proper synchronization"); if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) { if (behavior == DEVCG_DEFAULT_ALLOW) { -- cgit v1.2.3-59-g8ed1b From 655fe4effe0f1f40e4f6ca6b3cc64a7fe0032183 Mon Sep 17 00:00:00 2001 From: Kevin Strasser Date: Tue, 16 Jun 2015 10:35:30 -0700 Subject: usbcore: add sysfs support to xHCI usb3 hardware LPM Add a sysfs node to make it easier to verify if LPM is supported and being enabled for USB 3.0 devices. Signed-off-by: Kevin Strasser Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 14 ++++++++++++++ Documentation/usb/power-management.txt | 15 +++++++++++++-- drivers/usb/core/hub.c | 4 ++++ drivers/usb/core/sysfs.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index e5cc7633d013..e935625f5995 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -114,6 +114,20 @@ Description: enabled for the device. Developer can write y/Y/1 or n/N/0 to the file to enable/disable the feature. +What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm +Date: June 2015 +Contact: Kevin Strasser +Description: + If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is + plugged in to a xHCI host which supports link PM, it will check + if U1 and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host supports + USB3 hardware LPM, USB3 hardware LPM will be enabled for the + device and the USB device directory will contain a file named + power/usb3_hardware_lpm. The file holds a string value (enable + or disable) indicating whether or not USB3 hardware LPM is + enabled for the device. + What: /sys/bus/usb/devices/.../removable Date: February 2012 Contact: Matthew Garrett diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index b5f83911732a..4a15c90bc11d 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -521,10 +521,10 @@ enabling hardware LPM, the host can automatically put the device into lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices), which state device can enter and resume very quickly. -The user interface for controlling USB2 hardware LPM is located in the +The user interface for controlling hardware LPM is located in the power/ subdirectory of each USB device's sysfs directory, that is, in /sys/bus/usb/devices/.../power/ where "..." is the device's ID. The -relevant attribute files is usb2_hardware_lpm. +relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm. power/usb2_hardware_lpm @@ -537,6 +537,17 @@ relevant attribute files is usb2_hardware_lpm. can write y/Y/1 or n/N/0 to the file to enable/disable USB2 hardware LPM manually. This is for test purpose mainly. + power/usb3_hardware_lpm + + When a USB 3.0 lpm-capable device is plugged in to a + xHCI host which supports link PM, it will check if U1 + and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host + supports USB3 hardware LPM, USB3 hardware LPM will be + enabled for the device and this file will be created. + The file holds a string value (enable or disable) + indicating whether or not USB3 hardware LPM is + enabled for the device. USB Port Power Control ---------------------- diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 43cb2f2e3b43..d9ce8f9d9acc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3950,6 +3950,8 @@ int usb_disable_lpm(struct usb_device *udev) if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) goto enable_lpm; + udev->usb3_lpm_enabled = 0; + return 0; enable_lpm: @@ -4007,6 +4009,8 @@ void usb_enable_lpm(struct usb_device *udev) usb_enable_link_state(hcd, udev, USB3_LPM_U1); usb_enable_link_state(hcd, udev, USB3_LPM_U2); + + udev->usb3_lpm_enabled = 1; } EXPORT_SYMBOL_GPL(usb_enable_lpm); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d26973844a4d..cfc68c11c3f5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -531,6 +531,25 @@ static ssize_t usb2_lpm_besl_store(struct device *dev, } static DEVICE_ATTR_RW(usb2_lpm_besl); +static ssize_t usb3_hardware_lpm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm); + static struct attribute *usb2_hardware_lpm_attr[] = { &dev_attr_usb2_hardware_lpm.attr, &dev_attr_usb2_lpm_l1_timeout.attr, @@ -542,6 +561,15 @@ static struct attribute_group usb2_hardware_lpm_attr_group = { .attrs = usb2_hardware_lpm_attr, }; +static struct attribute *usb3_hardware_lpm_attr[] = { + &dev_attr_usb3_hardware_lpm.attr, + NULL, +}; +static struct attribute_group usb3_hardware_lpm_attr_group = { + .name = power_group_name, + .attrs = usb3_hardware_lpm_attr, +}; + static struct attribute *power_attrs[] = { &dev_attr_autosuspend.attr, &dev_attr_level.attr, @@ -564,6 +592,9 @@ static int add_power_attributes(struct device *dev) if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); + if (udev->lpm_capable == 1) + rc = sysfs_merge_group(&dev->kobj, + &usb3_hardware_lpm_attr_group); } return rc; -- cgit v1.2.3-59-g8ed1b From 2ce7918990641b07e70e1b25752d666369e2016e Mon Sep 17 00:00:00 2001 From: Andrey Smetanin Date: Fri, 3 Jul 2015 15:01:41 +0300 Subject: kvm/x86: add sending hyper-v crash notification to user space Sending of notification is done by exiting vcpu to user space if KVM_REQ_HV_CRASH is enabled for vcpu. At exit to user space the kvm_run structure contains system_event with type KVM_SYSTEM_EVENT_CRASH to notify about guest crash occurred. Signed-off-by: Andrey Smetanin Signed-off-by: Denis V. Lunev Reviewed-by: Peter Hornyack CC: Paolo Bonzini CC: Gleb Natapov Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 5 +++++ arch/x86/kvm/x86.c | 6 ++++++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + 4 files changed, 13 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a7926a90156f..a4ebcb712375 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3277,6 +3277,7 @@ should put the acknowledged interrupt vector into the 'epr' field. struct { #define KVM_SYSTEM_EVENT_SHUTDOWN 1 #define KVM_SYSTEM_EVENT_RESET 2 +#define KVM_SYSTEM_EVENT_CRASH 3 __u32 type; __u64 flags; } system_event; @@ -3296,6 +3297,10 @@ Valid values for 'type' are: KVM_SYSTEM_EVENT_RESET -- the guest has requested a reset of the VM. As with SHUTDOWN, userspace can choose to ignore the request, or to schedule the reset to occur in the future and may call KVM_RUN again. + KVM_SYSTEM_EVENT_CRASH -- the guest crash occurred and the guest + has requested a crash condition maintenance. Userspace can choose + to ignore the request, or to gather VM memory core dump and/or + reset/shutdown of the VM. /* Fix the size of the union. */ char padding[256]; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cfa3e5a7d6be..28076c266a9a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6263,6 +6263,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) vcpu_scan_ioapic(vcpu); if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu)) kvm_vcpu_reload_apic_access_page(vcpu); + if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) { + vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; + vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH; + r = 0; + goto out; + } } if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) { diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1d917d9b7f12..51103f0feb7e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -139,6 +139,7 @@ static inline bool is_error_page(struct page *page) #define KVM_REQ_DISABLE_IBS 24 #define KVM_REQ_APIC_PAGE_RELOAD 25 #define KVM_REQ_SMI 26 +#define KVM_REQ_HV_CRASH 27 #define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 716ad4ae4d4b..9ef19ebd9df4 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -317,6 +317,7 @@ struct kvm_run { struct { #define KVM_SYSTEM_EVENT_SHUTDOWN 1 #define KVM_SYSTEM_EVENT_RESET 2 +#define KVM_SYSTEM_EVENT_CRASH 3 __u32 type; __u64 flags; } system_event; -- cgit v1.2.3-59-g8ed1b From afc257bc9ac9c2f9055c9f9829322b3ff7574165 Mon Sep 17 00:00:00 2001 From: Mars Cheng Date: Tue, 14 Jul 2015 14:58:12 +0800 Subject: Document: DT: Add bindings for mediatek MT6795 SoC Platform This adds DT binding documentation for Mediatek MT6795. Signed-off-by: Mars Cheng Signed-off-by: Matthias Brugger --- Documentation/devicetree/bindings/arm/mediatek.txt | 9 +++++++-- .../devicetree/bindings/arm/mediatek/mediatek,sysirq.txt | 3 ++- Documentation/devicetree/bindings/serial/mtk-uart.txt | 5 +++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt index dd7550a29db6..ce26ff7aa9b0 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.txt +++ b/Documentation/devicetree/bindings/arm/mediatek.txt @@ -1,12 +1,14 @@ -MediaTek mt65xx & mt81xx Platforms Device Tree Bindings +MediaTek mt65xx, mt67xx & mt81xx Platforms Device Tree Bindings -Boards with a MediaTek mt65xx/mt81xx SoC shall have the following property: +Boards with a MediaTek mt65xx/mt67xx/mt81xx SoC shall have the +following property: Required root node property: compatible: Must contain one of "mediatek,mt6589" "mediatek,mt6592" + "mediatek,mt6795" "mediatek,mt8127" "mediatek,mt8135" "mediatek,mt8173" @@ -20,6 +22,9 @@ Supported boards: - Evaluation board for MT6592: Required root node properties: - compatible = "mediatek,mt6592-evb", "mediatek,mt6592"; +- Evaluation board for MT6795(Helio X10): + Required root node properties: + - compatible = "mediatek,mt6795-evb", "mediatek,mt6795"; - MTK mt8127 tablet moose EVB: Required root node properties: - compatible = "mediatek,mt8127-moose", "mediatek,mt8127"; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt index 4f5a5352ccd8..8136b6d44871 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt @@ -1,4 +1,4 @@ -Mediatek 65xx/81xx sysirq ++Mediatek 65xx/67xx/81xx sysirq Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI interrupt. @@ -8,6 +8,7 @@ Required properties: "mediatek,mt8173-sysirq" "mediatek,mt8135-sysirq" "mediatek,mt8127-sysirq" + "mediatek,mt6795-sysirq" "mediatek,mt6592-sysirq" "mediatek,mt6589-sysirq" "mediatek,mt6582-sysirq" diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index 8d63f1da07aa..5991511fa7ee 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -5,10 +5,11 @@ Required properties: * "mediatek,mt8135-uart" for MT8135 compatible UARTS * "mediatek,mt8127-uart" for MT8127 compatible UARTS * "mediatek,mt8173-uart" for MT8173 compatible UARTS + * "mediatek,mt6795-uart" for MT6795 compatible UARTS * "mediatek,mt6589-uart" for MT6589 compatible UARTS * "mediatek,mt6582-uart" for MT6582 compatible UARTS - * "mediatek,mt6577-uart" for all compatible UARTS (MT8173, MT6589, MT6582, - MT6577) + * "mediatek,mt6577-uart" for all compatible UARTS (MT8173, MT6795, MT6589, + MT6582, MT6577) - reg: The base address of the UART register bank. -- cgit v1.2.3-59-g8ed1b From ddc05fa286068a2d0cf87a47739b155806d46670 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:44 +0200 Subject: iio: st-accel: add support for lsm303agr accelerometer This adds support for the lsm303agr accelerometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 1 + drivers/iio/accel/st_accel_i2c.c | 5 +++++ drivers/iio/accel/st_accel_spi.c | 1 + 5 files changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index 8a6be3bdf267..d80bdaa75754 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -35,6 +35,7 @@ Accelerometers: - st,lsm303dl-accel - st,lsm303dlm-accel - st,lsm330-accel +- st,lsm303agr-accel Gyroscopes: - st,l3g4200d-gyro diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index aa1001931d0c..468f21fa2950 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -26,6 +26,7 @@ #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" #define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel" #define LSM330_ACCEL_DEV_NAME "lsm330_accel" +#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 12b42f6e70ab..ff30f8806880 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -233,6 +233,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { [2] = LSM330D_ACCEL_DEV_NAME, [3] = LSM330DL_ACCEL_DEV_NAME, [4] = LSM330DLC_ACCEL_DEV_NAME, + [5] = LSM303AGR_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index a2f1c20319eb..8b9cc84fd44f 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm330-accel", .data = LSM330_ACCEL_DEV_NAME, }, + { + .compatible = "st,lsm303agr-accel", + .data = LSM303AGR_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 12ec29389e4b..54b61a3961c3 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); -- cgit v1.2.3-59-g8ed1b From 1e9676a8474b657b6a793f0abff2205783a1ce6f Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:45 +0200 Subject: iio: st-magn: add support for lsm303agr magnetometer This adds support for the lsm303agr magnetometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/magnetometer/st_magn.h | 1 + drivers/iio/magnetometer/st_magn_core.c | 82 ++++++++++++++++++++++ drivers/iio/magnetometer/st_magn_i2c.c | 5 ++ drivers/iio/magnetometer/st_magn_spi.c | 1 + 5 files changed, 90 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index d80bdaa75754..d3ccdb190c53 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -47,6 +47,7 @@ Gyroscopes: - st,lsm330-gyro Magnetometers: +- st,lsm303agr-magn - st,lsm303dlh-magn - st,lsm303dlhc-magn - st,lsm303dlm-magn diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 604410236d99..06a4d9c35581 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -18,6 +18,7 @@ #define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn" #define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn" #define LIS3MDL_MAGN_DEV_NAME "lis3mdl" +#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn" int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 4c0cef865517..f8dc4b85d70c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -43,6 +43,7 @@ #define ST_MAGN_FS_AVL_8000MG 8000 #define ST_MAGN_FS_AVL_8100MG 8100 #define ST_MAGN_FS_AVL_12000MG 12000 +#define ST_MAGN_FS_AVL_15000MG 15000 #define ST_MAGN_FS_AVL_16000MG 16000 /* CUSTOM VALUES FOR SENSOR 0 */ @@ -157,6 +158,29 @@ #define ST_MAGN_2_OUT_Y_L_ADDR 0x2a #define ST_MAGN_2_OUT_Z_L_ADDR 0x2c +/* CUSTOM VALUES FOR SENSOR 3 */ +#define ST_MAGN_3_WAI_ADDR 0x4f +#define ST_MAGN_3_WAI_EXP 0x40 +#define ST_MAGN_3_ODR_ADDR 0x60 +#define ST_MAGN_3_ODR_MASK 0x0c +#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00 +#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01 +#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02 +#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03 +#define ST_MAGN_3_PW_ADDR 0x60 +#define ST_MAGN_3_PW_MASK 0x03 +#define ST_MAGN_3_PW_ON 0x00 +#define ST_MAGN_3_PW_OFF 0x03 +#define ST_MAGN_3_BDU_ADDR 0x62 +#define ST_MAGN_3_BDU_MASK 0x10 +#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62 +#define ST_MAGN_3_DRDY_INT_MASK 0x01 +#define ST_MAGN_3_FS_AVL_15000_GAIN 1500 +#define ST_MAGN_3_MULTIREAD_BIT false +#define ST_MAGN_3_OUT_X_L_ADDR 0x68 +#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a +#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c + static const struct iio_chan_spec st_magn_16bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -189,6 +213,22 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3) }; +static const struct iio_chan_spec st_magn_3_16bit_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Z_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(3) +}; + static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ @@ -402,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_MAGN_3_WAI_EXP, + .wai_addr = ST_MAGN_3_WAI_ADDR, + .sensors_supported = { + [0] = LSM303AGR_MAGN_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels, + .odr = { + .addr = ST_MAGN_3_ODR_ADDR, + .mask = ST_MAGN_3_ODR_MASK, + .odr_avl = { + { 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, }, + { 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, }, + { 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, }, + { 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_MAGN_3_PW_ADDR, + .mask = ST_MAGN_3_PW_MASK, + .value_on = ST_MAGN_3_PW_ON, + .value_off = ST_MAGN_3_PW_OFF, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_15000MG, + .gain = ST_MAGN_3_FS_AVL_15000_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_MAGN_3_BDU_ADDR, + .mask = ST_MAGN_3_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_MAGN_3_DRDY_IRQ_ADDR, + .mask_int1 = ST_MAGN_3_DRDY_INT_MASK, + }, + .multi_read_bit = ST_MAGN_3_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_magn_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 28aa80731cea..8aa37af306ed 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lis3mdl-magn", .data = LIS3MDL_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303agr-magn", + .data = LSM303AGR_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 7adacf160146..0abca2c6afa6 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); -- cgit v1.2.3-59-g8ed1b From 13517157d16f98564b91658940ccd720724da62f Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Thu, 23 Jul 2015 18:50:49 +0200 Subject: ARM: dts: rockchip: Add veyron-speedy board Which is formally known as the Asus C201 chromebook Signed-off-by: Romain Perier Reviewed-by: Doug Anderson Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.txt | 8 ++ arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/rk3288-veyron-speedy.dts | 155 +++++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/rk3288-veyron-speedy.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index c7769400ef85..c7411cc53533 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -43,6 +43,14 @@ Rockchip platforms device tree bindings - compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", "google,veyron", "rockchip,rk3288"; +- Google Speedy (Asus C201 Chromebook): + Required root node properties: + - compatible = "google,veyron-speedy-rev9", "google,veyron-speedy-rev8", + "google,veyron-speedy-rev7", "google,veyron-speedy-rev6", + "google,veyron-speedy-rev5", "google,veyron-speedy-rev4", + "google,veyron-speedy-rev3", "google,veyron-speedy-rev2", + "google,veyron-speedy", "google,veyron", "rockchip,rk3288"; + - Rockchip R88 board: Required root node properties: - compatible = "rockchip,r88", "rockchip,rk3368"; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index ce7e1a821a23..7017d8e3f4f5 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -491,7 +491,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-firefly.dtb \ rk3288-r89.dtb \ rk3288-veyron-jerry.dtb \ - rk3288-veyron-pinky.dtb + rk3288-veyron-pinky.dtb \ + rk3288-veyron-speedy.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts new file mode 100644 index 000000000000..a7ea7d06cf7f --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts @@ -0,0 +1,155 @@ +/* + * Google Veyron Speedy Rev 1+ board device tree source + * + * Copyright 2015 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3288-veyron-chromebook.dtsi" +#include "cros-ec-sbs.dtsi" + +/ { + model = "Google Speedy"; + compatible = "google,veyron-speedy-rev9", "google,veyron-speedy-rev8", + "google,veyron-speedy-rev7", "google,veyron-speedy-rev6", + "google,veyron-speedy-rev5", "google,veyron-speedy-rev4", + "google,veyron-speedy-rev3", "google,veyron-speedy-rev2", + "google,veyron-speedy", "google,veyron", "rockchip,rk3288"; + + panel_regulator: panel-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_h>; + regulator-name = "panel_regulator"; + vin-supply = <&vcc33_sys>; + }; + + vcc18_lcd: vcc18-lcd { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&avdd_1v8_disp_en>; + regulator-name = "vcc18_lcd"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc18_wl>; + }; + + backlight_regulator: backlight-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_pwr_en>; + regulator-name = "backlight_regulator"; + vin-supply = <&vcc33_sys>; + startup-delay-us = <15000>; + }; +}; + +&rk808 { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; +}; + +&sdmmc { + disable-wp; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio + &sdmmc_bus4>; +}; + +&vcc_5v { + enable-active-high; + gpio = <&gpio7 21 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&drv_5v>; +}; + +&vcc50_hdmi { + enable-active-high; + gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc50_hdmi_en>; +}; + +&pinctrl { + backlight { + bl_pwr_en: bl_pwr_en { + rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + buck-5v { + drv_5v: drv-5v { + rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hdmi { + vcc50_hdmi_en: vcc50-hdmi-en { + rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lcd { + lcd_enable_h: lcd-en { + rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + avdd_1v8_disp_en: avdd-1v8-disp-en { + rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + dvs_1: dvs-1 { + rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + dvs_2: dvs-2 { + rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From d879aeaa416fea126081452e811c1d225fd25b00 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:04 +0530 Subject: Documentation: DT: omap_serial: document missing compatible The compatible "ti,am4372-uart" is used in arch/arm/boot/dts/am4372.dtsi but not documented. Add necessary documentation. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/omap_serial.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index 54c2a155c783..d3bd2b1ec401 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -4,6 +4,7 @@ Required properties: - compatible : should be "ti,omap2-uart" for OMAP2 controllers - compatible : should be "ti,omap3-uart" for OMAP3 controllers - compatible : should be "ti,omap4-uart" for OMAP4 controllers +- compatible : should be "ti,am4372-uart" for AM437x controllers - reg : address and length of the register space - interrupts or interrupts-extended : Should contain the uart interrupt specifier or both the interrupt -- cgit v1.2.3-59-g8ed1b From 4fcdff9bcabc135d72f69ed8723a14a9e514fe46 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:06 +0530 Subject: serial: 8250_omap: introduce "ti,am3352-uart" compatible property Use of of_machine_is_compatible() for handling AM335x specific "DMA kick" quirk in 8250_omap driver makes it ugly to extend the quirk for other platforms. Instead use a new compatible. The new compatible will also make it easier to take care of other quirks on AM335x and like SoCs. In order to not break backward DTB compatibility for users of 8250_omap driver on AM335x based boards, existing use of of_machine_is_compatible() has not been removed. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/omap_serial.txt | 1 + arch/arm/boot/dts/am33xx.dtsi | 12 ++++---- drivers/tty/serial/8250/8250_omap.c | 32 ++++++++++++++-------- 3 files changed, 28 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index d3bd2b1ec401..0ee88209b341 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -5,6 +5,7 @@ Required properties: - compatible : should be "ti,omap3-uart" for OMAP3 controllers - compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,am4372-uart" for AM437x controllers +- compatible : should be "ti,am3352-uart" for AM335x controllers - reg : address and length of the register space - interrupts or interrupts-extended : Should contain the uart interrupt specifier or both the interrupt diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 21fcc440fc1a..b76f9a2ce05d 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -210,7 +210,7 @@ }; uart0: serial@44e09000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>; reg = <0x44e09000 0x2000>; @@ -221,7 +221,7 @@ }; uart1: serial@48022000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart2"; clock-frequency = <48000000>; reg = <0x48022000 0x2000>; @@ -232,7 +232,7 @@ }; uart2: serial@48024000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart3"; clock-frequency = <48000000>; reg = <0x48024000 0x2000>; @@ -243,7 +243,7 @@ }; uart3: serial@481a6000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart4"; clock-frequency = <48000000>; reg = <0x481a6000 0x2000>; @@ -252,7 +252,7 @@ }; uart4: serial@481a8000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart5"; clock-frequency = <48000000>; reg = <0x481a8000 0x2000>; @@ -261,7 +261,7 @@ }; uart5: serial@481aa000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart6"; clock-frequency = <48000000>; reg = <0x481aa000 0x2000>; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index d9c96b993a84..fff026f3d0bb 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -537,14 +538,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, switch (revision) { case OMAP_UART_REV_46: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS; + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS; break; case OMAP_UART_REV_52: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; case OMAP_UART_REV_63: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; default: @@ -1061,6 +1062,17 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 am3352_habit = OMAP_DMA_TX_KICK; + +static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap8250_dt_ids); + static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1125,11 +1137,17 @@ static int omap8250_probe(struct platform_device *pdev) up.port.unthrottle = omap_8250_unthrottle; if (pdev->dev.of_node) { + const struct of_device_id *id; + ret = of_alias_get_id(pdev->dev.of_node, "serial"); of_property_read_u32(pdev->dev.of_node, "clock-frequency", &up.port.uartclk); priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); + + id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); + if (id && id->data) + priv->habit |= *(u8 *)id->data; } else { ret = pdev->id; } @@ -1374,14 +1392,6 @@ static const struct dev_pm_ops omap8250_dev_pm_ops = { .complete = omap8250_complete, }; -static const struct of_device_id omap8250_dt_ids[] = { - { .compatible = "ti,omap2-uart" }, - { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap8250_dt_ids); - static struct platform_driver omap8250_platform_driver = { .driver = { .name = "omap8250", -- cgit v1.2.3-59-g8ed1b From 27c93af7e7d9ccdfa28e26767c09106bf0721998 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:08 +0530 Subject: serial: 8250_omap: workaround module disable errata on dra7x SoCs Due to Advisory 21 as documented in AM437x errata document, UART module cannot be disabled once DMA is used. The only workaround is to softreset the module before disabling it. DRA7x UARTs are compatible to AM437x UARTs in terms of this errata and prescribed workaround. Enable usage of workaround for this errata on DRA7x SoCs. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/omap_serial.txt | 1 + drivers/tty/serial/8250/8250_omap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index 0ee88209b341..7a71b5de77d6 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -6,6 +6,7 @@ Required properties: - compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,am4372-uart" for AM437x controllers - compatible : should be "ti,am3352-uart" for AM335x controllers +- compatible : should be "ti,dra742-uart" for DRA7x controllers - reg : address and length of the register space - interrupts or interrupts-extended : Should contain the uart interrupt specifier or both the interrupt diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index a2ee75dee070..d9a37191a1ae 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1082,6 +1082,7 @@ static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap4-uart" }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am4372_habit, }, + { .compatible = "ti,dra742-uart", .data = &am4372_habit, }, {}, }; MODULE_DEVICE_TABLE(of, omap8250_dt_ids); -- cgit v1.2.3-59-g8ed1b From 05a051436bdf37e121a627baca605977cd6d0730 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:09 +0200 Subject: ARM: at91/dt: add a new DT property to support FIFOs on Atmel USARTs This patch adds a new DT property, "atmel,fifo-size", to enable and set the maximum number of data the RX and TX FIFOs can store on FIFO capable USARTs. Please be aware that the VERSION register can not be used to guess the size of FIFOs. Indeed, for a given hardware version, the USARTs can be integrated on Atmel SoCs with different FIFO sizes. Also the "atmel,fifo-size" property is optional as older USARTs don't embed FIFO at all. Besides, the FIFO size can not be read or guessed from other registers: When designing the FIFO feature, no dedicated registers were added to store this size. Unsed spaces in the I/O register range are limited and better reserved for future usages. Instead, the FIFO size of each peripheral is documented in the programmer datasheet. Finally, on a given SoC, there can be several instances of USART with different FIFO sizes. This explain why we'd rather use a dedicated DT property than use the "compatible" property. Signed-off-by: Cyrille Pitchen Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/atmel-usart.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt index 90787aa2e648..e6e6142e33ac 100644 --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt +++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt @@ -22,6 +22,8 @@ Optional properties: memory peripheral interface and USART DMA channel ID, FIFO configuration. Refer to dma.txt and atmel-dma.txt for details. - dma-names: "rx" for RX channel, "tx" for TX channel. +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable USARTs. compatible description: - at91rm9200: legacy USART support @@ -57,4 +59,5 @@ Example: dmas = <&dma0 2 0x3>, <&dma0 2 0x204>; dma-names = "tx", "rx"; + atmel,fifo-size = <32>; }; -- cgit v1.2.3-59-g8ed1b From 678cdb2fbd7e44b8905a8f4e770c694eb77f0395 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 24 Jul 2015 13:24:40 +0800 Subject: regulator: mt6311: Add document for mt6311 regulator This patch adds a list of supported regulator names to the devicetree binding documentation for Mediatek MT6311 PMIC. Signed-off-by: Henry Chen Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- .../bindings/regulator/mt6311-regulator.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mt6311-regulator.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt new file mode 100644 index 000000000000..02649d8b3f5a --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt @@ -0,0 +1,35 @@ +Mediatek MT6311 Regulator Driver + +Required properties: +- compatible: "mediatek,mt6311-regulator" +- reg: I2C slave address, usually 0x6b. +- regulators: List of regulators provided by this controller. It is named + to VDVFS and VBIASN. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + VDVFS +LDO: + VBIASN + +Example: + mt6311: pmic@6b { + compatible = "mediatek,mt6311-regulator"; + reg = <0x6b>; + + regulators { + mt6311_vcpu_reg: VDVFS { + regulator-name = "VDVFS"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <10000>; + }; + mt6311_ldo_reg: VBIASN { + regulator-name = "VBIASN"; + regulator-min-microvolt = <200000>; + regulator-max-microvolt = <800000>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From a10726bb5472ff2ed95180cfb5e82091c45d7b19 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 14 Jul 2015 07:35:11 +0200 Subject: Documentation: mm: fix location of extfrag_index /proc/extfrag_index does not exist. This file is in debugfs. Fix the description of extfrag_threshold to reflect this. Signed-off-by: Rabin Vincent Signed-off-by: Jonathan Corbet --- Documentation/sysctl/vm.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 9832ec52f859..9c3f2f8054b5 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -225,11 +225,11 @@ with your system. To disable them, echo 4 (bit 3) into drop_caches. extfrag_threshold This parameter affects whether the kernel will compact memory or direct -reclaim to satisfy a high-order allocation. /proc/extfrag_index shows what -the fragmentation index for each order is in each zone in the system. Values -tending towards 0 imply allocations would fail due to lack of memory, -values towards 1000 imply failures are due to fragmentation and -1 implies -that the allocation will succeed as long as watermarks are met. +reclaim to satisfy a high-order allocation. The extfrag/extfrag_index file in +debugfs shows what the fragmentation index for each order is in each zone in +the system. Values tending towards 0 imply allocations would fail due to lack +of memory, values towards 1000 imply failures are due to fragmentation and -1 +implies that the allocation will succeed as long as watermarks are met. The kernel will not compact memory in a zone if the fragmentation index is <= extfrag_threshold. The default value is 500. -- cgit v1.2.3-59-g8ed1b From 9e1aa7c8882050577c9223ba85c4ee49cd1da469 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Thu, 16 Jul 2015 06:31:16 +0000 Subject: Documentation: Update filesystems/debugfs.txt This patch update the Documentation/filesystems/debugfs.txt file. The main work is to add the description of the following functions: debugfs_create_atomic_t debugfs_create_u32_array debugfs_create_devm_seqfile debugfs_create_file_size Signed-off-by: Wang Long Signed-off-by: Jonathan Corbet --- Documentation/filesystems/debugfs.txt | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index 88ab81c79109..463f595733e8 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt @@ -51,6 +51,17 @@ operations should be provided; others can be included as needed. Again, the return value will be a dentry pointer to the created file, NULL for error, or ERR_PTR(-ENODEV) if debugfs support is missing. +Create a file with an initial size, the following function can be used +instead: + + struct dentry *debugfs_create_file_size(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops, + loff_t file_size); + +file_size is the initial file size. The other parameters are the same +as the function debugfs_create_file. + In a number of cases, the creation of a set of file operations is not actually necessary; the debugfs code provides a number of helper functions for simple situations. Files containing a single integer value can be @@ -100,6 +111,14 @@ A read on the resulting file will yield either Y (for non-zero values) or N, followed by a newline. If written to, it will accept either upper- or lower-case values, or 1 or 0. Any other input will be silently ignored. +Also, atomic_t values can be placed in debugfs with: + + struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, + struct dentry *parent, atomic_t *value) + +A read of this file will get atomic_t values, and a write of this file +will set atomic_t values. + Another option is exporting a block of arbitrary binary data, with this structure and function: @@ -147,6 +166,27 @@ The "base" argument may be 0, but you may want to build the reg32 array using __stringify, and a number of register names (macros) are actually byte offsets over a base for the register block. +If you want to dump an u32 array in debugfs, you can create file with: + + struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, + struct dentry *parent, + u32 *array, u32 elements); + +The "array" argument provides data, and the "elements" argument is +the number of elements in the array. Note: Once array is created its +size can not be changed. + +There is a helper function to create device related seq_file: + + struct dentry *debugfs_create_devm_seqfile(struct device *dev, + const char *name, + struct dentry *parent, + int (*read_fn)(struct seq_file *s, + void *data)); + +The "dev" argument is the device related to this debugfs file, and +the "read_fn" is a function pointer which to be called to print the +seq_file content. There are a couple of other directory-oriented helper functions: -- cgit v1.2.3-59-g8ed1b From b9f2f4594c77073ca306ef345e9f9c1cde292dd3 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 17 Jul 2015 12:23:01 +0200 Subject: Documentation: Add MCB documentation Add basic introductory documentation for the MEN Chameleon Bus. Signed-off-by: Johannes Thumshirn Signed-off-by: Jonathan Corbet --- Documentation/men-chameleon-bus.txt | 162 ++++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 163 insertions(+) create mode 100644 Documentation/men-chameleon-bus.txt (limited to 'Documentation') diff --git a/Documentation/men-chameleon-bus.txt b/Documentation/men-chameleon-bus.txt new file mode 100644 index 000000000000..6d7bdb5d7f12 --- /dev/null +++ b/Documentation/men-chameleon-bus.txt @@ -0,0 +1,162 @@ + MEN Chameleon Bus + ================= + +Table of Contents +================= +1 Introduction + 1.1 Scope of this Document + 1.2 Limitations of the current implementation +2 Architecture + 2.1 MEN Chameleon Bus + 2.2 Carrier Devices + 2.3 Parser +3 Resource handling + 3.1 Memory Resources + 3.2 IRQs +4 Writing a MCB driver + 4.1 The driver structure + 4.2 Probing and attaching + 4.3 Initializing the driver + + +1 Introduction +=============== + This document describes the architecture and implementation of the MEN + Chameleon Bus (called MCB throughout this document). + +1.1 Scope of this Document +--------------------------- + This document is intended to be a short overview of the current + implementation and does by no means describe to complete possibilities of MCB + based devices. + +1.2 Limitations of the current implementation +---------------------------------------------- + The current implementation is limited to PCI and PCIe based carrier devices + that only use a single memory resource and share the PCI legacy IRQ. Not + implemented are: + - Multi-resource MCB devices like the VME Controller or M-Module carrier. + - MCB devices that need another MCB device, like SRAM for a DMA Controller's + buffer descriptors or a video controller's video memory. + - A per-carrier IRQ domain for carrier devices that have one (or more) IRQs + per MCB device like PCIe based carriers with MSI or MSI-X support. + +2 Architecture +=============== + MCB is divided in 3 functional blocks: + - The MEN Chameleon Bus itself, + - drivers for MCB Carrier Devices and + - the parser for the Chameleon table. + +2.1 MEN Chameleon Bus +---------------------- + The MEN Chameleon Bus is an artificial bus system that attaches to an MEN + Chameleon FPGA device. These devices are multi-function devices implemented + in a single FPGA and usually attached via some sort of PCI or PCIe link. Each + FPGA contains a header section describing the content of the FPGA. The header + lists the device id, PCI BAR, offset from the beginning of the PCI BAR, size + in the FPGA, interrupt number and some other properties currently not handled + by the MCB implementation. + +2.2 Carrier Devices +-------------------- + A carrier device is just an abstraction for the real world physical bus the + chameleon FPGA is attached to. Some IP Core drivers may need to interact with + properties of the carrier device (like querying the IRQ number of a PCI + device). To provide abstraction from the real hardware bus, an MCB carrier + device provides callback methods to translate the driver's MCB function calls + to hardware related function calls. For example a carrier device may + implement the get_irq() method which can be translate into a hardware bus + query for the IRQ number the device should use. + +2.3 Parser +----------- + The parser reads the 1st 512 bytes of a chameleon device and parses the + chameleon table. Currently the parser only supports the Chameleon v2 variant + of the chameleon table but can easily be adopted to support an older or + possible future variant. While parsing the table's entries new MCB devices + are allocated and their resources are assigned according to the resource + assignment in the chameleon table. After resource assignment is finished, the + MCB devices are registered at the MCB and thus at the driver core of the + Linux kernel. + +3 Resource handling +==================== + The current implementation assigns exactly one memory and one IRQ resource + per MCB device. But this is likely going to change in the future. + +3.1 Memory Resources +--------------------- + Each MCB device has exactly one memory resource, which can be requested from + the MCB bus. This memory resource is the physical address of the MCB device + inside the carrier and is intended to be passed to ioremap() and friends. It + is already requested from the kernel by calling request_mem_region(). + +3.2 IRQs +--------- + Each MCB device has exactly one IRQ resource, which can be requested from the + MCB bus. If a carrier device driver implements the ->get_irq() callback + method, the IRQ number assigned by the carrier device will be returned, + otherwise the IRQ number inside the chameleon table will be returned. This + number is suitable to be passed to request_irq(). + +4 Writing a MCB driver +======================= + +4.1 The driver structure +------------------------- + Each MCB driver has a structure to identify the device driver as well as + device ids which identify the IP Core inside the FPGA. The driver structure + also contaings callback methods which get executed on driver probe and + removal from the system. + + + static const struct mcb_device_id foo_ids[] = { + { .device = 0x123 }, + { } + }; + MODULE_DEVICE_TABLE(mcb, foo_ids); + + static struct mcb_driver foo_driver = { + driver = { + .name = "foo-bar", + .owner = THIS_MODULE, + }, + .probe = foo_probe, + .remove = foo_remove, + .id_table = foo_ids, + }; + +4.2 Probing and attaching +-------------------------- + When a driver is loaded and the MCB devices it services are found, the MCB + core will call the driver's probe callback method. When the driver is removed + from the system, the MCB core will call the driver's remove callback method. + + + static init foo_probe(struct mcb_device *mdev, const struct mcb_device_id *id); + static void foo_remove(struct mcb_device *mdev); + +4.3 Initializing the driver +---------------------------- + When the kernel is booted or your foo driver module is inserted, you have to + perform driver initialization. Usually it is enough to register your driver + module at the MCB core. + + + static int __init foo_init(void) + { + return mcb_register_driver(&foo_driver); + } + module_init(foo_init); + + static void __exit foo_exit(void) + { + mcb_unregister_driver(&foo_driver); + } + module_exit(foo_exit); + + The module_mcb_driver() macro can be used to reduce the above code. + + + module_mcb_driver(foo_driver); diff --git a/MAINTAINERS b/MAINTAINERS index 8133cefb6b6e..b9b91566380e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6665,6 +6665,7 @@ M: Johannes Thumshirn S: Maintained F: drivers/mcb/ F: include/linux/mcb.h +F: Documentation/men-chameleon-bus.txt MEN F21BMC (Board Management Controller) M: Andreas Werner -- cgit v1.2.3-59-g8ed1b From 3d5583cc82e9d505e4b9a37615f7a28c7ea465b9 Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Abd EL Mawgood Date: Thu, 16 Jul 2015 23:17:36 +0200 Subject: fix Evolution submenu name in email-clients.txt I have noticed that there is no submenu in Evolution called Heading instead there is Paragraph style Signed-off-by: Ahmed Mohamed Signed-off-by: Jonathan Corbet --- Documentation/email-clients.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt index c7d49b885559..3fa450881ecb 100644 --- a/Documentation/email-clients.txt +++ b/Documentation/email-clients.txt @@ -93,7 +93,7 @@ Evolution (GUI) Some people use this successfully for patches. When composing mail select: Preformat - from Format->Heading->Preformatted (Ctrl-7) + from Format->Paragraph Style->Preformatted (Ctrl-7) or the toolbar Then use: -- cgit v1.2.3-59-g8ed1b From fce96568f314d0fb72f5ca4bba2f64e7164a7817 Mon Sep 17 00:00:00 2001 From: Jim Davis Date: Thu, 16 Jul 2015 12:50:50 -0700 Subject: Documentation: installed man pages don't need to be executable Install the man pages with mode 644 instead of 755 Signed-off-by: Jim Davis Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b6a6a2e0dd3b..170042a1ea5f 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -60,7 +60,7 @@ mandocs: $(MAN) installmandocs: mandocs mkdir -p /usr/local/man/man9/ - install $(obj)/man/*.9.gz /usr/local/man/man9/ + install -m 644 $(obj)/man/*.9.gz /usr/local/man/man9/ ### #External programs used -- cgit v1.2.3-59-g8ed1b From 013542caa898289f37695bea849f1e368254ec8b Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Sat, 18 Jul 2015 14:31:40 +0200 Subject: Doc: fix trivial typo in SubmittingPatches This patch changes the tense of a verb in SubmittingPatches to ensure grammatical validity of the containing sentence. Signed-off-by: Benjamin Herr Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 56ef2e6f79c2..80b9f54f87ef 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -90,7 +90,7 @@ patch. Make sure your patch does not include any extra files which do not belong in a patch submission. Make sure to review your patch -after- -generated it with diff(1), to ensure accuracy. +generating it with diff(1), to ensure accuracy. If your changes produce a lot of deltas, you need to split them into individual patches which modify things in logical stages; see section -- cgit v1.2.3-59-g8ed1b From 7c97211b61d8b91b8f88237e4bbb3a8959ecb18a Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 23 Jul 2015 11:17:26 +0200 Subject: Documentation: Minor changes to men-chameleon-bus.txt Change men-chameleon-bus.txt according to the comments made by Randy Dunlap in https://lkml.org/lkml/2015/7/17/691. These are: * Some minor gramatical changes * Spelling fixes * Write the word "Chameleon" capitalized throughout the whole document * Explain MEN as MEN Mikro Elektronik GmbH. Signed-off-by: Johannes Thumshirn Signed-off-by: Jonathan Corbet --- Documentation/men-chameleon-bus.txt | 39 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/men-chameleon-bus.txt b/Documentation/men-chameleon-bus.txt index 6d7bdb5d7f12..30ded732027e 100644 --- a/Documentation/men-chameleon-bus.txt +++ b/Documentation/men-chameleon-bus.txt @@ -13,7 +13,7 @@ Table of Contents 3 Resource handling 3.1 Memory Resources 3.2 IRQs -4 Writing a MCB driver +4 Writing an MCB driver 4.1 The driver structure 4.2 Probing and attaching 4.3 Initializing the driver @@ -27,7 +27,7 @@ Table of Contents 1.1 Scope of this Document --------------------------- This document is intended to be a short overview of the current - implementation and does by no means describe to complete possibilities of MCB + implementation and does by no means describe the complete possibilities of MCB based devices. 1.2 Limitations of the current implementation @@ -43,40 +43,41 @@ Table of Contents 2 Architecture =============== - MCB is divided in 3 functional blocks: + MCB is divided into 3 functional blocks: - The MEN Chameleon Bus itself, - drivers for MCB Carrier Devices and - the parser for the Chameleon table. 2.1 MEN Chameleon Bus ---------------------- - The MEN Chameleon Bus is an artificial bus system that attaches to an MEN - Chameleon FPGA device. These devices are multi-function devices implemented - in a single FPGA and usually attached via some sort of PCI or PCIe link. Each - FPGA contains a header section describing the content of the FPGA. The header - lists the device id, PCI BAR, offset from the beginning of the PCI BAR, size - in the FPGA, interrupt number and some other properties currently not handled - by the MCB implementation. + The MEN Chameleon Bus is an artificial bus system that attaches to a so + called Chameleon FPGA device found on some hardware produced my MEN Mikro + Elektronik GmbH. These devices are multi-function devices implemented in a + single FPGA and usually attached via some sort of PCI or PCIe link. Each + FPGA contains a header section describing the content of the FPGA. The + header lists the device id, PCI BAR, offset from the beginning of the PCI + BAR, size in the FPGA, interrupt number and some other properties currently + not handled by the MCB implementation. 2.2 Carrier Devices -------------------- A carrier device is just an abstraction for the real world physical bus the - chameleon FPGA is attached to. Some IP Core drivers may need to interact with + Chameleon FPGA is attached to. Some IP Core drivers may need to interact with properties of the carrier device (like querying the IRQ number of a PCI device). To provide abstraction from the real hardware bus, an MCB carrier device provides callback methods to translate the driver's MCB function calls to hardware related function calls. For example a carrier device may - implement the get_irq() method which can be translate into a hardware bus + implement the get_irq() method which can be translated into a hardware bus query for the IRQ number the device should use. 2.3 Parser ----------- - The parser reads the 1st 512 bytes of a chameleon device and parses the - chameleon table. Currently the parser only supports the Chameleon v2 variant - of the chameleon table but can easily be adopted to support an older or + The parser reads the first 512 bytes of a Chameleon device and parses the + Chameleon table. Currently the parser only supports the Chameleon v2 variant + of the Chameleon table but can easily be adopted to support an older or possible future variant. While parsing the table's entries new MCB devices are allocated and their resources are assigned according to the resource - assignment in the chameleon table. After resource assignment is finished, the + assignment in the Chameleon table. After resource assignment is finished, the MCB devices are registered at the MCB and thus at the driver core of the Linux kernel. @@ -97,17 +98,17 @@ Table of Contents Each MCB device has exactly one IRQ resource, which can be requested from the MCB bus. If a carrier device driver implements the ->get_irq() callback method, the IRQ number assigned by the carrier device will be returned, - otherwise the IRQ number inside the chameleon table will be returned. This + otherwise the IRQ number inside the Chameleon table will be returned. This number is suitable to be passed to request_irq(). -4 Writing a MCB driver +4 Writing an MCB driver ======================= 4.1 The driver structure ------------------------- Each MCB driver has a structure to identify the device driver as well as device ids which identify the IP Core inside the FPGA. The driver structure - also contaings callback methods which get executed on driver probe and + also contains callback methods which get executed on driver probe and removal from the system. -- cgit v1.2.3-59-g8ed1b From fa466c91970a0207d9384016cc7884a7f61834b6 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 22 Jul 2015 07:32:22 -0500 Subject: spi: davinci: Choose correct pre-scaler limit based on SOC Currently the pre-scaler limit is incorrect. The value differs slightly for various devices so a single value can't be used. Using the compatible field select the correct pre-scaler limit. Add new compatible field value for Keystone devices to support their unique pre-scaler limit value. Signed-off-by: Franklin S Cooper Jr Reviewed-by: Sekhar Nori Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-davinci.txt | 2 + drivers/spi/spi-davinci.c | 43 ++++++++++++++++++---- include/linux/platform_data/spi-davinci.h | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index 12ecfe9e3599..d1e914adcf6e 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -12,6 +12,8 @@ Required properties: - compatible: - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family + - "ti,keystone-spi" for SPI used similar to that on Keystone2 SoC + family - reg: Offset and length of SPI controller register space - num-cs: Number of chip selects. This includes internal as well as GPIO chip selects. diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index b4605c4158f4..3cf9faa6cc3f 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -139,6 +139,8 @@ struct davinci_spi { u32 (*get_tx)(struct davinci_spi *); u8 *bytes_per_word; + + u8 prescaler_limit; }; static struct davinci_spi_config davinci_spi_default_cfg; @@ -266,7 +268,7 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, /* Subtract 1 to match what will be programmed into SPI register. */ ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1; - if (ret < 0 || ret > 255) + if (ret < dspi->prescaler_limit || ret > 255) return -EINVAL; return ret; @@ -833,13 +835,40 @@ rx_dma_failed: } #if defined(CONFIG_OF) + +/* OF SPI data structure */ +struct davinci_spi_of_data { + u8 version; + u8 prescaler_limit; +}; + +static const struct davinci_spi_of_data dm6441_spi_data = { + .version = SPI_VERSION_1, + .prescaler_limit = 2, +}; + +static const struct davinci_spi_of_data da830_spi_data = { + .version = SPI_VERSION_2, + .prescaler_limit = 2, +}; + +static const struct davinci_spi_of_data keystone_spi_data = { + .version = SPI_VERSION_1, + .prescaler_limit = 0, +}; + static const struct of_device_id davinci_spi_of_match[] = { { .compatible = "ti,dm6441-spi", + .data = &dm6441_spi_data, }, { .compatible = "ti,da830-spi", - .data = (void *)SPI_VERSION_2, + .data = &da830_spi_data, + }, + { + .compatible = "ti,keystone-spi", + .data = &keystone_spi_data, }, { }, }; @@ -858,21 +887,21 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi) { struct device_node *node = pdev->dev.of_node; + struct davinci_spi_of_data *spi_data; struct davinci_spi_platform_data *pdata; unsigned int num_cs, intr_line = 0; const struct of_device_id *match; pdata = &dspi->pdata; - pdata->version = SPI_VERSION_1; match = of_match_device(davinci_spi_of_match, &pdev->dev); if (!match) return -ENODEV; - /* match data has the SPI version number for SPI_VERSION_2 */ - if (match->data == (void *)SPI_VERSION_2) - pdata->version = SPI_VERSION_2; + spi_data = (struct davinci_spi_of_data *)match->data; + pdata->version = spi_data->version; + pdata->prescaler_limit = spi_data->prescaler_limit; /* * default num_cs is 1 and all chipsel are internal to the chip * indicated by chip_sel being NULL or cs_gpios being NULL or @@ -992,7 +1021,7 @@ static int davinci_spi_probe(struct platform_device *pdev) dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; - + dspi->prescaler_limit = pdata->prescaler_limit; dspi->version = pdata->version; dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; diff --git a/include/linux/platform_data/spi-davinci.h b/include/linux/platform_data/spi-davinci.h index 8dc2fa47a2aa..f4edcb03c40c 100644 --- a/include/linux/platform_data/spi-davinci.h +++ b/include/linux/platform_data/spi-davinci.h @@ -49,6 +49,7 @@ struct davinci_spi_platform_data { u8 num_chipselect; u8 intr_line; u8 *chip_sel; + u8 prescaler_limit; bool cshold_bug; enum dma_event_q dma_event_q; }; -- cgit v1.2.3-59-g8ed1b From 3a003baeec246f604ed1d2e0087560d7f15edcc6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:41:54 -0700 Subject: regulator: Add over current protection (OCP) support Some regulators can automatically shut down when they detect an over current event. Add an op (set_over_current_protection) and a DT property + constraint to support this capability. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 1 + drivers/regulator/core.c | 9 +++++++++ drivers/regulator/of_regulator.c | 3 +++ include/linux/regulator/driver.h | 1 + include/linux/regulator/machine.h | 1 + 5 files changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index db88feb28c03..24bd422cecd5 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -42,6 +42,7 @@ Optional properties: - regulator-system-load: Load in uA present on regulator that is not captured by any consumer request. - regulator-pull-down: Enable pull down resistor when the regulator is disabled. +- regulator-over-current-protection: Enable over current protection. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c9f72019bd68..520413e2bca0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1081,6 +1081,15 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->over_current_protection + && ops->set_over_current_protection) { + ret = ops->set_over_current_protection(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to set over current protection\n"); + goto out; + } + } + print_constraints(rdev); return 0; out: diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index b1c485b24ab2..250700c853bf 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -107,6 +107,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; + constraints->over_current_protection = of_property_read_bool(np, + "regulator-over-current-protection"); + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { switch (i) { case PM_SUSPEND_MEM: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4db9fbe4889d..45932228cbf5 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -148,6 +148,7 @@ struct regulator_ops { int (*get_current_limit) (struct regulator_dev *); int (*set_input_current_limit) (struct regulator_dev *, int lim_uA); + int (*set_over_current_protection) (struct regulator_dev *); /* enable/disable regulator */ int (*enable) (struct regulator_dev *); diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index b11be1260129..a1067d0b3991 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -147,6 +147,7 @@ struct regulation_constraints { unsigned ramp_disable:1; /* disable ramp delay */ unsigned soft_start:1; /* ramp voltage slowly */ unsigned pull_down:1; /* pull down resistor when regulator off */ + unsigned over_current_protection:1; /* auto disable on over current */ }; /** -- cgit v1.2.3-59-g8ed1b From e2adfacde619d8e39dc8c02919bd2524d3c39588 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:41:55 -0700 Subject: regulator: qcom-spmi: Add vendor specific configuration Add support for over current protection (OCP), pin control selection, soft start strength, and auto-mode. Cc: Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- .../bindings/regulator/qcom,spmi-regulator.txt | 60 ++++++- drivers/regulator/qcom_spmi-regulator.c | 200 ++++++++++++++++++++- 2 files changed, 251 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 75b4604bad07..d00bfd8624a5 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -91,13 +91,65 @@ see regulator.txt - with additional custom properties described below: - regulator-initial-mode: Usage: optional Value type: - Descrption: 1 = Set initial mode to high power mode (HPM), also referred - to as NPM. HPM consumes more ground current than LPM, but + Description: 2 = Set initial mode to auto mode (automatically select + between HPM and LPM); not available on boost type + regulators. + + 1 = Set initial mode to high power mode (HPM), also referred + to as NPM. HPM consumes more ground current than LPM, but it can source significantly higher load current. HPM is not available on boost type regulators. For voltage switch type regulators, HPM implies that over current protection and - soft start are active all the time. 0 = Set initial mode to - low power mode (LPM). + soft start are active all the time. + + 0 = Set initial mode to low power mode (LPM). + +- qcom,ocp-max-retries: + Usage: optional + Value type: + Description: Maximum number of times to try toggling a voltage switch + off and back on as a result of consecutive over current + events. + +- qcom,ocp-retry-delay: + Usage: optional + Value type: + Description: Time to delay in milliseconds between each voltage switch + toggle after an over current event takes place. + +- qcom,pin-ctrl-enable: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + enable the regulator, if any; supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + +- qcom,pin-ctrl-hpm: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + force the regulator into high power mode, if any; + supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state + +- qcom,vs-soft-start-strength: + Usage: optional + Value type: + Description: This property sets the soft start strength for voltage + switch type regulators; supported values are: + 0 = 0.05 uA + 1 = 0.25 uA + 2 = 0.55 uA + 3 = 0.75 uA Example: diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 9ef0e2f28ec4..88a5dc88badc 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -26,6 +26,70 @@ #include #include +/* Pin control enable input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT 0x10 + +/* Pin control high power mode input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10 +#define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20 + +/* + * Used with enable parameters to specify that hardware default register values + * should be left unaltered. + */ +#define SPMI_REGULATOR_USE_HW_DEFAULT 2 + +/* Soft start strength of a voltage switch type regulator */ +enum spmi_vs_soft_start_str { + SPMI_VS_SOFT_START_STR_0P05_UA = 0, + SPMI_VS_SOFT_START_STR_0P25_UA, + SPMI_VS_SOFT_START_STR_0P55_UA, + SPMI_VS_SOFT_START_STR_0P75_UA, + SPMI_VS_SOFT_START_STR_HW_DEFAULT, +}; + +/** + * struct spmi_regulator_init_data - spmi-regulator initialization data + * @pin_ctrl_enable: Bit mask specifying which hardware pins should be + * used to enable the regulator, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_ENABLE_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is + * set, then pin control enable hardware registers + * will not be modified. + * @pin_ctrl_hpm: Bit mask specifying which hardware pins should be + * used to force the regulator into high power + * mode, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_HPM_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is + * set, then pin control mode hardware registers + * will not be modified. + * @vs_soft_start_strength: This parameter sets the soft start strength for + * voltage switch type regulators. Its value + * should be one of SPMI_VS_SOFT_START_STR_*. If + * its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT, + * then the soft start strength will be left at its + * default hardware value. + */ +struct spmi_regulator_init_data { + unsigned pin_ctrl_enable; + unsigned pin_ctrl_hpm; + enum spmi_vs_soft_start_str vs_soft_start_strength; +}; + /* These types correspond to unique register layouts. */ enum spmi_regulator_logical_type { SPMI_REGULATOR_LOGICAL_TYPE_SMPS, @@ -458,6 +522,14 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev) return spmi_regulator_common_enable(rdev); } +static int spmi_regulator_vs_ocp(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 reg = SPMI_VS_OCP_OVERRIDE; + + return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, ®, 1); +} + static int spmi_regulator_common_disable(struct regulator_dev *rdev) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); @@ -791,6 +863,9 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev) if (reg & SPMI_COMMON_MODE_HPM_MASK) return REGULATOR_MODE_NORMAL; + if (reg & SPMI_COMMON_MODE_AUTO_MASK) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_IDLE; } @@ -798,11 +873,13 @@ static int spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - u8 mask = SPMI_COMMON_MODE_HPM_MASK; + u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; u8 val = 0; if (mode == REGULATOR_MODE_NORMAL) - val = mask; + val = SPMI_COMMON_MODE_HPM_MASK; + else if (mode == REGULATOR_MODE_FAST) + val = SPMI_COMMON_MODE_AUTO_MASK; return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); } @@ -972,6 +1049,7 @@ static struct regulator_ops spmi_vs_ops = { .is_enabled = spmi_regulator_common_is_enabled, .set_pull_down = spmi_regulator_common_set_pull_down, .set_soft_start = spmi_regulator_common_set_soft_start, + .set_over_current_protection = spmi_regulator_vs_ocp, }; static struct regulator_ops spmi_boost_ops = { @@ -1202,10 +1280,111 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) return ret; } +static int spmi_regulator_init_registers(struct spmi_regulator *vreg, + const struct spmi_regulator_init_data *data) +{ + int ret; + enum spmi_regulator_logical_type type; + u8 ctrl_reg[8], reg, mask; + + type = vreg->logical_type; + + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set up enable pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO + || type == SPMI_REGULATOR_LOGICAL_TYPE_VS) + && !(data->pin_ctrl_enable + & SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_ENABLE] &= + ~SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_ENABLE] |= + data->pin_ctrl_enable & SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + } + + /* Set up mode pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + } + + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS + && !(data->pin_ctrl_hpm & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + /* Write back any control register values that were modified. */ + ret = spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set soft start strength and over current protection for VS. */ + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS) { + if (data->vs_soft_start_strength + != SPMI_VS_SOFT_START_STR_HW_DEFAULT) { + reg = data->vs_soft_start_strength + & SPMI_VS_SOFT_START_SEL_MASK; + mask = SPMI_VS_SOFT_START_SEL_MASK; + return spmi_vreg_update_bits(vreg, + SPMI_VS_REG_SOFT_START, + reg, mask); + } + } + + return 0; +} + +static void spmi_regulator_get_dt_config(struct spmi_regulator *vreg, + struct device_node *node, struct spmi_regulator_init_data *data) +{ + /* + * Initialize configuration parameters to use hardware default in case + * no value is specified via device tree. + */ + data->pin_ctrl_enable = SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT; + data->pin_ctrl_hpm = SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT; + data->vs_soft_start_strength = SPMI_VS_SOFT_START_STR_HW_DEFAULT; + + /* These bindings are optional, so it is okay if they aren't found. */ + of_property_read_u32(node, "qcom,ocp-max-retries", + &vreg->ocp_max_retries); + of_property_read_u32(node, "qcom,ocp-retry-delay", + &vreg->ocp_retry_delay_ms); + of_property_read_u32(node, "qcom,pin-ctrl-enable", + &data->pin_ctrl_enable); + of_property_read_u32(node, "qcom,pin-ctrl-hpm", &data->pin_ctrl_hpm); + of_property_read_u32(node, "qcom,vs-soft-start-strength", + &data->vs_soft_start_strength); +} + static unsigned int spmi_regulator_of_map_mode(unsigned int mode) { - if (mode) + if (mode == 1) return REGULATOR_MODE_NORMAL; + if (mode == 2) + return REGULATOR_MODE_FAST; return REGULATOR_MODE_IDLE; } @@ -1214,12 +1393,23 @@ static int spmi_regulator_of_parse(struct device_node *node, const struct regulator_desc *desc, struct regulator_config *config) { + struct spmi_regulator_init_data data = { }; struct spmi_regulator *vreg = config->driver_data; struct device *dev = config->dev; int ret; - vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; - vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + spmi_regulator_get_dt_config(vreg, node, &data); + + if (!vreg->ocp_max_retries) + vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; + if (!vreg->ocp_retry_delay_ms) + vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + + ret = spmi_regulator_init_registers(vreg, &data); + if (ret) { + dev_err(dev, "common initialization failed, ret=%d\n", ret); + return ret; + } if (vreg->logical_type == SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS) { ret = spmi_regulator_ftsmps_init_slew_rate(vreg); -- cgit v1.2.3-59-g8ed1b From 2d69a115a991fb7400c501dc643c47ca54cc4045 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 9 Jul 2015 22:48:26 +0200 Subject: phy: dt bindings: add NXP LPC18xx/43xx USB OTG PHY bindings Add binding documentation for NXP LPC18xx/43xx USB OTG PHY. This PHY can found on NXP LPC18xx and LPC43xx devices with USB support. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/phy-lpc18xx-usb-otg.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt b/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt new file mode 100644 index 000000000000..bd61b467e30a --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt @@ -0,0 +1,26 @@ +NXP LPC18xx/43xx internal USB OTG PHY binding +--------------------------------------------- + +This file contains documentation for the internal USB OTG PHY found +in NXP LPC18xx and LPC43xx SoCs. + +Required properties: +- compatible : must be "nxp,lpc1850-usb-otg-phy" +- clocks : must be exactly one entry +See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- #phy-cells : must be 0 for this phy +See: Documentation/devicetree/bindings/phy/phy-bindings.txt + +The phy node must be a child of the creg syscon node. + +Example: +creg: syscon@40043000 { + compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd"; + reg = <0x40043000 0x1000>; + + usb0_otg_phy: phy@004 { + compatible = "nxp,lpc1850-usb-otg-phy"; + clocks = <&ccu1 CLK_USB0>; + #phy-cells = <0>; + }; +}; -- cgit v1.2.3-59-g8ed1b From d2332303efc00d35af7f3d8b025663965862b0e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:45 +0200 Subject: phy-sun4i-usb: Add id and vbus detection support for the otg phy (phy0) The usb0 phy is connected to an OTG controller, and as such needs some special handling: 1) It allows explicit control over the pullups, enable these on phy_init and disable them on phy_exit. 2) It has bits to signal id and vbus detect to the musb-core, add support for for monitoring id and vbus detect gpio-s for use in dual role mode, and set these bits to the correct values for operating in host only mode when no gpios are specified in the devicetree. While updating the devicetree binding documentation also add documentation for the sofar undocumented usage of regulators for vbus for all 3 phys. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 18 +- drivers/phy/phy-sun4i-usb.c | 250 ++++++++++++++++++++- 2 files changed, 256 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 16528b9eb561..557fa9940164 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -23,6 +23,13 @@ Required properties: * "usb1_reset" * "usb2_reset" for sun4i, sun6i or sun7i +Optional properties: +- usb0_id_det-gpios : gpio phandle for reading the otg id pin value +- usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus-supply : regulator phandle for controller usb0 vbus +- usb1_vbus-supply : regulator phandle for controller usb1 vbus +- usb2_vbus-supply : regulator phandle for controller usb2 vbus + Example: usbphy: phy@0x01c13400 { #phy-cells = <1>; @@ -32,6 +39,13 @@ Example: reg-names = "phy_ctrl", "pmu1", "pmu2"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>, <&usb_clk 2>; - reset-names = "usb1_reset", "usb2_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>; + reset-names = "usb0_reset", "usb1_reset", "usb2_reset"; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>; + usb0_id_det-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */ + usb0_vbus_det-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */ + usb0_vbus-supply = <®_usb0_vbus>; + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; }; diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e17c539e4f6f..37f52f73fdba 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -1,7 +1,7 @@ /* * Allwinner sun4i USB phy driver * - * Copyright (C) 2014 Hans de Goede + * Copyright (C) 2014-2015 Hans de Goede * * Based on code from * Allwinner Technology Co., Ltd. @@ -24,16 +24,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #define REG_ISCR 0x00 #define REG_PHYCTL 0x04 @@ -47,6 +50,17 @@ #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) #define SUNXI_ULPI_BYPASS_EN BIT(0) +/* ISCR, Interface Status and Control bits */ +#define ISCR_ID_PULLUP_EN (1 << 17) +#define ISCR_DPDM_PULLUP_EN (1 << 16) +/* sunxi has the phy id/vbus pins not connected, so we use the force bits */ +#define ISCR_FORCE_ID_MASK (3 << 14) +#define ISCR_FORCE_ID_LOW (2 << 14) +#define ISCR_FORCE_ID_HIGH (3 << 14) +#define ISCR_FORCE_VBUS_MASK (3 << 12) +#define ISCR_FORCE_VBUS_LOW (2 << 12) +#define ISCR_FORCE_VBUS_HIGH (3 << 12) + /* Common Control Bits for Both PHYs */ #define PHY_PLL_BW 0x03 #define PHY_RES45_CAL_EN 0x0c @@ -63,6 +77,13 @@ #define MAX_PHYS 3 +/* + * Note do not raise the debounce time, we must report Vusb high within 100ms + * otherwise we get Vbus errors + */ +#define DEBOUNCE_TIME msecs_to_jiffies(50) +#define POLL_TIME msecs_to_jiffies(250) + struct sun4i_usb_phy_data { void __iomem *base; struct mutex mutex; @@ -74,13 +95,56 @@ struct sun4i_usb_phy_data { struct regulator *vbus; struct reset_control *reset; struct clk *clk; + bool regulator_on; int index; } phys[MAX_PHYS]; + /* phy0 / otg related variables */ + bool phy0_init; + bool phy0_poll; + struct gpio_desc *id_det_gpio; + struct gpio_desc *vbus_det_gpio; + int id_det_irq; + int vbus_det_irq; + int id_det; + int vbus_det; + struct delayed_work detect; }; #define to_sun4i_usb_phy_data(phy) \ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index]) +static void sun4i_usb_phy0_update_iscr(struct phy *_phy, u32 clr, u32 set) +{ + struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + u32 iscr; + + iscr = readl(data->base + REG_ISCR); + iscr &= ~clr; + iscr |= set; + writel(iscr, data->base + REG_ISCR); +} + +static void sun4i_usb_phy0_set_id_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_ID_HIGH; + else + val = ISCR_FORCE_ID_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_ID_MASK, val); +} + +static void sun4i_usb_phy0_set_vbus_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_VBUS_HIGH; + else + val = ISCR_FORCE_VBUS_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_VBUS_MASK, val); +} + static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, int len) { @@ -171,12 +235,39 @@ static int sun4i_usb_phy_init(struct phy *_phy) sun4i_usb_phy_passby(phy, 1); + if (phy->index == 0) { + data->phy0_init = true; + + /* Enable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_DPDM_PULLUP_EN); + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_ID_PULLUP_EN); + + if (data->id_det_gpio) { + /* OTG mode, force ISCR and cable state updates */ + data->id_det = -1; + data->vbus_det = -1; + queue_delayed_work(system_wq, &data->detect, 0); + } else { + /* Host only mode */ + sun4i_usb_phy0_set_id_detect(_phy, 0); + sun4i_usb_phy0_set_vbus_detect(_phy, 1); + } + } + return 0; } static int sun4i_usb_phy_exit(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (phy->index == 0) { + /* Disable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0); + sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0); + data->phy0_init = false; + } sun4i_usb_phy_passby(phy, 0); reset_control_assert(phy->reset); @@ -188,20 +279,46 @@ static int sun4i_usb_phy_exit(struct phy *_phy) static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); - int ret = 0; + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + int ret; + + if (!phy->vbus || phy->regulator_on) + return 0; + + /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ + if (phy->index == 0 && data->vbus_det) + return 0; - if (phy->vbus) - ret = regulator_enable(phy->vbus); + ret = regulator_enable(phy->vbus); + if (ret) + return ret; - return ret; + phy->regulator_on = true; + + /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ + if (phy->index == 0 && data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return 0; } static int sun4i_usb_phy_power_off(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (!phy->vbus || !phy->regulator_on) + return 0; - if (phy->vbus) - regulator_disable(phy->vbus); + regulator_disable(phy->vbus); + phy->regulator_on = false; + + /* + * phy0 vbus typically slowly discharges, sometimes this causes the + * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. + */ + if (phy->index == 0 && !data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; } @@ -221,6 +338,49 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) +{ + struct sun4i_usb_phy_data *data = + container_of(work, struct sun4i_usb_phy_data, detect.work); + struct phy *phy0 = data->phys[0].phy; + int id_det, vbus_det; + + id_det = gpiod_get_value_cansleep(data->id_det_gpio); + vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + + mutex_lock(&phy0->mutex); + + if (!data->phy0_init) { + mutex_unlock(&phy0->mutex); + return; + } + + if (id_det != data->id_det) { + sun4i_usb_phy0_set_id_detect(phy0, id_det); + data->id_det = id_det; + } + + if (vbus_det != data->vbus_det) { + sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); + data->vbus_det = vbus_det; + } + + mutex_unlock(&phy0->mutex); + + if (data->phy0_poll) + queue_delayed_work(system_wq, &data->detect, POLL_TIME); +} + +static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) +{ + struct sun4i_usb_phy_data *data = dev_id; + + /* vbus or id changed, let the pins settle and then scan them */ + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return IRQ_HANDLED; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -232,6 +392,21 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, return data->phys[args->args[0]].phy; } +static int sun4i_usb_phy_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + + if (data->id_det_irq >= 0) + devm_free_irq(dev, data->id_det_irq, data); + if (data->vbus_det_irq >= 0) + devm_free_irq(dev, data->vbus_det_irq, data); + + cancel_delayed_work_sync(&data->detect); + + return 0; +} + static int sun4i_usb_phy_probe(struct platform_device *pdev) { struct sun4i_usb_phy_data *data; @@ -240,13 +415,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) struct phy_provider *phy_provider; bool dedicated_clocks; struct resource *res; - int i; + int i, ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; mutex_init(&data->mutex); + INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); + dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) data->num_phys = 2; @@ -269,6 +446,26 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); + data->id_det_gpio = devm_gpiod_get(dev, "usb0_id_det", GPIOD_IN); + if (IS_ERR(data->id_det_gpio)) { + if (PTR_ERR(data->id_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->id_det_gpio = NULL; + } + + data->vbus_det_gpio = devm_gpiod_get(dev, "usb0_vbus_det", GPIOD_IN); + if (IS_ERR(data->vbus_det_gpio)) { + if (PTR_ERR(data->vbus_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->vbus_det_gpio = NULL; + } + + /* We either want both gpio pins or neither (when in host mode) */ + if (!data->id_det_gpio != !data->vbus_det_gpio) { + dev_err(dev, "failed to get id or vbus detect pin\n"); + return -ENODEV; + } + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; @@ -318,10 +515,42 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy->phy, &data->phys[i]); } - dev_set_drvdata(dev, data); + data->id_det_irq = gpiod_to_irq(data->id_det_gpio); + data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); + if (data->id_det_irq < 0 || data->vbus_det_irq < 0) + data->phy0_poll = true; + + if (data->id_det_irq >= 0) { + ret = devm_request_irq(dev, data->id_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-id-det", data); + if (ret) { + dev_err(dev, "Err requesting id-det-irq: %d\n", ret); + return ret; + } + } + + if (data->vbus_det_irq >= 0) { + ret = devm_request_irq(dev, data->vbus_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-vbus-det", data); + if (ret) { + dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret); + data->vbus_det_irq = -1; + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); + if (IS_ERR(phy_provider)) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return PTR_ERR(phy_provider); + } - return PTR_ERR_OR_ZERO(phy_provider); + return 0; } static const struct of_device_id sun4i_usb_phy_of_match[] = { @@ -335,6 +564,7 @@ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { .probe = sun4i_usb_phy_probe, + .remove = sun4i_usb_phy_remove, .driver = { .of_match_table = sun4i_usb_phy_of_match, .name = "sun4i-usb-phy", -- cgit v1.2.3-59-g8ed1b From 123dfdbcfaf5eb8753cd6293ab50c41e9b8e9ebf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:48 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a23 SoC The usb-phys on the sun8i-a23 SoC have the same setup wrt clocks as on the sun6i-a31 SoC, but there are only 2 instead of 3 like on the sun5i-a13 SoC. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 2 ++ drivers/phy/phy-sun4i-usb.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 557fa9940164..f0c640adee64 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -7,6 +7,7 @@ Required properties: * allwinner,sun5i-a13-usb-phy * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy + * allwinner,sun8i-a23-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" @@ -17,6 +18,7 @@ Required properties: - clock-names : * "usb_phy" for sun4i, sun5i or sun7i * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i + * "usb0_phy", "usb1_phy" for sun8i - resets : a list of phandle + reset specifier pairs - reset-names : * "usb0_reset" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 50ecab9d73df..00424dde79c1 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -442,7 +442,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); dev_set_drvdata(dev, data); - if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -453,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->disc_thresh = 3; - if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; @@ -588,6 +590,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun5i-a13-usb-phy" }, { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, + { .compatible = "allwinner,sun8i-a23-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v1.2.3-59-g8ed1b From fc1f45ed3043da3aa901e88a9ef0995bbd320698 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:49 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC The usb-phys on the sun8i-a33 SoC are mostly the same as sun8i-a23 but for some reason (hw bug?) the phyctl register was moved to a different address and is not initialized to 0 on reset. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 1 + drivers/phy/phy-sun4i-usb.c | 39 ++++++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index f0c640adee64..5f48979b4edc 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -8,6 +8,7 @@ Required properties: * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy * allwinner,sun8i-a23-usb-phy + * allwinner,sun8i-a33-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 00424dde79c1..ddc399536c5c 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -40,9 +40,10 @@ #include #define REG_ISCR 0x00 -#define REG_PHYCTL 0x04 +#define REG_PHYCTL_A10 0x04 #define REG_PHYBIST 0x08 #define REG_PHYTUNE 0x0c +#define REG_PHYCTL_A33 0x10 #define PHYCTL_DATA BIT(7) @@ -90,6 +91,7 @@ struct sun4i_usb_phy_data { struct mutex mutex; int num_phys; u32 disc_thresh; + bool has_a33_phyctl; struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -152,37 +154,46 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, { struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 temp, usbc_bit = BIT(phy->index * 2); + void *phyctl; int i; mutex_lock(&phy_data->mutex); + if (phy_data->has_a33_phyctl) { + phyctl = phy_data->base + REG_PHYCTL_A33; + /* A33 needs us to set phyctl to 0 explicitly */ + writel(0, phyctl); + } else { + phyctl = phy_data->base + REG_PHYCTL_A10; + } + for (i = 0; i < len; i++) { - temp = readl(phy_data->base + REG_PHYCTL); + temp = readl(phyctl); /* clear the address portion */ temp &= ~(0xff << 8); /* set the address */ temp |= ((addr + i) << 8); - writel(temp, phy_data->base + REG_PHYCTL); + writel(temp, phyctl); /* set the data bit and clear usbc bit*/ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); if (data & 0x1) temp |= PHYCTL_DATA; else temp &= ~PHYCTL_DATA; temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); /* pulse usbc_bit */ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp |= usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); data >>= 1; } @@ -443,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -455,11 +467,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->disc_thresh = 3; if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; + if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) + data->has_a33_phyctl = true; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); data->base = devm_ioremap_resource(dev, res); if (IS_ERR(data->base)) @@ -591,6 +607,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, { .compatible = "allwinner,sun8i-a23-usb-phy" }, + { .compatible = "allwinner,sun8i-a33-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v1.2.3-59-g8ed1b From 8665c18bece7965c3690ac3824bef2f97bae3d71 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:51 +0200 Subject: phy-sun4i-usb: Add support for monitoring vbus via a power-supply On some boards there is no vbus_det gpio pin, instead vbus-detection for otg can be done via the pmic. This commit adds support for monitoring vbus_det via the power_supply exported by the pmic, enabling support for otg on these boards. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 1 + drivers/phy/Kconfig | 1 + drivers/phy/phy-sun4i-usb.c | 76 ++++++++++++++++++++-- 3 files changed, 71 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 5f48979b4edc..0cebf7454517 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -29,6 +29,7 @@ Required properties: Optional properties: - usb0_id_det-gpios : gpio phandle for reading the otg id pin value - usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus_power-supply: power-supply phandle for usb0 vbus presence detect - usb0_vbus-supply : regulator phandle for controller usb0 vbus - usb1_vbus-supply : regulator phandle for controller usb1 vbus - usb2_vbus-supply : regulator phandle for controller usb2 vbus diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0c1ad2e2c01..0fe9bff7b37b 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -209,6 +209,7 @@ config PHY_SUN4I_USB depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER depends on EXTCON + depends on POWER_SUPPLY select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 4ba9856ac71a..5138843ec42d 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,9 @@ struct sun4i_usb_phy_data { bool phy0_poll; struct gpio_desc *id_det_gpio; struct gpio_desc *vbus_det_gpio; + struct power_supply *vbus_power_supply; + struct notifier_block vbus_power_nb; + bool vbus_power_nb_registered; int id_det_irq; int vbus_det_irq; int id_det; @@ -352,6 +356,30 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) +{ + if (data->vbus_det_gpio) + return gpiod_get_value_cansleep(data->vbus_det_gpio); + + if (data->vbus_power_supply) { + union power_supply_propval val; + int r; + + r = power_supply_get_property(data->vbus_power_supply, + POWER_SUPPLY_PROP_PRESENT, &val); + if (r == 0) + return val.intval; + } + + /* Fallback: report vbus as high */ + return 1; +} + +static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) +{ + return data->vbus_det_gpio || data->vbus_power_supply; +} + static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) { struct sun4i_usb_phy_data *data = @@ -360,10 +388,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); - if (data->vbus_det_gpio) - vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); - else - vbus_det = 1; /* Report vbus as high */ + vbus_det = sun4i_usb_phy0_get_vbus_det(data); mutex_lock(&phy0->mutex); @@ -378,7 +403,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough for * the musb-ip to end the current device session. */ - if (!data->vbus_det_gpio && id_det == 0) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 0) { sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(200); sun4i_usb_phy0_set_vbus_detect(phy0, 1); @@ -404,7 +429,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough to * the musb-ip to end the current host session. */ - if (!data->vbus_det_gpio && id_det == 1) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 1) { mutex_lock(&phy0->mutex); sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(1000); @@ -430,6 +455,20 @@ static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct sun4i_usb_phy_data *data = + container_of(nb, struct sun4i_usb_phy_data, vbus_power_nb); + struct power_supply *psy = v; + + /* Properties on the vbus_power_supply changed, scan vbus_det */ + if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return NOTIFY_OK; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -446,6 +485,8 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + if (data->vbus_power_nb_registered) + power_supply_unreg_notifier(&data->vbus_power_nb); if (data->id_det_irq >= 0) devm_free_irq(dev, data->id_det_irq, data); if (data->vbus_det_irq >= 0) @@ -522,8 +563,18 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->vbus_det_gpio = NULL; } + if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { + data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, + "usb0_vbus_power-supply"); + if (IS_ERR(data->vbus_power_supply)) + return PTR_ERR(data->vbus_power_supply); + + if (!data->vbus_power_supply) + return -EPROBE_DEFER; + } + /* vbus_det without id_det makes no sense, and is not supported */ - if (data->vbus_det_gpio && !data->id_det_gpio) { + if (sun4i_usb_phy0_have_vbus_det(data) && !data->id_det_gpio) { dev_err(dev, "usb0_id_det missing or invalid\n"); return -ENODEV; } @@ -620,6 +671,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } + if (data->vbus_power_supply) { + data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify; + data->vbus_power_nb.priority = 0; + ret = power_supply_reg_notifier(&data->vbus_power_nb); + if (ret) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + data->vbus_power_nb_registered = true; + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); if (IS_ERR(phy_provider)) { sun4i_usb_phy_remove(pdev); /* Stop detect work */ -- cgit v1.2.3-59-g8ed1b From 0817b62cc037a56c5e4238c7eb7522299ea27aef Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jul 2015 20:48:08 +0200 Subject: clk: change clk_ops' ->determine_rate() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clock rates are stored in an unsigned long field, but ->determine_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change ->determine_rate() prototype to return 0 or an error code, and pass a pointer to a clk_rate_request structure containing the expected target rate and the rate constraints imposed by clk users. The clk_rate_request structure might be extended in the future to contain other kind of constraints like the rounding policy, the maximum clock inaccuracy or other things that are not yet supported by the CCF (power consumption constraints ?). Signed-off-by: Boris Brezillon CC: Jonathan Corbet CC: Tony Lindgren CC: Ralf Baechle CC: "Emilio López" CC: Maxime Ripard Acked-by: Tero Kristo CC: Peter De Schrijver CC: Prashant Gaikwad CC: Stephen Warren CC: Thierry Reding CC: Alexandre Courbot CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-arm-kernel@lists.infradead.org CC: linux-omap@vger.kernel.org CC: linux-mips@linux-mips.org CC: linux-tegra@vger.kernel.org [sboyd@codeaurora.org: Fix parent dereference problem in __clk_determine_rate()] Signed-off-by: Stephen Boyd Tested-by: Romain Perier Signed-off-by: Heiko Stuebner [sboyd@codeaurora.org: Folded in fix from Heiko for fixed-rate clocks without parents or a rate determining op] Signed-off-by: Stephen Boyd --- Documentation/clk.txt | 8 +- arch/arm/mach-omap2/dpll3xxx.c | 29 +++--- arch/arm/mach-omap2/dpll44xx.c | 30 +++--- arch/mips/alchemy/common/clock.c | 61 +++++-------- drivers/clk/at91/clk-programmable.c | 25 ++--- drivers/clk/at91/clk-usb.c | 28 +++--- drivers/clk/bcm/clk-kona.c | 34 ++++--- drivers/clk/clk-composite.c | 48 +++++----- drivers/clk/clk.c | 176 ++++++++++++++++++++---------------- drivers/clk/hisilicon/clk-hi3620.c | 39 ++++---- drivers/clk/mmp/clk-mix.c | 20 ++-- drivers/clk/qcom/clk-pll.c | 18 ++-- drivers/clk/qcom/clk-rcg.c | 44 ++++----- drivers/clk/qcom/clk-rcg2.c | 78 ++++++++-------- drivers/clk/sunxi/clk-factors.c | 21 ++--- drivers/clk/sunxi/clk-sun6i-ar100.c | 21 ++--- drivers/clk/sunxi/clk-sunxi.c | 20 ++-- drivers/clk/tegra/clk-emc.c | 28 +++--- include/linux/clk-provider.h | 49 ++++++---- include/linux/clk/ti.h | 16 +--- 20 files changed, 392 insertions(+), 401 deletions(-) (limited to 'Documentation') diff --git a/Documentation/clk.txt b/Documentation/clk.txt index f463bdc37f88..5c4bc4d01d0c 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -71,12 +71,8 @@ the operations defined in clk.h: long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 44e57ec225d4..8c57ace30421 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -462,43 +462,38 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) /** * omap3_noncore_dpll_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired target rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns a 0 on success, negative error value in failure. */ -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap2_dpll_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } /** diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index f231be05b9a6..446a4e0d5a6a 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -191,42 +191,36 @@ out: /** * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns 0 on success and a negative error value otherwise. */ -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap4_dpll_regm4xen_round_rate(hw, rate, - best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index 6e46abe0dac6..0b4cf3e9f005 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -389,10 +389,9 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate, return div1; } -static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk, - int scale, int maxdiv) +static int alchemy_clk_fgcs_detr(struct clk_hw *hw, + struct clk_rate_request *req, + int scale, int maxdiv) { struct clk *pc, *bpc, *free; long tdv, tpr, pr, nr, br, bpr, diff, lastdiff; @@ -422,14 +421,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } pr = clk_get_rate(pc); - if (pr < rate) + if (pr < req->rate) continue; /* what can hardware actually provide */ - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { @@ -448,15 +447,16 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, */ if (lastdiff && free) { for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) { - tpr = rate * j; + tpr = req->rate * j; if (tpr < 0) break; pr = clk_round_rate(free, tpr); - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, + NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { lastdiff = diff; @@ -469,9 +469,10 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } } - *best_parent_rate = bpr; - *best_parent_clk = __clk_get_hw(bpc); - return br; + req->best_parent_rate = bpr; + req->best_parent_hw = __clk_get_hw(bpc); + req->rate = br; + return 0; } static int alchemy_clk_fgv1_en(struct clk_hw *hw) @@ -562,14 +563,10 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, return parent_rate / v; } -static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv1_detr(struct clk_hw *hw, + struct clk_rate_request *req) { - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, 2, 512); + return alchemy_clk_fgcs_detr(hw, req, 2, 512); } /* Au1000, Au1100, Au15x0, Au12x0 */ @@ -696,11 +693,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, return t; } -static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv2_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale, maxdiv; @@ -713,8 +707,7 @@ static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, maxdiv = 512; } - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, maxdiv); + return alchemy_clk_fgcs_detr(hw, req, scale, maxdiv); } /* Au1300 larger input mux, no separate disable bit, flexible divider */ @@ -917,17 +910,13 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, return 0; } -static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_csrc_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, 4); + return alchemy_clk_fgcs_detr(hw, req, scale, 4); } static struct clk_ops alchemy_clkops_csrc = { diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 8c86c0f7847a..43dacad5c96d 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -54,12 +54,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, return parent_rate >> pres; } -static long clk_programmable_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int clk_programmable_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -76,24 +72,29 @@ static long clk_programmable_determine_rate(struct clk_hw *hw, parent_rate = __clk_get_rate(parent); for (shift = 0; shift < PROG_PRES_MASK; shift++) { tmp_rate = parent_rate >> shift; - if (tmp_rate <= rate) + if (tmp_rate <= req->rate) break; } - if (tmp_rate > rate) + if (tmp_rate > req->rate) continue; - if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) { + if (best_rate < 0 || + (req->rate - tmp_rate) < (req->rate - best_rate)) { best_rate = tmp_rate; - *best_parent_rate = parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } if (!best_rate) break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index b0cbd2b1ff59..24747df97742 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -56,12 +56,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); } -static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -80,23 +76,23 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) { unsigned long tmp_parent_rate; - tmp_parent_rate = rate * div; + tmp_parent_rate = req->rate * div; tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); - if (tmp_rate < rate) - tmp_diff = rate - tmp_rate; + if (tmp_rate < req->rate) + tmp_diff = req->rate - tmp_rate; else - tmp_diff = tmp_rate - rate; + tmp_diff = tmp_rate - req->rate; if (best_diff < 0 || best_diff > tmp_diff) { best_rate = tmp_rate; best_diff = tmp_diff; - *best_parent_rate = tmp_parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = tmp_parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } - if (!best_diff || tmp_rate < rate) + if (!best_diff || tmp_rate < req->rate) break; } @@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 79a98506c433..d9c039c1902c 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1017,10 +1017,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, rate ? rate : 1, *parent_rate, NULL); } -static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, struct clk_hw **best_parent) +static int kona_peri_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct kona_clk *bcm_clk = to_kona_clk(hw); struct clk *clk = hw->clk; @@ -1029,6 +1027,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long best_delta; unsigned long best_rate; u32 parent_count; + long rate; u32 which; /* @@ -1037,14 +1036,21 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, */ WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); parent_count = (u32)bcm_clk->init_data.num_parents; - if (parent_count < 2) - return kona_peri_clk_round_rate(hw, rate, best_parent_rate); + if (parent_count < 2) { + rate = kona_peri_clk_round_rate(hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; + } /* Unless we can do better, stick with current parent */ current_parent = clk_get_parent(clk); parent_rate = __clk_get_rate(current_parent); - best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - best_delta = abs(best_rate - rate); + best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate); + best_delta = abs(best_rate - req->rate); /* Check whether any other parent clock can produce a better result */ for (which = 0; which < parent_count; which++) { @@ -1058,17 +1064,19 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, /* We don't support CLK_SET_RATE_PARENT */ parent_rate = __clk_get_rate(parent); - other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - delta = abs(other_rate - rate); + other_rate = kona_peri_clk_round_rate(hw, req->rate, + &parent_rate); + delta = abs(other_rate - req->rate); if (delta < best_delta) { best_delta = delta; best_rate = other_rate; - *best_parent = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; } } - return best_rate; + req->rate = best_rate; + return 0; } static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 616f5aef3c26..9e69f346ecc6 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -55,11 +55,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, return rate_ops->recalc_rate(rate_hw, parent_rate); } -static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; @@ -71,25 +68,28 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; + long rate; int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { __clk_hw_set_clk(rate_hw, hw); - return rate_ops->determine_rate(rate_hw, rate, min_rate, - max_rate, - best_parent_rate, - best_parent_p); + return rate_ops->determine_rate(rate_hw, req); } else if (rate_hw && rate_ops && rate_ops->round_rate && mux_hw && mux_ops && mux_ops->set_parent) { - *best_parent_p = NULL; + req->best_parent_hw = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { parent = clk_get_parent(mux_hw->clk); - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = __clk_get_rate(parent); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); - return rate_ops->round_rate(rate_hw, rate, - best_parent_rate); + rate = rate_ops->round_rate(rate_hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; } for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) { @@ -99,33 +99,33 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, parent_rate = __clk_get_rate(parent); - tmp_rate = rate_ops->round_rate(rate_hw, rate, + tmp_rate = rate_ops->round_rate(rate_hw, req->rate, &parent_rate); if (tmp_rate < 0) continue; - rate_diff = abs(rate - tmp_rate); + rate_diff = abs(req->rate - tmp_rate); - if (!rate_diff || !*best_parent_p + if (!rate_diff || !req->best_parent_hw || best_rate_diff > rate_diff) { - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; } if (!rate_diff) - return rate; + return 0; } - return best_rate; + req->rate = best_rate; + return 0; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); - return mux_ops->determine_rate(mux_hw, rate, min_rate, - max_rate, best_parent_rate, - best_parent_p); + return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); + req->rate = 0; return 0; } } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ddb4b541016f..4e9ff928ef88 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -436,28 +436,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now, return now <= rate && now > best; } -static long -clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p, +static int +clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req, unsigned long flags) { struct clk_core *core = hw->core, *parent, *best_parent = NULL; - int i, num_parents; - unsigned long parent_rate, best = 0; + int i, num_parents, ret; + unsigned long best = 0; + struct clk_rate_request parent_req = *req; /* if NO_REPARENT flag set, pass through to current parent */ if (core->flags & CLK_SET_RATE_NO_REPARENT) { parent = core->parent; - if (core->flags & CLK_SET_RATE_PARENT) - best = __clk_determine_rate(parent ? parent->hw : NULL, - rate, min_rate, max_rate); - else if (parent) + if (core->flags & CLK_SET_RATE_PARENT) { + ret = __clk_determine_rate(parent ? parent->hw : NULL, + &parent_req); + if (ret) + return ret; + + best = parent_req.rate; + } else if (parent) { best = clk_core_get_rate_nolock(parent); - else + } else { best = clk_core_get_rate_nolock(core); + } + goto out; } @@ -467,24 +470,30 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, parent = clk_core_get_parent_by_index(core, i); if (!parent) continue; - if (core->flags & CLK_SET_RATE_PARENT) - parent_rate = __clk_determine_rate(parent->hw, rate, - min_rate, - max_rate); - else - parent_rate = clk_core_get_rate_nolock(parent); - if (mux_is_better_rate(rate, parent_rate, best, flags)) { + + if (core->flags & CLK_SET_RATE_PARENT) { + parent_req = *req; + ret = __clk_determine_rate(parent->hw, &parent_req); + if (ret) + continue; + } else { + parent_req.rate = clk_core_get_rate_nolock(parent); + } + + if (mux_is_better_rate(req->rate, parent_req.rate, + best, flags)) { best_parent = parent; - best = parent_rate; + best = parent_req.rate; } } out: if (best_parent) - *best_parent_p = best_parent->hw; - *best_parent_rate = best; + req->best_parent_hw = best_parent->hw; + req->best_parent_rate = best; + req->rate = best; - return best; + return 0; } struct clk *__clk_lookup(const char *name) @@ -515,28 +524,17 @@ static void clk_core_get_boundaries(struct clk_core *core, * directly as a determine_rate callback (e.g. for a mux), or from a more * complex clock that may combine a mux with other operations. */ -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, 0); + return clk_mux_determine_rate_flags(hw, req, 0); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, - CLK_MUX_ROUND_CLOSEST); + return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); @@ -759,14 +757,11 @@ int clk_enable(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_enable); -static unsigned long clk_core_round_rate_nolock(struct clk_core *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +static int clk_core_round_rate_nolock(struct clk_core *core, + struct clk_rate_request *req) { - unsigned long parent_rate = 0; struct clk_core *parent; - struct clk_hw *parent_hw; + long rate; lockdep_assert_held(&prepare_lock); @@ -774,21 +769,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, return 0; parent = core->parent; - if (parent) - parent_rate = parent->rate; + if (parent) { + req->best_parent_hw = parent->hw; + req->best_parent_rate = parent->rate; + } else { + req->best_parent_hw = NULL; + req->best_parent_rate = 0; + } if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - return core->ops->determine_rate(core->hw, rate, - min_rate, max_rate, - &parent_rate, &parent_hw); - } else if (core->ops->round_rate) - return core->ops->round_rate(core->hw, rate, &parent_rate); - else if (core->flags & CLK_SET_RATE_PARENT) - return clk_core_round_rate_nolock(core->parent, rate, min_rate, - max_rate); - else - return core->rate; + return core->ops->determine_rate(core->hw, req); + } else if (core->ops->round_rate) { + rate = core->ops->round_rate(core->hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + } else if (core->flags & CLK_SET_RATE_PARENT) { + return clk_core_round_rate_nolock(parent, req); + } else { + req->rate = core->rate; + } + + return 0; } /** @@ -800,15 +804,14 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, * * Useful for clk_ops such as .set_rate and .determine_rate. */ -unsigned long __clk_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - if (!hw) + if (!hw) { + req->rate = 0; return 0; + } - return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate); + return clk_core_round_rate_nolock(hw->core, req); } EXPORT_SYMBOL_GPL(__clk_determine_rate); @@ -821,15 +824,20 @@ EXPORT_SYMBOL_GPL(__clk_determine_rate); */ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { - unsigned long min_rate; - unsigned long max_rate; + struct clk_rate_request req; + int ret; if (!clk) return 0; - clk_core_get_boundaries(clk->core, &min_rate, &max_rate); + clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate); + req.rate = rate; + + ret = clk_core_round_rate_nolock(clk->core, &req); + if (ret) + return 0; - return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate); + return req.rate; } EXPORT_SYMBOL_GPL(__clk_round_rate); @@ -1249,7 +1257,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, { struct clk_core *top = core; struct clk_core *old_parent, *parent; - struct clk_hw *parent_hw; unsigned long best_parent_rate = 0; unsigned long new_rate; unsigned long min_rate; @@ -1270,20 +1277,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, /* find the closest rate and parent clk/rate */ if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - ret = core->ops->determine_rate(core->hw, rate, - min_rate, - max_rate, - &best_parent_rate, - &parent_hw); + struct clk_rate_request req; + + req.rate = rate; + req.min_rate = min_rate; + req.max_rate = max_rate; + if (parent) { + req.best_parent_hw = parent->hw; + req.best_parent_rate = parent->rate; + } else { + req.best_parent_hw = NULL; + req.best_parent_rate = 0; + } + + ret = core->ops->determine_rate(core->hw, &req); if (ret < 0) return NULL; - new_rate = ret; - parent = parent_hw ? parent_hw->core : NULL; + best_parent_rate = req.best_parent_rate; + new_rate = req.rate; + parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; } else if (core->ops->round_rate) { ret = core->ops->round_rate(core->hw, rate, - &best_parent_rate); + &best_parent_rate); if (ret < 0) return NULL; diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 715d34a5ef9b..a0674ba6659e 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -294,34 +294,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, } } -static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int mmc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_mmc *mclk = to_mmc(hw); - unsigned long best = 0; - if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { - rate = 13000000; - best = 26000000; - } else if (rate <= 26000000) { - rate = 25000000; - best = 180000000; - } else if (rate <= 52000000) { - rate = 50000000; - best = 360000000; - } else if (rate <= 100000000) { - rate = 100000000; - best = 720000000; + if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { + req->rate = 13000000; + req->best_parent_rate = 26000000; + } else if (req->rate <= 26000000) { + req->rate = 25000000; + req->best_parent_rate = 180000000; + } else if (req->rate <= 52000000) { + req->rate = 50000000; + req->best_parent_rate = 360000000; + } else if (req->rate <= 100000000) { + req->rate = 100000000; + req->best_parent_rate = 720000000; } else { /* max is 180M */ - rate = 180000000; - best = 1440000000; + req->rate = 180000000; + req->best_parent_rate = 1440000000; } - *best_parent_rate = best; - return rate; + return 0; } static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len) diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index de6a873175d2..7a37432761f9 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -201,11 +201,8 @@ error: return ret; } -static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int mmp_clk_mix_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct mmp_clk_mix *mix = to_clk_mix(hw); struct mmp_clk_mix_clk_table *item; @@ -221,7 +218,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, parent = NULL; mix_rate_best = 0; parent_rate_best = 0; - gap_best = rate; + gap_best = req->rate; parent_best = NULL; if (mix->table) { @@ -233,7 +230,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, item->parent_index); parent_rate = __clk_get_rate(parent); mix_rate = parent_rate / item->divisor; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -251,7 +248,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, for (j = 0; j < div_val_max; j++) { div = _get_div(mix, j); mix_rate = parent_rate / div; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -265,10 +262,11 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, } found: - *best_parent_rate = parent_rate_best; - *best_parent_clk = __clk_get_hw(parent_best); + req->best_parent_rate = parent_rate_best; + req->best_parent_hw = __clk_get_hw(parent_best); + req->rate = mix_rate_best; - return mix_rate_best; + return 0; } static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw, diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 245d5063a385..6017a76b47c8 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -135,19 +135,23 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) return NULL; } -static long -clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int +clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { + struct clk *parent = __clk_get_parent(hw->clk); struct clk_pll *pll = to_clk_pll(hw); const struct pll_freq_tbl *f; - f = find_freq(pll->freq_tbl, rate); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); + + f = find_freq(pll->freq_tbl, req->rate); if (!f) - return clk_pll_recalc_rate(hw, *p_rate); + req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate); + else + req->rate = f->freq; - return f->freq; + return 0; } static int diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index 7b3d62674203..2bc42bb21b3d 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -404,13 +404,11 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, pre_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw, +static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, + struct clk_rate_request *req, const struct parent_map *parent_map) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; int index; @@ -435,25 +433,24 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, rcg->s.parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, + rcg->s.parent_map); } -static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_dyn_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); u32 reg; @@ -464,13 +461,11 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, bank = reg_to_bank(rcg, reg); s = &rcg->s[bank]; - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, s->parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map); } -static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_rcg_bypass_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -478,10 +473,11 @@ static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src); p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_round_rate(p, req->rate); + req->rate = req->best_parent_rate; - return *p_rate; + return 0; } static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index b95d17fbb8d7..aa6c3bdac040 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -176,11 +176,10 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, hid_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int _freq_tbl_determine_rate(struct clk_hw *hw, + const struct freq_tbl *f, struct clk_rate_request *req) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); int index; @@ -210,19 +209,19 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req); } static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) @@ -374,35 +373,34 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, return clk_edp_pixel_set_rate(hw, rate, parent_rate); } -static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_edp_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac; int delta = 100000; - s64 src_rate = *p_rate; s64 request; u32 mask = BIT(rcg->hid_width) - 1; u32 hid_div; int index = qcom_find_src_index(hw, rcg->parent_map, f->src); + struct clk *p = clk_get_parent_by_index(hw->clk, index); /* Force the correct parent */ - *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, index)); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_get_rate(p); - if (src_rate == 810000000) + if (req->best_parent_rate == 810000000) frac = frac_table_810m; else frac = frac_table_675m; for (; frac->num; frac++) { - request = rate; + request = req->rate; request *= frac->den; request = div_s64(request, frac->num); - if ((src_rate < (request - delta)) || - (src_rate > (request + delta))) + if ((req->best_parent_rate < (request - delta)) || + (req->best_parent_rate > (request + delta))) continue; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, @@ -410,8 +408,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, hid_div >>= CFG_SRC_DIV_SHIFT; hid_div &= mask; - return calc_rate(src_rate, frac->num, frac->den, !!frac->den, - hid_div); + req->rate = calc_rate(req->best_parent_rate, + frac->num, frac->den, + !!frac->den, hid_div); + return 0; } return -EINVAL; @@ -428,9 +428,8 @@ const struct clk_ops clk_edp_pixel_ops = { }; EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); -static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_byte_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -439,17 +438,19 @@ static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, u32 mask = BIT(rcg->hid_width) - 1; struct clk *p; - if (rate == 0) + if (req->rate == 0) return -EINVAL; p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = parent_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = parent_rate = __clk_round_rate(p, req->rate); - div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1; div = min_t(u32, div, mask); - return calc_rate(parent_rate, 0, 0, 0, div); + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; } static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, @@ -494,10 +495,8 @@ static const struct frac_entry frac_table_pixel[] = { { } }; -static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; @@ -507,18 +506,19 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->parent_map, f->src); struct clk *parent = clk_get_parent_by_index(hw->clk, index); - *p = __clk_get_hw(parent); + req->best_parent_hw = __clk_get_hw(parent); for (; frac->num; frac++) { - request = (rate * frac->den) / frac->num; + request = (req->rate * frac->den) / frac->num; src_rate = __clk_round_rate(parent, request); if ((src_rate < (request - delta)) || (src_rate > (request + delta))) continue; - *p_rate = src_rate; - return (src_rate * frac->num) / frac->den; + req->best_parent_rate = src_rate; + req->rate = (src_rate * frac->num) / frac->den; + return 0; } return -EINVAL; diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 8c20190a3e9f..7a485870991d 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -79,11 +79,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } -static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_factors_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -96,13 +93,14 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = clk_factors_round_rate(hw, rate, &parent_rate); + child_rate = clk_factors_round_rate(hw, req->rate, + &parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; @@ -110,10 +108,11 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_p = __clk_get_hw(best_parent); - *best_parent_rate = best; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; - return best_child_rate; + return 0; } static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index 63cf149195ae..d70c1ea345db 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -44,17 +44,14 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, return (parent_rate >> shift) / (div + 1); } -static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int ar100_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int nparents = __clk_get_num_parents(hw->clk); long best_rate = -EINVAL; int i; - *best_parent_clk = NULL; + req->best_parent_hw = NULL; for (i = 0; i < nparents; i++) { unsigned long parent_rate; @@ -65,7 +62,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, parent = clk_get_parent_by_index(hw->clk, i); parent_rate = __clk_get_rate(parent); - div = DIV_ROUND_UP(parent_rate, rate); + div = DIV_ROUND_UP(parent_rate, req->rate); /* * The AR100 clk contains 2 divisors: @@ -101,14 +98,16 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, continue; tmp_rate = (parent_rate >> shift) / div; - if (!*best_parent_clk || tmp_rate > best_rate) { - *best_parent_clk = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + if (!req->best_parent_hw || tmp_rate > best_rate) { + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate = tmp_rate; } } - return best_rate; + req->rate = best_rate; + + return 0; } static int ar100_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9a82f17d2d73..d0f72a151bf1 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -118,11 +118,8 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp, return (parent_rate / calcm) >> calcp; } -static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -135,14 +132,14 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i, + child_rate = sun6i_ahb1_clk_round(req->rate, NULL, NULL, i, parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; @@ -150,10 +147,11 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_clk = __clk_get_hw(best_parent); - *best_parent_rate = best; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; - return best_child_rate; + return 0; } static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 7649685c86bc..08ae518c9950 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -116,11 +116,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw, * safer since things have EMC rate floors. Also don't touch parent_rate * since we don't want the CCF to play with our parent clocks. */ -static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct tegra_clk_emc *tegra; u8 ram_code = tegra_read_ram_code(); @@ -135,22 +131,28 @@ static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, timing = tegra->timings + i; - if (timing->rate > max_rate) { + if (timing->rate > req->max_rate) { i = min(i, 1); - return tegra->timings[i - 1].rate; + req->rate = tegra->timings[i - 1].rate; + return 0; } - if (timing->rate < min_rate) + if (timing->rate < req->min_rate) continue; - if (timing->rate >= rate) - return timing->rate; + if (timing->rate >= req->rate) { + req->rate = timing->rate; + return 0; + } } - if (timing) - return timing->rate; + if (timing) { + req->rate = timing->rate; + return 0; + } - return __clk_get_rate(hw->clk); + req->rate = __clk_get_rate(hw->clk); + return 0; } static u8 emc_get_parent(struct clk_hw *hw) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 78842f46f152..14998f05acf2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -37,6 +37,28 @@ struct clk_hw; struct clk_core; struct dentry; +/** + * struct clk_rate_request - Structure encoding the clk constraints that + * a clock user might require. + * + * @rate: Requested clock rate. This field will be adjusted by + * clock drivers according to hardware capabilities. + * @min_rate: Minimum rate imposed by clk users. + * @max_rate: Maximum rate a imposed by clk users. + * @best_parent_rate: The best parent rate a parent can provide to fulfill the + * requested constraints. + * @best_parent_hw: The most appropriate parent clock that fulfills the + * requested constraints. + * + */ +struct clk_rate_request { + unsigned long rate; + unsigned long min_rate; + unsigned long max_rate; + unsigned long best_parent_rate; + struct clk_hw *best_parent_hw; +}; + /** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers @@ -176,12 +198,8 @@ struct clk_ops { unsigned long parent_rate); long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, unsigned long rate, @@ -578,20 +596,11 @@ unsigned long __clk_get_flags(struct clk *clk); bool __clk_is_prepared(struct clk *clk); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); -unsigned long __clk_determine_rate(struct clk_hw *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); +int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req); void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79b76e13d904..448b4f87b9eb 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -269,23 +269,15 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index); -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, -- cgit v1.2.3-59-g8ed1b From f2d2eb9d05b7d03acff0589e5fd8c13a0031cb6c Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 20 Jul 2015 22:05:55 +0200 Subject: KVM: s390: remove outdated documentation The old Documentation/s390/kvm.txt file is either outdated or described in Documentation/virtual/kvm/api.txt. Let's get rid of it. Signed-off-by: Christian Borntraeger Reviewed-by: David Hildenbrand --- Documentation/s390/00-INDEX | 2 - Documentation/s390/kvm.txt | 125 -------------------------------------------- 2 files changed, 127 deletions(-) delete mode 100644 Documentation/s390/kvm.txt (limited to 'Documentation') diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX index 10c874ebdfe5..9189535f6cd2 100644 --- a/Documentation/s390/00-INDEX +++ b/Documentation/s390/00-INDEX @@ -16,8 +16,6 @@ Debugging390.txt - hints for debugging on s390 systems. driver-model.txt - information on s390 devices and the driver model. -kvm.txt - - ioctl calls to /dev/kvm on s390. monreader.txt - information on accessing the z/VM monitor stream from Linux. qeth.txt diff --git a/Documentation/s390/kvm.txt b/Documentation/s390/kvm.txt deleted file mode 100644 index 85f3280d7ef6..000000000000 --- a/Documentation/s390/kvm.txt +++ /dev/null @@ -1,125 +0,0 @@ -*** BIG FAT WARNING *** -The kvm module is currently in EXPERIMENTAL state for s390. This means that -the interface to the module is not yet considered to remain stable. Thus, be -prepared that we keep breaking your userspace application and guest -compatibility over and over again until we feel happy with the result. Make sure -your guest kernel, your host kernel, and your userspace launcher are in a -consistent state. - -This Documentation describes the unique ioctl calls to /dev/kvm, the resulting -kvm-vm file descriptors, and the kvm-vcpu file descriptors that differ from x86. - -1. ioctl calls to /dev/kvm -KVM does support the following ioctls on s390 that are common with other -architectures and do behave the same: -KVM_GET_API_VERSION -KVM_CREATE_VM (*) see note -KVM_CHECK_EXTENSION -KVM_GET_VCPU_MMAP_SIZE - -Notes: -* KVM_CREATE_VM may fail on s390, if the calling process has multiple -threads and has not called KVM_S390_ENABLE_SIE before. - -In addition, on s390 the following architecture specific ioctls are supported: -ioctl: KVM_S390_ENABLE_SIE -args: none -see also: include/linux/kvm.h -This call causes the kernel to switch on PGSTE in the user page table. This -operation is needed in order to run a virtual machine, and it requires the -calling process to be single-threaded. Note that the first call to KVM_CREATE_VM -will implicitly try to switch on PGSTE if the user process has not called -KVM_S390_ENABLE_SIE before. User processes that want to launch multiple threads -before creating a virtual machine have to call KVM_S390_ENABLE_SIE, or will -observe an error calling KVM_CREATE_VM. Switching on PGSTE is a one-time -operation, is not reversible, and will persist over the entire lifetime of -the calling process. It does not have any user-visible effect other than a small -performance penalty. - -2. ioctl calls to the kvm-vm file descriptor -KVM does support the following ioctls on s390 that are common with other -architectures and do behave the same: -KVM_CREATE_VCPU -KVM_SET_USER_MEMORY_REGION (*) see note -KVM_GET_DIRTY_LOG (**) see note - -Notes: -* kvm does only allow exactly one memory slot on s390, which has to start - at guest absolute address zero and at a user address that is aligned on any - page boundary. This hardware "limitation" allows us to have a few unique - optimizations. The memory slot doesn't have to be filled - with memory actually, it may contain sparse holes. That said, with different - user memory layout this does still allow a large flexibility when - doing the guest memory setup. -** KVM_GET_DIRTY_LOG doesn't work properly yet. The user will receive an empty -log. This ioctl call is only needed for guest migration, and we intend to -implement this one in the future. - -In addition, on s390 the following architecture specific ioctls for the kvm-vm -file descriptor are supported: -ioctl: KVM_S390_INTERRUPT -args: struct kvm_s390_interrupt * -see also: include/linux/kvm.h -This ioctl is used to submit a floating interrupt for a virtual machine. -Floating interrupts may be delivered to any virtual cpu in the configuration. -Only some interrupt types defined in include/linux/kvm.h make sense when -submitted as floating interrupts. The following interrupts are not considered -to be useful as floating interrupts, and a call to inject them will result in --EINVAL error code: program interrupts and interprocessor signals. Valid -floating interrupts are: -KVM_S390_INT_VIRTIO -KVM_S390_INT_SERVICE - -3. ioctl calls to the kvm-vcpu file descriptor -KVM does support the following ioctls on s390 that are common with other -architectures and do behave the same: -KVM_RUN -KVM_GET_REGS -KVM_SET_REGS -KVM_GET_SREGS -KVM_SET_SREGS -KVM_GET_FPU -KVM_SET_FPU - -In addition, on s390 the following architecture specific ioctls for the -kvm-vcpu file descriptor are supported: -ioctl: KVM_S390_INTERRUPT -args: struct kvm_s390_interrupt * -see also: include/linux/kvm.h -This ioctl is used to submit an interrupt for a specific virtual cpu. -Only some interrupt types defined in include/linux/kvm.h make sense when -submitted for a specific cpu. The following interrupts are not considered -to be useful, and a call to inject them will result in -EINVAL error code: -service processor calls and virtio interrupts. Valid interrupt types are: -KVM_S390_PROGRAM_INT -KVM_S390_SIGP_STOP -KVM_S390_RESTART -KVM_S390_SIGP_SET_PREFIX -KVM_S390_INT_EMERGENCY - -ioctl: KVM_S390_STORE_STATUS -args: unsigned long -see also: include/linux/kvm.h -This ioctl stores the state of the cpu at the guest real address given as -argument, unless one of the following values defined in include/linux/kvm.h -is given as argument: -KVM_S390_STORE_STATUS_NOADDR - the CPU stores its status to the save area in -absolute lowcore as defined by the principles of operation -KVM_S390_STORE_STATUS_PREFIXED - the CPU stores its status to the save area in -its prefix page just like the dump tool that comes with zipl. This is useful -to create a system dump for use with lkcdutils or crash. - -ioctl: KVM_S390_SET_INITIAL_PSW -args: struct kvm_s390_psw * -see also: include/linux/kvm.h -This ioctl can be used to set the processor status word (psw) of a stopped cpu -prior to running it with KVM_RUN. Note that this call is not required to modify -the psw during sie intercepts that fall back to userspace because struct kvm_run -does contain the psw, and this value is evaluated during reentry of KVM_RUN -after the intercept exit was recognized. - -ioctl: KVM_S390_INITIAL_RESET -args: none -see also: include/linux/kvm.h -This ioctl can be used to perform an initial cpu reset as defined by the -principles of operation. The target cpu has to be in stopped state. -- cgit v1.2.3-59-g8ed1b From 4246a0b63bd8f56a1469b12eafeb875b1041a451 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 20 Jul 2015 15:29:37 +0200 Subject: block: add a bi_error field to struct bio Currently we have two different ways to signal an I/O error on a BIO: (1) by clearing the BIO_UPTODATE flag (2) by returning a Linux errno value to the bi_end_io callback The first one has the drawback of only communicating a single possible error (-EIO), and the second one has the drawback of not beeing persistent when bios are queued up, and are not passed along from child to parent bio in the ever more popular chaining scenario. Having both mechanisms available has the additional drawback of utterly confusing driver authors and introducing bugs where various I/O submitters only deal with one of them, and the others have to add boilerplate code to deal with both kinds of error returns. So add a new bi_error field to store an errno value directly in struct bio and remove the existing mechanisms to clean all this up. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: NeilBrown Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 2 +- arch/m68k/emu/nfblock.c | 2 +- arch/powerpc/sysdev/axonram.c | 2 +- arch/xtensa/platforms/iss/simdisk.c | 12 ++----- block/bio-integrity.c | 11 +++---- block/bio.c | 43 +++++++++++-------------- block/blk-core.c | 15 ++++----- block/blk-lib.c | 30 ++++++++---------- block/blk-map.c | 2 +- block/blk-mq.c | 6 ++-- block/bounce.c | 27 ++++++++-------- drivers/block/aoe/aoecmd.c | 10 +++--- drivers/block/aoe/aoedev.c | 2 +- drivers/block/brd.c | 13 +++++--- drivers/block/drbd/drbd_actlog.c | 4 +-- drivers/block/drbd/drbd_bitmap.c | 19 +++--------- drivers/block/drbd/drbd_int.h | 11 ++++--- drivers/block/drbd/drbd_req.c | 10 +++--- drivers/block/drbd/drbd_worker.c | 44 +++++++------------------- drivers/block/floppy.c | 7 +++-- drivers/block/null_blk.c | 2 +- drivers/block/pktcdvd.c | 32 +++++++++---------- drivers/block/ps3vram.c | 3 +- drivers/block/rsxx/dev.c | 9 ++++-- drivers/block/umem.c | 4 +-- drivers/block/xen-blkback/blkback.c | 4 +-- drivers/block/xen-blkfront.c | 9 ++---- drivers/block/zram/zram_drv.c | 5 ++- drivers/md/bcache/btree.c | 10 +++--- drivers/md/bcache/closure.h | 2 +- drivers/md/bcache/io.c | 8 ++--- drivers/md/bcache/journal.c | 8 ++--- drivers/md/bcache/movinggc.c | 8 ++--- drivers/md/bcache/request.c | 27 ++++++++-------- drivers/md/bcache/super.c | 14 ++++----- drivers/md/bcache/writeback.c | 10 +++--- drivers/md/dm-bio-prison.c | 6 ++-- drivers/md/dm-bufio.c | 26 ++++++++++------ drivers/md/dm-cache-target.c | 24 +++++++------- drivers/md/dm-crypt.c | 14 ++++----- drivers/md/dm-flakey.c | 2 +- drivers/md/dm-io.c | 6 ++-- drivers/md/dm-log-writes.c | 11 +++---- drivers/md/dm-raid1.c | 24 +++++++------- drivers/md/dm-snap.c | 6 ++-- drivers/md/dm-stripe.c | 2 +- drivers/md/dm-thin.c | 41 +++++++++++++----------- drivers/md/dm-verity.c | 9 +++--- drivers/md/dm-zero.c | 2 +- drivers/md/dm.c | 15 +++++---- drivers/md/faulty.c | 4 +-- drivers/md/linear.c | 2 +- drivers/md/md.c | 18 +++++------ drivers/md/multipath.c | 12 +++---- drivers/md/raid0.c | 2 +- drivers/md/raid1.c | 53 ++++++++++++++++--------------- drivers/md/raid10.c | 55 +++++++++++++++----------------- drivers/md/raid5.c | 52 +++++++++++++++---------------- drivers/nvdimm/blk.c | 5 +-- drivers/nvdimm/btt.c | 5 +-- drivers/nvdimm/pmem.c | 2 +- drivers/s390/block/dcssblk.c | 2 +- drivers/s390/block/xpram.c | 3 +- drivers/target/target_core_iblock.c | 21 +++++-------- drivers/target/target_core_pscsi.c | 6 ++-- fs/btrfs/check-integrity.c | 10 +++--- fs/btrfs/compression.c | 24 ++++++++------ fs/btrfs/disk-io.c | 35 +++++++++++---------- fs/btrfs/extent_io.c | 30 +++++++----------- fs/btrfs/inode.c | 50 ++++++++++++++++-------------- fs/btrfs/raid56.c | 62 +++++++++++++++++-------------------- fs/btrfs/scrub.c | 22 ++++++------- fs/btrfs/volumes.c | 23 +++++++------- fs/buffer.c | 4 +-- fs/direct-io.c | 13 ++++---- fs/ext4/page-io.c | 15 ++++----- fs/ext4/readpage.c | 6 ++-- fs/f2fs/data.c | 10 +++--- fs/gfs2/lops.c | 10 +++--- fs/gfs2/ops_fstype.c | 6 ++-- fs/jfs/jfs_logmgr.c | 8 ++--- fs/jfs/jfs_metapage.c | 8 ++--- fs/logfs/dev_bdev.c | 12 +++---- fs/mpage.c | 4 +-- fs/nfs/blocklayout/blocklayout.c | 14 ++++----- fs/nilfs2/segbuf.c | 5 ++- fs/ocfs2/cluster/heartbeat.c | 9 +++--- fs/xfs/xfs_aops.c | 5 ++- fs/xfs/xfs_buf.c | 7 ++--- include/linux/bio.h | 13 +++++--- include/linux/blk_types.h | 4 +-- include/linux/swap.h | 4 +-- kernel/power/swap.c | 12 +++---- kernel/trace/blktrace.c | 10 ++---- mm/page_io.c | 12 +++---- 95 files changed, 622 insertions(+), 682 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index fd12c0d835fd..5be8a7f4cc7f 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -1109,7 +1109,7 @@ it will loop and handle as many sectors (on a bio-segment granularity) as specified. Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the -right thing to use is bio_endio(bio, uptodate) instead. +right thing to use is bio_endio(bio) instead. If the driver is dropping the io_request_lock from its request_fn strategy, then it just needs to replace that with q->queue_lock instead. diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 2d75ae246167..f2a00c591bf7 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -76,7 +76,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio) bvec_to_phys(&bvec)); sec += len; } - bio_endio(bio, 0); + bio_endio(bio); } static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index ee90db17b097..f86250c48b53 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -132,7 +132,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) phys_mem += vec.bv_len; transfered += vec.bv_len; } - bio_endio(bio, 0); + bio_endio(bio); } /** diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c index 48eebacdf5fe..fa84ca990caa 100644 --- a/arch/xtensa/platforms/iss/simdisk.c +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -101,8 +101,9 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector, spin_unlock(&dev->lock); } -static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) +static void simdisk_make_request(struct request_queue *q, struct bio *bio) { + struct simdisk *dev = q->queuedata; struct bio_vec bvec; struct bvec_iter iter; sector_t sector = bio->bi_iter.bi_sector; @@ -116,17 +117,10 @@ static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) sector += len; __bio_kunmap_atomic(buffer); } - return 0; -} -static void simdisk_make_request(struct request_queue *q, struct bio *bio) -{ - struct simdisk *dev = q->queuedata; - int status = simdisk_xfer_bio(dev, bio); - bio_endio(bio, status); + bio_endio(bio); } - static int simdisk_open(struct block_device *bdev, fmode_t mode) { struct simdisk *dev = bdev->bd_disk->private_data; diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 719b7152aed1..4aecca79374a 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -355,13 +355,12 @@ static void bio_integrity_verify_fn(struct work_struct *work) container_of(work, struct bio_integrity_payload, bip_work); struct bio *bio = bip->bip_bio; struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - int error; - error = bio_integrity_process(bio, bi->verify_fn); + bio->bi_error = bio_integrity_process(bio, bi->verify_fn); /* Restore original bio completion handler */ bio->bi_end_io = bip->bip_end_io; - bio_endio(bio, error); + bio_endio(bio); } /** @@ -376,7 +375,7 @@ static void bio_integrity_verify_fn(struct work_struct *work) * in process context. This function postpones completion * accordingly. */ -void bio_integrity_endio(struct bio *bio, int error) +void bio_integrity_endio(struct bio *bio) { struct bio_integrity_payload *bip = bio_integrity(bio); @@ -386,9 +385,9 @@ void bio_integrity_endio(struct bio *bio, int error) * integrity metadata. Restore original bio end_io handler * and run it. */ - if (error) { + if (bio->bi_error) { bio->bi_end_io = bip->bip_end_io; - bio_endio(bio, error); + bio_endio(bio); return; } diff --git a/block/bio.c b/block/bio.c index 2a00d349cd68..a23f489f398f 100644 --- a/block/bio.c +++ b/block/bio.c @@ -269,7 +269,6 @@ static void bio_free(struct bio *bio) void bio_init(struct bio *bio) { memset(bio, 0, sizeof(*bio)); - bio->bi_flags = 1 << BIO_UPTODATE; atomic_set(&bio->__bi_remaining, 1); atomic_set(&bio->__bi_cnt, 1); } @@ -292,14 +291,17 @@ void bio_reset(struct bio *bio) __bio_free(bio); memset(bio, 0, BIO_RESET_BYTES); - bio->bi_flags = flags | (1 << BIO_UPTODATE); + bio->bi_flags = flags; atomic_set(&bio->__bi_remaining, 1); } EXPORT_SYMBOL(bio_reset); -static void bio_chain_endio(struct bio *bio, int error) +static void bio_chain_endio(struct bio *bio) { - bio_endio(bio->bi_private, error); + struct bio *parent = bio->bi_private; + + parent->bi_error = bio->bi_error; + bio_endio(parent); bio_put(bio); } @@ -896,11 +898,11 @@ struct submit_bio_ret { int error; }; -static void submit_bio_wait_endio(struct bio *bio, int error) +static void submit_bio_wait_endio(struct bio *bio) { struct submit_bio_ret *ret = bio->bi_private; - ret->error = error; + ret->error = bio->bi_error; complete(&ret->event); } @@ -1445,7 +1447,7 @@ void bio_unmap_user(struct bio *bio) } EXPORT_SYMBOL(bio_unmap_user); -static void bio_map_kern_endio(struct bio *bio, int err) +static void bio_map_kern_endio(struct bio *bio) { bio_put(bio); } @@ -1501,13 +1503,13 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, } EXPORT_SYMBOL(bio_map_kern); -static void bio_copy_kern_endio(struct bio *bio, int err) +static void bio_copy_kern_endio(struct bio *bio) { bio_free_pages(bio); bio_put(bio); } -static void bio_copy_kern_endio_read(struct bio *bio, int err) +static void bio_copy_kern_endio_read(struct bio *bio) { char *p = bio->bi_private; struct bio_vec *bvec; @@ -1518,7 +1520,7 @@ static void bio_copy_kern_endio_read(struct bio *bio, int err) p += bvec->bv_len; } - bio_copy_kern_endio(bio, err); + bio_copy_kern_endio(bio); } /** @@ -1778,25 +1780,15 @@ static inline bool bio_remaining_done(struct bio *bio) /** * bio_endio - end I/O on a bio * @bio: bio - * @error: error, if any * * Description: - * bio_endio() will end I/O on the whole bio. bio_endio() is the - * preferred way to end I/O on a bio, it takes care of clearing - * BIO_UPTODATE on error. @error is 0 on success, and and one of the - * established -Exxxx (-EIO, for instance) error values in case - * something went wrong. No one should call bi_end_io() directly on a - * bio unless they own it and thus know that it has an end_io - * function. + * bio_endio() will end I/O on the whole bio. bio_endio() is the preferred + * way to end I/O on a bio. No one should call bi_end_io() directly on a + * bio unless they own it and thus know that it has an end_io function. **/ -void bio_endio(struct bio *bio, int error) +void bio_endio(struct bio *bio) { while (bio) { - if (error) - clear_bit(BIO_UPTODATE, &bio->bi_flags); - else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = -EIO; - if (unlikely(!bio_remaining_done(bio))) break; @@ -1810,11 +1802,12 @@ void bio_endio(struct bio *bio, int error) */ if (bio->bi_end_io == bio_chain_endio) { struct bio *parent = bio->bi_private; + parent->bi_error = bio->bi_error; bio_put(bio); bio = parent; } else { if (bio->bi_end_io) - bio->bi_end_io(bio, error); + bio->bi_end_io(bio); bio = NULL; } } diff --git a/block/blk-core.c b/block/blk-core.c index 627ed0c593fb..7ef15b947b91 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -143,9 +143,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, unsigned int nbytes, int error) { if (error) - clear_bit(BIO_UPTODATE, &bio->bi_flags); - else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = -EIO; + bio->bi_error = error; if (unlikely(rq->cmd_flags & REQ_QUIET)) set_bit(BIO_QUIET, &bio->bi_flags); @@ -154,7 +152,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, /* don't actually finish bio if it's part of flush sequence */ if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) - bio_endio(bio, error); + bio_endio(bio); } void blk_dump_rq_flags(struct request *rq, char *msg) @@ -1620,7 +1618,8 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio->bi_error = -EIO; + bio_endio(bio); return; } @@ -1673,7 +1672,8 @@ get_rq: */ req = get_request(q, rw_flags, bio, GFP_NOIO); if (IS_ERR(req)) { - bio_endio(bio, PTR_ERR(req)); /* @q is dead */ + bio->bi_error = PTR_ERR(req); + bio_endio(bio); goto out_unlock; } @@ -1896,7 +1896,8 @@ generic_make_request_checks(struct bio *bio) return true; end_io: - bio_endio(bio, err); + bio->bi_error = err; + bio_endio(bio); return false; } diff --git a/block/blk-lib.c b/block/blk-lib.c index 7688ee3f5d72..6dee17443f14 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -11,16 +11,16 @@ struct bio_batch { atomic_t done; - unsigned long flags; + int error; struct completion *wait; }; -static void bio_batch_end_io(struct bio *bio, int err) +static void bio_batch_end_io(struct bio *bio) { struct bio_batch *bb = bio->bi_private; - if (err && (err != -EOPNOTSUPP)) - clear_bit(BIO_UPTODATE, &bb->flags); + if (bio->bi_error && bio->bi_error != -EOPNOTSUPP) + bb->error = bio->bi_error; if (atomic_dec_and_test(&bb->done)) complete(bb->wait); bio_put(bio); @@ -78,7 +78,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, } atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; blk_start_plug(&plug); @@ -134,9 +134,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - ret = -EIO; - + if (bb.error) + return bb.error; return ret; } EXPORT_SYMBOL(blkdev_issue_discard); @@ -172,7 +171,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, return -EOPNOTSUPP; atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; while (nr_sects) { @@ -208,9 +207,8 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - ret = -ENOTSUPP; - + if (bb.error) + return bb.error; return ret; } EXPORT_SYMBOL(blkdev_issue_write_same); @@ -236,7 +234,7 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, DECLARE_COMPLETION_ONSTACK(wait); atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; ret = 0; @@ -270,10 +268,8 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - /* One of bios in the batch was completed with error.*/ - ret = -EIO; - + if (bb.error) + return bb.error; return ret; } diff --git a/block/blk-map.c b/block/blk-map.c index da310a105429..5fe1c30bfba7 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -103,7 +103,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, * normal IO completion path */ bio_get(bio); - bio_endio(bio, 0); + bio_endio(bio); __blk_rq_unmap_user(bio); return -EINVAL; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 7d842db59699..94559025c5e6 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1199,7 +1199,7 @@ static struct request *blk_mq_map_request(struct request_queue *q, struct blk_mq_alloc_data alloc_data; if (unlikely(blk_mq_queue_enter(q, GFP_KERNEL))) { - bio_endio(bio, -EIO); + bio_io_error(bio); return NULL; } @@ -1283,7 +1283,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } @@ -1368,7 +1368,7 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } diff --git a/block/bounce.c b/block/bounce.c index b17311227c12..f4db245b9f3a 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -123,7 +123,7 @@ static void copy_to_high_bio_irq(struct bio *to, struct bio *from) } } -static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) +static void bounce_end_io(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; struct bio_vec *bvec, *org_vec; @@ -141,39 +141,40 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) mempool_free(bvec->bv_page, pool); } - bio_endio(bio_orig, err); + bio_orig->bi_error = bio->bi_error; + bio_endio(bio_orig); bio_put(bio); } -static void bounce_end_io_write(struct bio *bio, int err) +static void bounce_end_io_write(struct bio *bio) { - bounce_end_io(bio, page_pool, err); + bounce_end_io(bio, page_pool); } -static void bounce_end_io_write_isa(struct bio *bio, int err) +static void bounce_end_io_write_isa(struct bio *bio) { - bounce_end_io(bio, isa_page_pool, err); + bounce_end_io(bio, isa_page_pool); } -static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) +static void __bounce_end_io_read(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) copy_to_high_bio_irq(bio_orig, bio); - bounce_end_io(bio, pool, err); + bounce_end_io(bio, pool); } -static void bounce_end_io_read(struct bio *bio, int err) +static void bounce_end_io_read(struct bio *bio) { - __bounce_end_io_read(bio, page_pool, err); + __bounce_end_io_read(bio, page_pool); } -static void bounce_end_io_read_isa(struct bio *bio, int err) +static void bounce_end_io_read_isa(struct bio *bio) { - __bounce_end_io_read(bio, isa_page_pool, err); + __bounce_end_io_read(bio, isa_page_pool); } #ifdef CONFIG_NEED_BOUNCE_POOL diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 422b7d84f686..ad80c85e0857 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1110,7 +1110,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) d->ip.rq = NULL; do { bio = rq->bio; - bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); + bok = !fastfail && !bio->bi_error; } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size)); /* cf. http://lkml.org/lkml/2006/10/31/28 */ @@ -1172,7 +1172,7 @@ ktiocomplete(struct frame *f) ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); noskb: if (buf) - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; goto out; } @@ -1185,7 +1185,7 @@ noskb: if (buf) "aoe: runt data size in read from", (long) d->aoemajor, d->aoeminor, skb->len, n); - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; break; } if (n > f->iter.bi_size) { @@ -1193,7 +1193,7 @@ noskb: if (buf) "aoe: too-large data size in read from", (long) d->aoemajor, d->aoeminor, n, f->iter.bi_size); - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; break; } bvcpy(skb, f->buf->bio, f->iter, n); @@ -1695,7 +1695,7 @@ aoe_failbuf(struct aoedev *d, struct buf *buf) if (buf == NULL) return; buf->iter.bi_size = 0; - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; if (buf->nframesout == 0) aoe_end_buf(d, buf); } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index e774c50b6842..ffd1947500c6 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -170,7 +170,7 @@ aoe_failip(struct aoedev *d) if (rq == NULL) return; while ((bio = d->ip.nxbio)) { - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; d->ip.nxbio = bio->bi_next; n = (unsigned long) rq->special; rq->special = (void *) --n; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index e573e470bd8a..f9ab74505e69 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -331,14 +331,12 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) struct bio_vec bvec; sector_t sector; struct bvec_iter iter; - int err = -EIO; sector = bio->bi_iter.bi_sector; if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) - goto out; + goto io_error; if (unlikely(bio->bi_rw & REQ_DISCARD)) { - err = 0; discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } @@ -349,15 +347,20 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) bio_for_each_segment(bvec, bio, iter) { unsigned int len = bvec.bv_len; + int err; + err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset, rw, sector); if (err) - break; + goto io_error; sector += len >> SECTOR_SHIFT; } out: - bio_endio(bio, err); + bio_endio(bio); + return; +io_error: + bio_io_error(bio); } static int brd_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 1318e3217cb0..b3868e7a1ffd 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -175,11 +175,11 @@ static int _drbd_md_sync_page_io(struct drbd_device *device, atomic_inc(&device->md_io.in_use); /* drbd_md_put_buffer() is in the completion handler */ device->md_io.submit_jif = jiffies; if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) - bio_endio(bio, -EIO); + bio_io_error(bio); else submit_bio(rw, bio); wait_until_done_or_force_detached(device, bdev, &device->md_io.done); - if (bio_flagged(bio, BIO_UPTODATE)) + if (!bio->bi_error) err = device->md_io.error; out: diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 434c77dcc99e..e5e0f19ceda0 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -941,36 +941,27 @@ static void drbd_bm_aio_ctx_destroy(struct kref *kref) } /* bv_page may be a copy, or may be the original */ -static void drbd_bm_endio(struct bio *bio, int error) +static void drbd_bm_endio(struct bio *bio) { struct drbd_bm_aio_ctx *ctx = bio->bi_private; struct drbd_device *device = ctx->device; struct drbd_bitmap *b = device->bitmap; unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page); - int uptodate = bio_flagged(bio, BIO_UPTODATE); - - - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! - * do we want to WARN() on this? */ - if (!error && !uptodate) - error = -EIO; if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 && !bm_test_page_unchanged(b->bm_pages[idx])) drbd_warn(device, "bitmap page idx %u changed during IO!\n", idx); - if (error) { + if (bio->bi_error) { /* ctx error will hold the completed-last non-zero error code, * in case error codes differ. */ - ctx->error = error; + ctx->error = bio->bi_error; bm_set_page_io_err(b->bm_pages[idx]); /* Not identical to on disk version of it. * Is BM_PAGE_IO_ERROR enough? */ if (__ratelimit(&drbd_ratelimit_state)) drbd_err(device, "IO ERROR %d on bitmap page idx %u\n", - error, idx); + bio->bi_error, idx); } else { bm_clear_page_io_err(b->bm_pages[idx]); dynamic_drbd_dbg(device, "bitmap page idx %u completed\n", idx); @@ -1031,7 +1022,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { bio->bi_rw |= rw; - bio_endio(bio, -EIO); + bio_io_error(bio); } else { submit_bio(rw, bio); /* this should not count as user activity and cause the diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index efd19c2da9c2..a08c4a9179f1 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1481,9 +1481,9 @@ extern int drbd_khelper(struct drbd_device *device, char *cmd); /* drbd_worker.c */ /* bi_end_io handlers */ -extern void drbd_md_endio(struct bio *bio, int error); -extern void drbd_peer_request_endio(struct bio *bio, int error); -extern void drbd_request_endio(struct bio *bio, int error); +extern void drbd_md_endio(struct bio *bio); +extern void drbd_peer_request_endio(struct bio *bio); +extern void drbd_request_endio(struct bio *bio); extern int drbd_worker(struct drbd_thread *thi); enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor); void drbd_resync_after_changed(struct drbd_device *device); @@ -1604,12 +1604,13 @@ static inline void drbd_generic_make_request(struct drbd_device *device, __release(local); if (!bio->bi_bdev) { drbd_err(device, "drbd_generic_make_request: bio->bi_bdev == NULL\n"); - bio_endio(bio, -ENODEV); + bio->bi_error = -ENODEV; + bio_endio(bio); return; } if (drbd_insert_fault(device, fault_type)) - bio_endio(bio, -EIO); + bio_io_error(bio); else generic_make_request(bio); } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3907202fb9d9..9cb41166366e 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -201,7 +201,8 @@ void start_new_tl_epoch(struct drbd_connection *connection) void complete_master_bio(struct drbd_device *device, struct bio_and_error *m) { - bio_endio(m->bio, m->error); + m->bio->bi_error = m->error; + bio_endio(m->bio); dec_ap_bio(device); } @@ -1153,12 +1154,12 @@ drbd_submit_req_private_bio(struct drbd_request *req) rw == WRITE ? DRBD_FAULT_DT_WR : rw == READ ? DRBD_FAULT_DT_RD : DRBD_FAULT_DT_RA)) - bio_endio(bio, -EIO); + bio_io_error(bio); else generic_make_request(bio); put_ldev(device); } else - bio_endio(bio, -EIO); + bio_io_error(bio); } static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req) @@ -1191,7 +1192,8 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long /* only pass the error to the upper layers. * if user cannot handle io errors, that's not our business. */ drbd_err(device, "could not kmalloc() req\n"); - bio_endio(bio, -ENOMEM); + bio->bi_error = -ENOMEM; + bio_endio(bio); return ERR_PTR(-ENOMEM); } req->start_jif = start_jif; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index d0fae55d871d..5578c1477ba6 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -65,12 +65,12 @@ rwlock_t global_state_lock; /* used for synchronous meta data and bitmap IO * submitted by drbd_md_sync_page_io() */ -void drbd_md_endio(struct bio *bio, int error) +void drbd_md_endio(struct bio *bio) { struct drbd_device *device; device = bio->bi_private; - device->md_io.error = error; + device->md_io.error = bio->bi_error; /* We grabbed an extra reference in _drbd_md_sync_page_io() to be able * to timeout on the lower level device, and eventually detach from it. @@ -170,31 +170,20 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver. */ -void drbd_peer_request_endio(struct bio *bio, int error) +void drbd_peer_request_endio(struct bio *bio) { struct drbd_peer_request *peer_req = bio->bi_private; struct drbd_device *device = peer_req->peer_device->device; - int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; int is_discard = !!(bio->bi_rw & REQ_DISCARD); - if (error && __ratelimit(&drbd_ratelimit_state)) + if (bio->bi_error && __ratelimit(&drbd_ratelimit_state)) drbd_warn(device, "%s: error=%d s=%llus\n", is_write ? (is_discard ? "discard" : "write") - : "read", error, + : "read", bio->bi_error, (unsigned long long)peer_req->i.sector); - if (!error && !uptodate) { - if (__ratelimit(&drbd_ratelimit_state)) - drbd_warn(device, "%s: setting error to -EIO s=%llus\n", - is_write ? "write" : "read", - (unsigned long long)peer_req->i.sector); - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! */ - error = -EIO; - } - if (error) + if (bio->bi_error) set_bit(__EE_WAS_ERROR, &peer_req->flags); bio_put(bio); /* no need for the bio anymore */ @@ -208,24 +197,13 @@ void drbd_peer_request_endio(struct bio *bio, int error) /* read, readA or write requests on R_PRIMARY coming from drbd_make_request */ -void drbd_request_endio(struct bio *bio, int error) +void drbd_request_endio(struct bio *bio) { unsigned long flags; struct drbd_request *req = bio->bi_private; struct drbd_device *device = req->device; struct bio_and_error m; enum drbd_req_event what; - int uptodate = bio_flagged(bio, BIO_UPTODATE); - - if (!error && !uptodate) { - drbd_warn(device, "p %s: setting error to -EIO\n", - bio_data_dir(bio) == WRITE ? "write" : "read"); - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! */ - error = -EIO; - } - /* If this request was aborted locally before, * but now was completed "successfully", @@ -259,14 +237,14 @@ void drbd_request_endio(struct bio *bio, int error) if (__ratelimit(&drbd_ratelimit_state)) drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n"); - if (!error) + if (!bio->bi_error) panic("possible random memory corruption caused by delayed completion of aborted local request\n"); } /* to avoid recursion in __req_mod */ - if (unlikely(error)) { + if (unlikely(bio->bi_error)) { if (bio->bi_rw & REQ_DISCARD) - what = (error == -EOPNOTSUPP) + what = (bio->bi_error == -EOPNOTSUPP) ? DISCARD_COMPLETED_NOTSUPP : DISCARD_COMPLETED_WITH_ERROR; else @@ -279,7 +257,7 @@ void drbd_request_endio(struct bio *bio, int error) what = COMPLETED_OK; bio_put(req->private_bio); - req->private_bio = ERR_PTR(error); + req->private_bio = ERR_PTR(bio->bi_error); /* not req_mod(), we need irqsave here! */ spin_lock_irqsave(&device->resource->req_lock, flags); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a08cda955285..331363e7de0f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3771,13 +3771,14 @@ struct rb0_cbdata { struct completion complete; }; -static void floppy_rb0_cb(struct bio *bio, int err) +static void floppy_rb0_cb(struct bio *bio) { struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private; int drive = cbdata->drive; - if (err) { - pr_info("floppy: error %d while reading block 0\n", err); + if (bio->bi_error) { + pr_info("floppy: error %d while reading block 0\n", + bio->bi_error); set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); } complete(&cbdata->complete); diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 69de41a87b74..016a59afcf24 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -222,7 +222,7 @@ static void end_cmd(struct nullb_cmd *cmd) blk_end_request_all(cmd->rq, 0); break; case NULL_Q_BIO: - bio_endio(cmd->bio, 0); + bio_endio(cmd->bio); break; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 4c20c228184c..a7a259e031da 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -977,7 +977,7 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) } } -static void pkt_end_io_read(struct bio *bio, int err) +static void pkt_end_io_read(struct bio *bio) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; @@ -985,9 +985,9 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, - (unsigned long long)bio->bi_iter.bi_sector, err); + (unsigned long long)bio->bi_iter.bi_sector, bio->bi_error); - if (err) + if (bio->bi_error) atomic_inc(&pkt->io_errors); if (atomic_dec_and_test(&pkt->io_wait)) { atomic_inc(&pkt->run_sm); @@ -996,13 +996,13 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_bio_finished(pd); } -static void pkt_end_io_packet_write(struct bio *bio, int err) +static void pkt_end_io_packet_write(struct bio *bio) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, err); + pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, bio->bi_error); pd->stats.pkt_ended++; @@ -1340,22 +1340,22 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) pkt_queue_bio(pd, pkt->w_bio); } -static void pkt_finish_packet(struct packet_data *pkt, int uptodate) +static void pkt_finish_packet(struct packet_data *pkt, int error) { struct bio *bio; - if (!uptodate) + if (error) pkt->cache_valid = 0; /* Finish all bios corresponding to this packet */ - while ((bio = bio_list_pop(&pkt->orig_bios))) - bio_endio(bio, uptodate ? 0 : -EIO); + while ((bio = bio_list_pop(&pkt->orig_bios))) { + bio->bi_error = error; + bio_endio(bio); + } } static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt) { - int uptodate; - pkt_dbg(2, pd, "pkt %d\n", pkt->id); for (;;) { @@ -1384,7 +1384,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data if (atomic_read(&pkt->io_wait) > 0) return; - if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) { + if (!pkt->w_bio->bi_error) { pkt_set_state(pkt, PACKET_FINISHED_STATE); } else { pkt_set_state(pkt, PACKET_RECOVERY_STATE); @@ -1401,8 +1401,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data break; case PACKET_FINISHED_STATE: - uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags); - pkt_finish_packet(pkt, uptodate); + pkt_finish_packet(pkt, pkt->w_bio->bi_error); return; default: @@ -2332,13 +2331,14 @@ static void pkt_close(struct gendisk *disk, fmode_t mode) } -static void pkt_end_io_read_cloned(struct bio *bio, int err) +static void pkt_end_io_read_cloned(struct bio *bio) { struct packet_stacked_data *psd = bio->bi_private; struct pktcdvd_device *pd = psd->pd; + psd->bio->bi_error = bio->bi_error; bio_put(bio); - bio_endio(psd->bio, err); + bio_endio(psd->bio); mempool_free(psd, psd_pool); pkt_bio_finished(pd); } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index b1612eb16172..49b4706b162c 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -593,7 +593,8 @@ out: next = bio_list_peek(&priv->list); spin_unlock_irq(&priv->lock); - bio_endio(bio, error); + bio->bi_error = error; + bio_endio(bio); return next; } diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index ac8c62cb4875..63b9d2ffa8ee 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -137,7 +137,10 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card, if (!card->eeh_state && card->gendisk) disk_stats_complete(card, meta->bio, meta->start_time); - bio_endio(meta->bio, atomic_read(&meta->error) ? -EIO : 0); + if (atomic_read(&meta->error)) + bio_io_error(meta->bio); + else + bio_endio(meta->bio); kmem_cache_free(bio_meta_pool, meta); } } @@ -199,7 +202,9 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) queue_err: kmem_cache_free(bio_meta_pool, bio_meta); req_err: - bio_endio(bio, st); + if (st) + bio->bi_error = st; + bio_endio(bio); } /*----------------- Device Setup -------------------*/ diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 4cf81b5bf0f7..3b3afd2ec5d6 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -456,7 +456,7 @@ static void process_page(unsigned long data) PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (control & DMASCR_HARD_ERROR) { /* error */ - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; dev_printk(KERN_WARNING, &card->dev->dev, "I/O error on sector %d/%d\n", le32_to_cpu(desc->local_addr)>>9, @@ -505,7 +505,7 @@ static void process_page(unsigned long data) return_bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, 0); + bio_endio(bio); } } diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index ced96777b677..662648e08596 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1078,9 +1078,9 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) /* * bio callback. */ -static void end_block_io_op(struct bio *bio, int error) +static void end_block_io_op(struct bio *bio) { - __end_block_io_op(bio->bi_private, error); + __end_block_io_op(bio->bi_private, bio->bi_error); bio_put(bio); } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6d89ed35d80c..d542db7a6c73 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -82,7 +82,6 @@ struct blk_shadow { struct split_bio { struct bio *bio; atomic_t pending; - int err; }; static DEFINE_MUTEX(blkfront_mutex); @@ -1478,16 +1477,14 @@ static int blkfront_probe(struct xenbus_device *dev, return 0; } -static void split_bio_end(struct bio *bio, int error) +static void split_bio_end(struct bio *bio) { struct split_bio *split_bio = bio->bi_private; - if (error) - split_bio->err = error; - if (atomic_dec_and_test(&split_bio->pending)) { split_bio->bio->bi_phys_segments = 0; - bio_endio(split_bio->bio, split_bio->err); + split_bio->bio->bi_error = bio->bi_error; + bio_endio(split_bio->bio); kfree(split_bio); } bio_put(bio); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f439ad2800da..68c3d4800464 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -850,7 +850,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) if (unlikely(bio->bi_rw & REQ_DISCARD)) { zram_bio_discard(zram, index, offset, bio); - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -883,8 +883,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) update_position(&index, &offset, &bvec); } - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); + bio_endio(bio); return; out: diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 00cde40db572..83392f856dfd 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -278,7 +278,7 @@ err: goto out; } -static void btree_node_read_endio(struct bio *bio, int error) +static void btree_node_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; closure_put(cl); @@ -305,7 +305,7 @@ static void bch_btree_node_read(struct btree *b) bch_submit_bbio(bio, b->c, &b->key, 0); closure_sync(&cl); - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (bio->bi_error) set_btree_node_io_error(b); bch_bbio_free(bio, b->c); @@ -371,15 +371,15 @@ static void btree_node_write_done(struct closure *cl) __btree_node_write_done(cl); } -static void btree_node_write_endio(struct bio *bio, int error) +static void btree_node_write_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct btree *b = container_of(cl, struct btree, io); - if (error) + if (bio->bi_error) set_btree_node_io_error(b); - bch_bbio_count_io_errors(b->c, bio, error, "writing btree"); + bch_bbio_count_io_errors(b->c, bio, bio->bi_error, "writing btree"); closure_put(cl); } diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index 79a6d63e8ed3..782cc2c8a185 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h @@ -38,7 +38,7 @@ * they are running owned by the thread that is running them. Otherwise, suppose * you submit some bios and wish to have a function run when they all complete: * - * foo_endio(struct bio *bio, int error) + * foo_endio(struct bio *bio) * { * closure_put(cl); * } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index bf6a9ca18403..9440df94bc83 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -55,19 +55,19 @@ static void bch_bio_submit_split_done(struct closure *cl) s->bio->bi_end_io = s->bi_end_io; s->bio->bi_private = s->bi_private; - bio_endio(s->bio, 0); + bio_endio(s->bio); closure_debug_destroy(&s->cl); mempool_free(s, s->p->bio_split_hook); } -static void bch_bio_submit_split_endio(struct bio *bio, int error) +static void bch_bio_submit_split_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl); - if (error) - clear_bit(BIO_UPTODATE, &s->bio->bi_flags); + if (bio->bi_error) + s->bio->bi_error = bio->bi_error; bio_put(bio); closure_put(cl); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 418607a6ba33..d6a4e16030a6 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -24,7 +24,7 @@ * bit. */ -static void journal_read_endio(struct bio *bio, int error) +static void journal_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; closure_put(cl); @@ -401,7 +401,7 @@ retry: #define last_seq(j) ((j)->seq - fifo_used(&(j)->pin) + 1) -static void journal_discard_endio(struct bio *bio, int error) +static void journal_discard_endio(struct bio *bio) { struct journal_device *ja = container_of(bio, struct journal_device, discard_bio); @@ -547,11 +547,11 @@ void bch_journal_next(struct journal *j) pr_debug("journal_pin full (%zu)", fifo_used(&j->pin)); } -static void journal_write_endio(struct bio *bio, int error) +static void journal_write_endio(struct bio *bio) { struct journal_write *w = bio->bi_private; - cache_set_err_on(error, w->c, "journal io error"); + cache_set_err_on(bio->bi_error, w->c, "journal io error"); closure_put(&w->c->journal.io); } diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index cd7490311e51..b929fc944e9c 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -60,20 +60,20 @@ static void write_moving_finish(struct closure *cl) closure_return_with_destructor(cl, moving_io_destructor); } -static void read_moving_endio(struct bio *bio, int error) +static void read_moving_endio(struct bio *bio) { struct bbio *b = container_of(bio, struct bbio, bio); struct moving_io *io = container_of(bio->bi_private, struct moving_io, cl); - if (error) - io->op.error = error; + if (bio->bi_error) + io->op.error = bio->bi_error; else if (!KEY_DIRTY(&b->key) && ptr_stale(io->op.c, &b->key, 0)) { io->op.error = -EINTR; } - bch_bbio_endio(io->op.c, bio, error, "reading data to move"); + bch_bbio_endio(io->op.c, bio, bio->bi_error, "reading data to move"); } static void moving_init(struct moving_io *io) diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index f292790997d7..a09b9462ff49 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -173,22 +173,22 @@ static void bch_data_insert_error(struct closure *cl) bch_data_insert_keys(cl); } -static void bch_data_insert_endio(struct bio *bio, int error) +static void bch_data_insert_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); - if (error) { + if (bio->bi_error) { /* TODO: We could try to recover from this. */ if (op->writeback) - op->error = error; + op->error = bio->bi_error; else if (!op->replace) set_closure_fn(cl, bch_data_insert_error, op->wq); else set_closure_fn(cl, NULL, NULL); } - bch_bbio_endio(op->c, bio, error, "writing data to cache"); + bch_bbio_endio(op->c, bio, bio->bi_error, "writing data to cache"); } static void bch_data_insert_start(struct closure *cl) @@ -477,7 +477,7 @@ struct search { struct data_insert_op iop; }; -static void bch_cache_read_endio(struct bio *bio, int error) +static void bch_cache_read_endio(struct bio *bio) { struct bbio *b = container_of(bio, struct bbio, bio); struct closure *cl = bio->bi_private; @@ -490,15 +490,15 @@ static void bch_cache_read_endio(struct bio *bio, int error) * from the backing device. */ - if (error) - s->iop.error = error; + if (bio->bi_error) + s->iop.error = bio->bi_error; else if (!KEY_DIRTY(&b->key) && ptr_stale(s->iop.c, &b->key, 0)) { atomic_long_inc(&s->iop.c->cache_read_races); s->iop.error = -EINTR; } - bch_bbio_endio(s->iop.c, bio, error, "reading from cache"); + bch_bbio_endio(s->iop.c, bio, bio->bi_error, "reading from cache"); } /* @@ -591,13 +591,13 @@ static void cache_lookup(struct closure *cl) /* Common code for the make_request functions */ -static void request_endio(struct bio *bio, int error) +static void request_endio(struct bio *bio) { struct closure *cl = bio->bi_private; - if (error) { + if (bio->bi_error) { struct search *s = container_of(cl, struct search, cl); - s->iop.error = error; + s->iop.error = bio->bi_error; /* Only cache read errors are recoverable */ s->recoverable = false; } @@ -613,7 +613,8 @@ static void bio_complete(struct search *s) &s->d->disk->part0, s->start_time); trace_bcache_request_end(s->d, s->orig_bio); - bio_endio(s->orig_bio, s->iop.error); + s->orig_bio->bi_error = s->iop.error; + bio_endio(s->orig_bio); s->orig_bio = NULL; } } @@ -992,7 +993,7 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio) } else { if ((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(dc->bdev))) - bio_endio(bio, 0); + bio_endio(bio); else bch_generic_make_request(bio, &d->bio_split_hook); } diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index fc8e545ced18..be01fd3c87f1 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -221,7 +221,7 @@ err: return err; } -static void write_bdev_super_endio(struct bio *bio, int error) +static void write_bdev_super_endio(struct bio *bio) { struct cached_dev *dc = bio->bi_private; /* XXX: error checking */ @@ -290,11 +290,11 @@ void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent) closure_return_with_destructor(cl, bch_write_bdev_super_unlock); } -static void write_super_endio(struct bio *bio, int error) +static void write_super_endio(struct bio *bio) { struct cache *ca = bio->bi_private; - bch_count_io_errors(ca, error, "writing superblock"); + bch_count_io_errors(ca, bio->bi_error, "writing superblock"); closure_put(&ca->set->sb_write); } @@ -339,12 +339,12 @@ void bcache_write_super(struct cache_set *c) /* UUID io */ -static void uuid_endio(struct bio *bio, int error) +static void uuid_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct cache_set *c = container_of(cl, struct cache_set, uuid_write); - cache_set_err_on(error, c, "accessing uuids"); + cache_set_err_on(bio->bi_error, c, "accessing uuids"); bch_bbio_free(bio, c); closure_put(cl); } @@ -512,11 +512,11 @@ static struct uuid_entry *uuid_find_empty(struct cache_set *c) * disk. */ -static void prio_endio(struct bio *bio, int error) +static void prio_endio(struct bio *bio) { struct cache *ca = bio->bi_private; - cache_set_err_on(error, ca->set, "accessing priorities"); + cache_set_err_on(bio->bi_error, ca->set, "accessing priorities"); bch_bbio_free(bio, ca->set); closure_put(&ca->prio); } diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index f1986bcd1bf0..b4fc874c30fd 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -166,12 +166,12 @@ static void write_dirty_finish(struct closure *cl) closure_return_with_destructor(cl, dirty_io_destructor); } -static void dirty_endio(struct bio *bio, int error) +static void dirty_endio(struct bio *bio) { struct keybuf_key *w = bio->bi_private; struct dirty_io *io = w->private; - if (error) + if (bio->bi_error) SET_KEY_DIRTY(&w->key, false); closure_put(&io->cl); @@ -193,15 +193,15 @@ static void write_dirty(struct closure *cl) continue_at(cl, write_dirty_finish, system_wq); } -static void read_dirty_endio(struct bio *bio, int error) +static void read_dirty_endio(struct bio *bio) { struct keybuf_key *w = bio->bi_private; struct dirty_io *io = w->private; bch_count_io_errors(PTR_CACHE(io->dc->disk.c, &w->key, 0), - error, "reading dirty data from cache"); + bio->bi_error, "reading dirty data from cache"); - dirty_endio(bio, error); + dirty_endio(bio); } static void read_dirty_submit(struct closure *cl) diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c index cd6d1d21e057..03af174485d3 100644 --- a/drivers/md/dm-bio-prison.c +++ b/drivers/md/dm-bio-prison.c @@ -236,8 +236,10 @@ void dm_cell_error(struct dm_bio_prison *prison, bio_list_init(&bios); dm_cell_release(prison, cell, &bios); - while ((bio = bio_list_pop(&bios))) - bio_endio(bio, error); + while ((bio = bio_list_pop(&bios))) { + bio->bi_error = error; + bio_endio(bio); + } } EXPORT_SYMBOL_GPL(dm_cell_error); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 86dbbc737402..83cc52eaf56d 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -545,7 +545,8 @@ static void dmio_complete(unsigned long error, void *context) { struct dm_buffer *b = context; - b->bio.bi_end_io(&b->bio, error ? -EIO : 0); + b->bio.bi_error = error ? -EIO : 0; + b->bio.bi_end_io(&b->bio); } static void use_dmio(struct dm_buffer *b, int rw, sector_t block, @@ -575,13 +576,16 @@ static void use_dmio(struct dm_buffer *b, int rw, sector_t block, b->bio.bi_end_io = end_io; r = dm_io(&io_req, 1, ®ion, NULL); - if (r) - end_io(&b->bio, r); + if (r) { + b->bio.bi_error = r; + end_io(&b->bio); + } } -static void inline_endio(struct bio *bio, int error) +static void inline_endio(struct bio *bio) { bio_end_io_t *end_fn = bio->bi_private; + int error = bio->bi_error; /* * Reset the bio to free any attached resources @@ -589,7 +593,8 @@ static void inline_endio(struct bio *bio, int error) */ bio_reset(bio); - end_fn(bio, error); + bio->bi_error = error; + end_fn(bio); } static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, @@ -661,13 +666,14 @@ static void submit_io(struct dm_buffer *b, int rw, sector_t block, * Set the error, clear B_WRITING bit and wake anyone who was waiting on * it. */ -static void write_endio(struct bio *bio, int error) +static void write_endio(struct bio *bio) { struct dm_buffer *b = container_of(bio, struct dm_buffer, bio); - b->write_error = error; - if (unlikely(error)) { + b->write_error = bio->bi_error; + if (unlikely(bio->bi_error)) { struct dm_bufio_client *c = b->c; + int error = bio->bi_error; (void)cmpxchg(&c->async_write_error, 0, error); } @@ -1026,11 +1032,11 @@ found_buffer: * The endio routine for reading: set the error, clear the bit and wake up * anyone waiting on the buffer. */ -static void read_endio(struct bio *bio, int error) +static void read_endio(struct bio *bio) { struct dm_buffer *b = container_of(bio, struct dm_buffer, bio); - b->read_error = error; + b->read_error = bio->bi_error; BUG_ON(!test_bit(B_READING, &b->state)); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1b4e1756b169..04d0dadc48b1 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -919,14 +919,14 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio) wake_worker(cache); } -static void writethrough_endio(struct bio *bio, int err) +static void writethrough_endio(struct bio *bio) { struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT); dm_unhook_bio(&pb->hook_info, bio); - if (err) { - bio_endio(bio, err); + if (bio->bi_error) { + bio_endio(bio); return; } @@ -1231,7 +1231,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) * The block was promoted via an overwrite, so it's dirty. */ set_dirty(cache, mg->new_oblock, mg->cblock); - bio_endio(mg->new_ocell->holder, 0); + bio_endio(mg->new_ocell->holder); cell_defer(cache, mg->new_ocell, false); } free_io_migration(mg); @@ -1284,7 +1284,7 @@ static void issue_copy(struct dm_cache_migration *mg) } } -static void overwrite_endio(struct bio *bio, int err) +static void overwrite_endio(struct bio *bio) { struct dm_cache_migration *mg = bio->bi_private; struct cache *cache = mg->cache; @@ -1294,7 +1294,7 @@ static void overwrite_endio(struct bio *bio, int err) dm_unhook_bio(&pb->hook_info, bio); - if (err) + if (bio->bi_error) mg->err = true; mg->requeue_holder = false; @@ -1358,7 +1358,7 @@ static void issue_discard(struct dm_cache_migration *mg) b = to_dblock(from_dblock(b) + 1); } - bio_endio(bio, 0); + bio_endio(bio); cell_defer(mg->cache, mg->new_ocell, false); free_migration(mg); } @@ -1631,7 +1631,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs, calc_discard_block_range(cache, bio, &b, &e); if (b == e) { - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -2213,8 +2213,10 @@ static void requeue_deferred_bios(struct cache *cache) bio_list_merge(&bios, &cache->deferred_bios); bio_list_init(&cache->deferred_bios); - while ((bio = bio_list_pop(&bios))) - bio_endio(bio, DM_ENDIO_REQUEUE); + while ((bio = bio_list_pop(&bios))) { + bio->bi_error = DM_ENDIO_REQUEUE; + bio_endio(bio); + } } static int more_work(struct cache *cache) @@ -3119,7 +3121,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio) * This is a duplicate writethrough io that is no * longer needed because the block has been demoted. */ - bio_endio(bio, 0); + bio_endio(bio); // FIXME: remap everything as a miss cell_defer(cache, cell, false); r = DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 0f48fed44a17..744b80c608e5 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1076,7 +1076,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io) if (io->ctx.req) crypt_free_req(cc, io->ctx.req, base_bio); - bio_endio(base_bio, error); + base_bio->bi_error = error; + bio_endio(base_bio); } /* @@ -1096,15 +1097,12 @@ static void crypt_dec_pending(struct dm_crypt_io *io) * The work is done per CPU global for all dm-crypt instances. * They should not depend on each other and do not block. */ -static void crypt_endio(struct bio *clone, int error) +static void crypt_endio(struct bio *clone) { struct dm_crypt_io *io = clone->bi_private; struct crypt_config *cc = io->cc; unsigned rw = bio_data_dir(clone); - if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error)) - error = -EIO; - /* * free the processed pages */ @@ -1113,13 +1111,13 @@ static void crypt_endio(struct bio *clone, int error) bio_put(clone); - if (rw == READ && !error) { + if (rw == READ && !clone->bi_error) { kcryptd_queue_crypt(io); return; } - if (unlikely(error)) - io->error = error; + if (unlikely(clone->bi_error)) + io->error = clone->bi_error; crypt_dec_pending(io); } diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index b257e46876d3..04481247aab8 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -296,7 +296,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio) * Drop writes? */ if (test_bit(DROP_WRITES, &fc->flags)) { - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 74adcd2c967e..efc6659f9d6a 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -134,12 +134,12 @@ static void dec_count(struct io *io, unsigned int region, int error) complete_io(io); } -static void endio(struct bio *bio, int error) +static void endio(struct bio *bio) { struct io *io; unsigned region; - if (error && bio_data_dir(bio) == READ) + if (bio->bi_error && bio_data_dir(bio) == READ) zero_fill_bio(bio); /* @@ -149,7 +149,7 @@ static void endio(struct bio *bio, int error) bio_put(bio); - dec_count(io, region, error); + dec_count(io, region, bio->bi_error); } /*----------------------------------------------------------------- diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index ad1b049ae2ab..e9d17488d5e3 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -146,16 +146,16 @@ static void put_io_block(struct log_writes_c *lc) } } -static void log_end_io(struct bio *bio, int err) +static void log_end_io(struct bio *bio) { struct log_writes_c *lc = bio->bi_private; struct bio_vec *bvec; int i; - if (err) { + if (bio->bi_error) { unsigned long flags; - DMERR("Error writing log block, error=%d", err); + DMERR("Error writing log block, error=%d", bio->bi_error); spin_lock_irqsave(&lc->blocks_lock, flags); lc->logging_enabled = false; spin_unlock_irqrestore(&lc->blocks_lock, flags); @@ -205,7 +205,6 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); page = alloc_page(GFP_KERNEL); if (!page) { @@ -270,7 +269,6 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); for (i = 0; i < block->vec_cnt; i++) { /* @@ -292,7 +290,6 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); ret = bio_add_page(bio, block->vecs[i].bv_page, block->vecs[i].bv_len, 0); @@ -606,7 +603,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio) WARN_ON(flush_bio || fua_bio); if (lc->device_supports_discard) goto map_bio; - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d83696bf403b..e1eabfb2f52d 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -490,9 +490,11 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio) * If device is suspended, complete the bio. */ if (dm_noflush_suspending(ms->ti)) - bio_endio(bio, DM_ENDIO_REQUEUE); + bio->bi_error = DM_ENDIO_REQUEUE; else - bio_endio(bio, -EIO); + bio->bi_error = -EIO; + + bio_endio(bio); return; } @@ -515,7 +517,7 @@ static void read_callback(unsigned long error, void *context) bio_set_m(bio, NULL); if (likely(!error)) { - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -531,7 +533,7 @@ static void read_callback(unsigned long error, void *context) DMERR_LIMIT("Read failure on mirror device %s. Failing I/O.", m->dev->name); - bio_endio(bio, -EIO); + bio_io_error(bio); } /* Asynchronous read. */ @@ -580,7 +582,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) if (likely(m)) read_async_bio(m, bio); else - bio_endio(bio, -EIO); + bio_io_error(bio); } } @@ -598,7 +600,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) static void write_callback(unsigned long error, void *context) { - unsigned i, ret = 0; + unsigned i; struct bio *bio = (struct bio *) context; struct mirror_set *ms; int should_wake = 0; @@ -614,7 +616,7 @@ static void write_callback(unsigned long error, void *context) * regions with the same code. */ if (likely(!error)) { - bio_endio(bio, ret); + bio_endio(bio); return; } @@ -623,7 +625,8 @@ static void write_callback(unsigned long error, void *context) * degrade the array. */ if (bio->bi_rw & REQ_DISCARD) { - bio_endio(bio, -EOPNOTSUPP); + bio->bi_error = -EOPNOTSUPP; + bio_endio(bio); return; } @@ -828,13 +831,12 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures) * be wrong if the failed leg returned after reboot and * got replicated back to the good legs.) */ - if (unlikely(!get_valid_mirror(ms) || (keep_log(ms) && ms->log_failure))) - bio_endio(bio, -EIO); + bio_io_error(bio); else if (errors_handled(ms) && !keep_log(ms)) hold_bio(ms, bio); else - bio_endio(bio, 0); + bio_endio(bio); } } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7c82d3ccce87..dd8ca0bb0980 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1490,7 +1490,7 @@ out: error_bios(snapshot_bios); } else { if (full_bio) - bio_endio(full_bio, 0); + bio_endio(full_bio); flush_bios(snapshot_bios); } @@ -1580,11 +1580,11 @@ static void start_copy(struct dm_snap_pending_exception *pe) dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); } -static void full_bio_end_io(struct bio *bio, int error) +static void full_bio_end_io(struct bio *bio) { void *callback_data = bio->bi_private; - dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0); + dm_kcopyd_do_callback(callback_data, 0, bio->bi_error ? 1 : 0); } static void start_full_bio(struct dm_snap_pending_exception *pe, diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index a672a1502c14..4f94c7da82f6 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -273,7 +273,7 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio, return DM_MAPIO_REMAPPED; } else { /* The range doesn't map to the target stripe */ - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index c33f61a4cc28..2ade2c46dca9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -614,8 +614,10 @@ static void error_bio_list(struct bio_list *bios, int error) { struct bio *bio; - while ((bio = bio_list_pop(bios))) - bio_endio(bio, error); + while ((bio = bio_list_pop(bios))) { + bio->bi_error = error; + bio_endio(bio); + } } static void error_thin_bio_list(struct thin_c *tc, struct bio_list *master, int error) @@ -864,14 +866,14 @@ static void copy_complete(int read_err, unsigned long write_err, void *context) complete_mapping_preparation(m); } -static void overwrite_endio(struct bio *bio, int err) +static void overwrite_endio(struct bio *bio) { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); struct dm_thin_new_mapping *m = h->overwrite_mapping; bio->bi_end_io = m->saved_bi_end_io; - m->err = err; + m->err = bio->bi_error; complete_mapping_preparation(m); } @@ -996,7 +998,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) */ if (bio) { inc_remap_and_issue_cell(tc, m->cell, m->data_block); - bio_endio(bio, 0); + bio_endio(bio); } else { inc_all_io_entry(tc->pool, m->cell->holder); remap_and_issue(tc, m->cell->holder, m->data_block); @@ -1026,7 +1028,7 @@ static void process_prepared_discard_fail(struct dm_thin_new_mapping *m) static void process_prepared_discard_success(struct dm_thin_new_mapping *m) { - bio_endio(m->bio, 0); + bio_endio(m->bio); free_discard_mapping(m); } @@ -1040,7 +1042,7 @@ static void process_prepared_discard_no_passdown(struct dm_thin_new_mapping *m) metadata_operation_failed(tc->pool, "dm_thin_remove_range", r); bio_io_error(m->bio); } else - bio_endio(m->bio, 0); + bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); mempool_free(m, tc->pool->mapping_pool); @@ -1111,7 +1113,8 @@ static void process_prepared_discard_passdown(struct dm_thin_new_mapping *m) * Even if r is set, there could be sub discards in flight that we * need to wait for. */ - bio_endio(m->bio, r); + m->bio->bi_error = r; + bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); mempool_free(m, pool->mapping_pool); } @@ -1487,9 +1490,10 @@ static void handle_unserviceable_bio(struct pool *pool, struct bio *bio) { int error = should_error_unserviceable_bio(pool); - if (error) - bio_endio(bio, error); - else + if (error) { + bio->bi_error = error; + bio_endio(bio); + } else retry_on_resume(bio); } @@ -1625,7 +1629,7 @@ static void process_discard_cell_passdown(struct thin_c *tc, struct dm_bio_priso * will prevent completion until the sub range discards have * completed. */ - bio_endio(bio, 0); + bio_endio(bio); } static void process_discard_bio(struct thin_c *tc, struct bio *bio) @@ -1639,7 +1643,7 @@ static void process_discard_bio(struct thin_c *tc, struct bio *bio) /* * The discard covers less than a block. */ - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -1784,7 +1788,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block if (bio_data_dir(bio) == READ) { zero_fill_bio(bio); cell_defer_no_holder(tc, cell); - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -1849,7 +1853,7 @@ static void process_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell) } else { zero_fill_bio(bio); - bio_endio(bio, 0); + bio_endio(bio); } } else provision_block(tc, bio, block, cell); @@ -1920,7 +1924,7 @@ static void __process_bio_read_only(struct thin_c *tc, struct bio *bio, } zero_fill_bio(bio); - bio_endio(bio, 0); + bio_endio(bio); break; default: @@ -1945,7 +1949,7 @@ static void process_cell_read_only(struct thin_c *tc, struct dm_bio_prison_cell static void process_bio_success(struct thin_c *tc, struct bio *bio) { - bio_endio(bio, 0); + bio_endio(bio); } static void process_bio_fail(struct thin_c *tc, struct bio *bio) @@ -2581,7 +2585,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio) thin_hook_bio(tc, bio); if (tc->requeue_mode) { - bio_endio(bio, DM_ENDIO_REQUEUE); + bio->bi_error = DM_ENDIO_REQUEUE; + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index bb9c6a00e4b0..4b34df8fdb58 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -458,8 +458,9 @@ static void verity_finish_io(struct dm_verity_io *io, int error) bio->bi_end_io = io->orig_bi_end_io; bio->bi_private = io->orig_bi_private; + bio->bi_error = error; - bio_endio(bio, error); + bio_endio(bio); } static void verity_work(struct work_struct *w) @@ -469,12 +470,12 @@ static void verity_work(struct work_struct *w) verity_finish_io(io, verity_verify_io(io)); } -static void verity_end_io(struct bio *bio, int error) +static void verity_end_io(struct bio *bio) { struct dm_verity_io *io = bio->bi_private; - if (error) { - verity_finish_io(io, error); + if (bio->bi_error) { + verity_finish_io(io, bio->bi_error); return; } diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index b9a64bbce304..766bc93006e6 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c @@ -47,7 +47,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio) break; } - bio_endio(bio, 0); + bio_endio(bio); /* accepted bio, don't make new request */ return DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f331d888e7f5..7f367fcace03 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -944,7 +944,8 @@ static void dec_pending(struct dm_io *io, int error) } else { /* done with normal IO or empty flush */ trace_block_bio_complete(md->queue, bio, io_error); - bio_endio(bio, io_error); + bio->bi_error = io_error; + bio_endio(bio); } } } @@ -957,17 +958,15 @@ static void disable_write_same(struct mapped_device *md) limits->max_write_same_sectors = 0; } -static void clone_endio(struct bio *bio, int error) +static void clone_endio(struct bio *bio) { + int error = bio->bi_error; int r = error; struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); struct dm_io *io = tio->io; struct mapped_device *md = tio->io->md; dm_endio_fn endio = tio->ti->type->end_io; - if (!bio_flagged(bio, BIO_UPTODATE) && !error) - error = -EIO; - if (endio) { r = endio(tio->ti, bio, error); if (r < 0 || r == DM_ENDIO_REQUEUE) @@ -996,7 +995,7 @@ static void clone_endio(struct bio *bio, int error) /* * Partial completion handling for request-based dm */ -static void end_clone_bio(struct bio *clone, int error) +static void end_clone_bio(struct bio *clone) { struct dm_rq_clone_bio_info *info = container_of(clone, struct dm_rq_clone_bio_info, clone); @@ -1013,13 +1012,13 @@ static void end_clone_bio(struct bio *clone, int error) * the remainder. */ return; - else if (error) { + else if (bio->bi_error) { /* * Don't notice the error to the upper layer yet. * The error handling decision is made by the target driver, * when the request is completed. */ - tio->error = error; + tio->error = bio->bi_error; return; } diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 1277eb26b58a..4a8e15058e8b 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -70,7 +70,7 @@ #include -static void faulty_fail(struct bio *bio, int error) +static void faulty_fail(struct bio *bio) { struct bio *b = bio->bi_private; @@ -181,7 +181,7 @@ static void make_request(struct mddev *mddev, struct bio *bio) /* special case - don't decrement, don't generic_make_request, * just fail immediately */ - bio_endio(bio, -EIO); + bio_io_error(bio); return; } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index fa7d577f3d12..aefd66142eef 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -297,7 +297,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) if (unlikely((split->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { /* Just ignore it */ - bio_endio(split, 0); + bio_endio(split); } else generic_make_request(split); } while (split != bio); diff --git a/drivers/md/md.c b/drivers/md/md.c index d429c30cd514..ac4381a6625c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -263,7 +263,9 @@ static void md_make_request(struct request_queue *q, struct bio *bio) return; } if (mddev->ro == 1 && unlikely(rw == WRITE)) { - bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS); + if (bio_sectors(bio) != 0) + bio->bi_error = -EROFS; + bio_endio(bio); return; } smp_rmb(); /* Ensure implications of 'active' are visible */ @@ -377,7 +379,7 @@ static int md_mergeable_bvec(struct request_queue *q, * Generic flush handling for md */ -static void md_end_flush(struct bio *bio, int err) +static void md_end_flush(struct bio *bio) { struct md_rdev *rdev = bio->bi_private; struct mddev *mddev = rdev->mddev; @@ -433,7 +435,7 @@ static void md_submit_flush_data(struct work_struct *ws) if (bio->bi_iter.bi_size == 0) /* an empty barrier - all done */ - bio_endio(bio, 0); + bio_endio(bio); else { bio->bi_rw &= ~REQ_FLUSH; mddev->pers->make_request(mddev, bio); @@ -728,15 +730,13 @@ void md_rdev_clear(struct md_rdev *rdev) } EXPORT_SYMBOL_GPL(md_rdev_clear); -static void super_written(struct bio *bio, int error) +static void super_written(struct bio *bio) { struct md_rdev *rdev = bio->bi_private; struct mddev *mddev = rdev->mddev; - if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) { - printk("md: super_written gets error=%d, uptodate=%d\n", - error, test_bit(BIO_UPTODATE, &bio->bi_flags)); - WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags)); + if (bio->bi_error) { + printk("md: super_written gets error=%d\n", bio->bi_error); md_error(mddev, rdev); } @@ -791,7 +791,7 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, bio_add_page(bio, page, size, 0); submit_bio_wait(rw, bio); - ret = test_bit(BIO_UPTODATE, &bio->bi_flags); + ret = !bio->bi_error; bio_put(bio); return ret; } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index ac3ede2bd00e..082a489af9d3 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -77,18 +77,18 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) struct bio *bio = mp_bh->master_bio; struct mpconf *conf = mp_bh->mddev->private; - bio_endio(bio, err); + bio->bi_error = err; + bio_endio(bio); mempool_free(mp_bh, conf->pool); } -static void multipath_end_request(struct bio *bio, int error) +static void multipath_end_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh *mp_bh = bio->bi_private; struct mpconf *conf = mp_bh->mddev->private; struct md_rdev *rdev = conf->multipaths[mp_bh->path].rdev; - if (uptodate) + if (!bio->bi_error) multipath_end_bh_io(mp_bh, 0); else if (!(bio->bi_rw & REQ_RAHEAD)) { /* @@ -101,7 +101,7 @@ static void multipath_end_request(struct bio *bio, int error) (unsigned long long)bio->bi_iter.bi_sector); multipath_reschedule_retry(mp_bh); } else - multipath_end_bh_io(mp_bh, error); + multipath_end_bh_io(mp_bh, bio->bi_error); rdev_dec_pending(rdev, conf->mddev); } @@ -123,7 +123,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio) mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { - bio_endio(bio, -EIO); + bio_io_error(bio); mempool_free(mp_bh, conf->pool); return; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index efb654eb5399..e6e0ae56f66b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -543,7 +543,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) if (unlikely((split->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { /* Just ignore it */ - bio_endio(split, 0); + bio_endio(split); } else generic_make_request(split); } while (split != bio); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f80f1af61ce7..9aa7d1fb2bc1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -255,9 +255,10 @@ static void call_bio_endio(struct r1bio *r1_bio) done = 1; if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; + if (done) { - bio_endio(bio, 0); + bio_endio(bio); /* * Wake up any possible resync thread that waits for the device * to go idle. @@ -312,9 +313,9 @@ static int find_bio_disk(struct r1bio *r1_bio, struct bio *bio) return mirror; } -static void raid1_end_read_request(struct bio *bio, int error) +static void raid1_end_read_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r1bio *r1_bio = bio->bi_private; int mirror; struct r1conf *conf = r1_bio->mddev->private; @@ -397,9 +398,8 @@ static void r1_bio_write_done(struct r1bio *r1_bio) } } -static void raid1_end_write_request(struct bio *bio, int error) +static void raid1_end_write_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r1bio *r1_bio = bio->bi_private; int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state); struct r1conf *conf = r1_bio->mddev->private; @@ -410,7 +410,7 @@ static void raid1_end_write_request(struct bio *bio, int error) /* * 'one mirror IO has finished' event handler: */ - if (!uptodate) { + if (bio->bi_error) { set_bit(WriteErrorSeen, &conf->mirrors[mirror].rdev->flags); if (!test_and_set_bit(WantReplacement, @@ -793,7 +793,7 @@ static void flush_pending_writes(struct r1conf *conf) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1068,7 +1068,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1734,7 +1734,7 @@ abort: return err; } -static void end_sync_read(struct bio *bio, int error) +static void end_sync_read(struct bio *bio) { struct r1bio *r1_bio = bio->bi_private; @@ -1745,16 +1745,16 @@ static void end_sync_read(struct bio *bio, int error) * or re-read if the read failed. * We don't do much here, just schedule handling by raid1d */ - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) set_bit(R1BIO_Uptodate, &r1_bio->state); if (atomic_dec_and_test(&r1_bio->remaining)) reschedule_retry(r1_bio); } -static void end_sync_write(struct bio *bio, int error) +static void end_sync_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r1bio *r1_bio = bio->bi_private; struct mddev *mddev = r1_bio->mddev; struct r1conf *conf = mddev->private; @@ -1941,7 +1941,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio) idx ++; } set_bit(R1BIO_Uptodate, &r1_bio->state); - set_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = 0; return 1; } @@ -1965,15 +1965,14 @@ static void process_checks(struct r1bio *r1_bio) for (i = 0; i < conf->raid_disks * 2; i++) { int j; int size; - int uptodate; + int error; struct bio *b = r1_bio->bios[i]; if (b->bi_end_io != end_sync_read) continue; - /* fixup the bio for reuse, but preserve BIO_UPTODATE */ - uptodate = test_bit(BIO_UPTODATE, &b->bi_flags); + /* fixup the bio for reuse, but preserve errno */ + error = b->bi_error; bio_reset(b); - if (!uptodate) - clear_bit(BIO_UPTODATE, &b->bi_flags); + b->bi_error = error; b->bi_vcnt = vcnt; b->bi_iter.bi_size = r1_bio->sectors << 9; b->bi_iter.bi_sector = r1_bio->sector + @@ -1996,7 +1995,7 @@ static void process_checks(struct r1bio *r1_bio) } for (primary = 0; primary < conf->raid_disks * 2; primary++) if (r1_bio->bios[primary]->bi_end_io == end_sync_read && - test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) { + !r1_bio->bios[primary]->bi_error) { r1_bio->bios[primary]->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[primary].rdev, mddev); break; @@ -2006,14 +2005,14 @@ static void process_checks(struct r1bio *r1_bio) int j; struct bio *pbio = r1_bio->bios[primary]; struct bio *sbio = r1_bio->bios[i]; - int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags); + int error = sbio->bi_error; if (sbio->bi_end_io != end_sync_read) continue; - /* Now we can 'fixup' the BIO_UPTODATE flag */ - set_bit(BIO_UPTODATE, &sbio->bi_flags); + /* Now we can 'fixup' the error value */ + sbio->bi_error = 0; - if (uptodate) { + if (!error) { for (j = vcnt; j-- ; ) { struct page *p, *s; p = pbio->bi_io_vec[j].bv_page; @@ -2028,7 +2027,7 @@ static void process_checks(struct r1bio *r1_bio) if (j >= 0) atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) - && uptodate)) { + && !error)) { /* No need to write to this device. */ sbio->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[i].rdev, mddev); @@ -2269,11 +2268,11 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio struct bio *bio = r1_bio->bios[m]; if (bio->bi_end_io == NULL) continue; - if (test_bit(BIO_UPTODATE, &bio->bi_flags) && + if (!bio->bi_error && test_bit(R1BIO_MadeGood, &r1_bio->state)) { rdev_clear_badblocks(rdev, r1_bio->sector, s, 0); } - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && + if (bio->bi_error && test_bit(R1BIO_WriteError, &r1_bio->state)) { if (!rdev_set_badblocks(rdev, r1_bio->sector, s, 0)) md_error(conf->mddev, rdev); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 940f2f365461..929e9a26d81b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -101,7 +101,7 @@ static int _enough(struct r10conf *conf, int previous, int ignore); static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *skipped); static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio); -static void end_reshape_write(struct bio *bio, int error); +static void end_reshape_write(struct bio *bio); static void end_reshape(struct r10conf *conf); static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data) @@ -307,9 +307,9 @@ static void raid_end_bio_io(struct r10bio *r10_bio) } else done = 1; if (!test_bit(R10BIO_Uptodate, &r10_bio->state)) - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; if (done) { - bio_endio(bio, 0); + bio_endio(bio); /* * Wake up any possible resync thread that waits for the device * to go idle. @@ -358,9 +358,9 @@ static int find_bio_disk(struct r10conf *conf, struct r10bio *r10_bio, return r10_bio->devs[slot].devnum; } -static void raid10_end_read_request(struct bio *bio, int error) +static void raid10_end_read_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r10bio *r10_bio = bio->bi_private; int slot, dev; struct md_rdev *rdev; @@ -438,9 +438,8 @@ static void one_write_done(struct r10bio *r10_bio) } } -static void raid10_end_write_request(struct bio *bio, int error) +static void raid10_end_write_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; int dev; int dec_rdev = 1; @@ -460,7 +459,7 @@ static void raid10_end_write_request(struct bio *bio, int error) /* * this branch is our 'one mirror IO has finished' event handler: */ - if (!uptodate) { + if (bio->bi_error) { if (repl) /* Never record new bad blocks to replacement, * just fail it. @@ -957,7 +956,7 @@ static void flush_pending_writes(struct r10conf *conf) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1133,7 +1132,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1916,7 +1915,7 @@ abort: return err; } -static void end_sync_read(struct bio *bio, int error) +static void end_sync_read(struct bio *bio) { struct r10bio *r10_bio = bio->bi_private; struct r10conf *conf = r10_bio->mddev->private; @@ -1928,7 +1927,7 @@ static void end_sync_read(struct bio *bio, int error) } else d = find_bio_disk(conf, r10_bio, bio, NULL, NULL); - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) set_bit(R10BIO_Uptodate, &r10_bio->state); else /* The write handler will notice the lack of @@ -1977,9 +1976,8 @@ static void end_sync_request(struct r10bio *r10_bio) } } -static void end_sync_write(struct bio *bio, int error) +static void end_sync_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; struct mddev *mddev = r10_bio->mddev; struct r10conf *conf = mddev->private; @@ -1996,7 +1994,7 @@ static void end_sync_write(struct bio *bio, int error) else rdev = conf->mirrors[d].rdev; - if (!uptodate) { + if (bio->bi_error) { if (repl) md_error(mddev, rdev); else { @@ -2044,7 +2042,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) /* find the first device with a block */ for (i=0; icopies; i++) - if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) + if (!r10_bio->devs[i].bio->bi_error) break; if (i == conf->copies) @@ -2064,7 +2062,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) continue; if (i == first) continue; - if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) { + if (!r10_bio->devs[i].bio->bi_error) { /* We know that the bi_io_vec layout is the same for * both 'first' and 'i', so we just compare them. * All vec entries are PAGE_SIZE; @@ -2706,8 +2704,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) rdev = conf->mirrors[dev].rdev; if (r10_bio->devs[m].bio == NULL) continue; - if (test_bit(BIO_UPTODATE, - &r10_bio->devs[m].bio->bi_flags)) { + if (!r10_bio->devs[m].bio->bi_error) { rdev_clear_badblocks( rdev, r10_bio->devs[m].addr, @@ -2722,8 +2719,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) rdev = conf->mirrors[dev].replacement; if (r10_bio->devs[m].repl_bio == NULL) continue; - if (test_bit(BIO_UPTODATE, - &r10_bio->devs[m].repl_bio->bi_flags)) { + + if (!r10_bio->devs[m].repl_bio->bi_error) { rdev_clear_badblocks( rdev, r10_bio->devs[m].addr, @@ -2748,8 +2745,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) r10_bio->devs[m].addr, r10_bio->sectors, 0); rdev_dec_pending(rdev, conf->mddev); - } else if (bio != NULL && - !test_bit(BIO_UPTODATE, &bio->bi_flags)) { + } else if (bio != NULL && bio->bi_error) { if (!narrow_write_error(r10_bio, m)) { md_error(conf->mddev, rdev); set_bit(R10BIO_Degraded, @@ -3263,7 +3259,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio = r10_bio->devs[i].bio; bio_reset(bio); - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; if (conf->mirrors[d].rdev == NULL || test_bit(Faulty, &conf->mirrors[d].rdev->flags)) continue; @@ -3300,7 +3296,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, /* Need to set up for writing to the replacement */ bio = r10_bio->devs[i].repl_bio; bio_reset(bio); - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; sector = r10_bio->devs[i].addr; atomic_inc(&conf->mirrors[d].rdev->nr_pending); @@ -3377,7 +3373,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, if (bio->bi_end_io == end_sync_read) { md_sync_acct(bio->bi_bdev, nr_sectors); - set_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = 0; generic_make_request(bio); } } @@ -4380,7 +4376,7 @@ read_more: read_bio->bi_end_io = end_sync_read; read_bio->bi_rw = READ; read_bio->bi_flags &= (~0UL << BIO_RESET_BITS); - __set_bit(BIO_UPTODATE, &read_bio->bi_flags); + read_bio->bi_error = 0; read_bio->bi_vcnt = 0; read_bio->bi_iter.bi_size = 0; r10_bio->master_bio = read_bio; @@ -4601,9 +4597,8 @@ static int handle_reshape_read_error(struct mddev *mddev, return 0; } -static void end_reshape_write(struct bio *bio, int error) +static void end_reshape_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; struct mddev *mddev = r10_bio->mddev; struct r10conf *conf = mddev->private; @@ -4620,7 +4615,7 @@ static void end_reshape_write(struct bio *bio, int error) rdev = conf->mirrors[d].rdev; } - if (!uptodate) { + if (bio->bi_error) { /* FIXME should record badblock */ md_error(mddev, rdev); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 59e44e99eef3..84d6eec1033e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -233,7 +233,7 @@ static void return_io(struct bio *return_bi) bi->bi_iter.bi_size = 0; trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); - bio_endio(bi, 0); + bio_endio(bi); bi = return_bi; } } @@ -887,9 +887,9 @@ static int use_new_offset(struct r5conf *conf, struct stripe_head *sh) } static void -raid5_end_read_request(struct bio *bi, int error); +raid5_end_read_request(struct bio *bi); static void -raid5_end_write_request(struct bio *bi, int error); +raid5_end_write_request(struct bio *bi); static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) { @@ -2277,12 +2277,11 @@ static void shrink_stripes(struct r5conf *conf) conf->slab_cache = NULL; } -static void raid5_end_read_request(struct bio * bi, int error) +static void raid5_end_read_request(struct bio * bi) { struct stripe_head *sh = bi->bi_private; struct r5conf *conf = sh->raid_conf; int disks = sh->disks, i; - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); char b[BDEVNAME_SIZE]; struct md_rdev *rdev = NULL; sector_t s; @@ -2291,9 +2290,9 @@ static void raid5_end_read_request(struct bio * bi, int error) if (bi == &sh->dev[i].req) break; - pr_debug("end_read_request %llu/%d, count: %d, uptodate %d.\n", + pr_debug("end_read_request %llu/%d, count: %d, error %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), - uptodate); + bi->bi_error); if (i == disks) { BUG(); return; @@ -2312,7 +2311,7 @@ static void raid5_end_read_request(struct bio * bi, int error) s = sh->sector + rdev->new_data_offset; else s = sh->sector + rdev->data_offset; - if (uptodate) { + if (!bi->bi_error) { set_bit(R5_UPTODATE, &sh->dev[i].flags); if (test_bit(R5_ReadError, &sh->dev[i].flags)) { /* Note that this cannot happen on a @@ -2400,13 +2399,12 @@ static void raid5_end_read_request(struct bio * bi, int error) release_stripe(sh); } -static void raid5_end_write_request(struct bio *bi, int error) +static void raid5_end_write_request(struct bio *bi) { struct stripe_head *sh = bi->bi_private; struct r5conf *conf = sh->raid_conf; int disks = sh->disks, i; struct md_rdev *uninitialized_var(rdev); - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); sector_t first_bad; int bad_sectors; int replacement = 0; @@ -2429,23 +2427,23 @@ static void raid5_end_write_request(struct bio *bi, int error) break; } } - pr_debug("end_write_request %llu/%d, count %d, uptodate: %d.\n", + pr_debug("end_write_request %llu/%d, count %d, error: %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), - uptodate); + bi->bi_error); if (i == disks) { BUG(); return; } if (replacement) { - if (!uptodate) + if (bi->bi_error) md_error(conf->mddev, rdev); else if (is_badblock(rdev, sh->sector, STRIPE_SECTORS, &first_bad, &bad_sectors)) set_bit(R5_MadeGoodRepl, &sh->dev[i].flags); } else { - if (!uptodate) { + if (bi->bi_error) { set_bit(STRIPE_DEGRADED, &sh->state); set_bit(WriteErrorSeen, &rdev->flags); set_bit(R5_WriteError, &sh->dev[i].flags); @@ -2466,7 +2464,7 @@ static void raid5_end_write_request(struct bio *bi, int error) } rdev_dec_pending(rdev, conf->mddev); - if (sh->batch_head && !uptodate && !replacement) + if (sh->batch_head && bi->bi_error && !replacement) set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state); if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) @@ -3107,7 +3105,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); bi->bi_next = *return_bi; @@ -3131,7 +3130,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); bi->bi_next = *return_bi; @@ -3156,7 +3156,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { bi->bi_next = *return_bi; *return_bi = bi; @@ -4749,12 +4750,11 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf) * first). * If the read failed.. */ -static void raid5_align_endio(struct bio *bi, int error) +static void raid5_align_endio(struct bio *bi) { struct bio* raid_bi = bi->bi_private; struct mddev *mddev; struct r5conf *conf; - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); struct md_rdev *rdev; bio_put(bi); @@ -4766,10 +4766,10 @@ static void raid5_align_endio(struct bio *bi, int error) rdev_dec_pending(rdev, conf->mddev); - if (!error && uptodate) { + if (!bi->bi_error) { trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev), raid_bi, 0); - bio_endio(raid_bi, 0); + bio_endio(raid_bi); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); return; @@ -5133,7 +5133,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) remaining = raid5_dec_bi_active_stripes(bi); if (remaining == 0) { md_write_end(mddev); - bio_endio(bi, 0); + bio_endio(bi); } } @@ -5297,7 +5297,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) release_stripe_plug(mddev, sh); } else { /* cannot get stripe for read-ahead, just give-up */ - clear_bit(BIO_UPTODATE, &bi->bi_flags); + bi->bi_error = -EIO; break; } } @@ -5311,7 +5311,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); - bio_endio(bi, 0); + bio_endio(bi); } } @@ -5707,7 +5707,7 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) if (remaining == 0) { trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev), raid_bio, 0); - bio_endio(raid_bio, 0); + bio_endio(raid_bio); } if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 4f97b248c236..0df77cb07df6 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c @@ -180,7 +180,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) * another kernel subsystem, and we just pass it through. */ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - err = -EIO; + bio->bi_error = -EIO; goto out; } @@ -199,6 +199,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); + bio->bi_error = err; break; } } @@ -206,7 +207,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); out: - bio_endio(bio, err); + bio_endio(bio); } static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 411c7b2bb37a..341202ed32b4 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1189,7 +1189,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) * another kernel subsystem, and we just pass it through. */ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - err = -EIO; + bio->bi_error = -EIO; goto out; } @@ -1211,6 +1211,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); + bio->bi_error = err; break; } } @@ -1218,7 +1219,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); out: - bio_endio(bio, err); + bio_endio(bio); } static int btt_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ade9eb917a4d..4c079d5cb539 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -77,7 +77,7 @@ static void pmem_make_request(struct request_queue *q, struct bio *bio) if (bio_data_dir(bio)) wmb_pmem(); - bio_endio(bio, 0); + bio_endio(bio); } static int pmem_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index da212813f2d5..8bcb822b0bac 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -871,7 +871,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } bytes_done += bvec.bv_len; } - bio_endio(bio, 0); + bio_endio(bio); return; fail: bio_io_error(bio); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 7d4e9397ac31..93856b9b6214 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -220,8 +220,7 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) index++; } } - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); + bio_endio(bio); return; fail: bio_io_error(bio); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 6d88d24e6cce..5a9982f5d5d6 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -306,20 +306,13 @@ static void iblock_complete_cmd(struct se_cmd *cmd) kfree(ibr); } -static void iblock_bio_done(struct bio *bio, int err) +static void iblock_bio_done(struct bio *bio) { struct se_cmd *cmd = bio->bi_private; struct iblock_req *ibr = cmd->priv; - /* - * Set -EIO if !BIO_UPTODATE and the passed is still err=0 - */ - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) - err = -EIO; - - if (err != 0) { - pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," - " err: %d\n", bio, err); + if (bio->bi_error) { + pr_err("bio error: %p, err: %d\n", bio, bio->bi_error); /* * Bump the ib_bio_err_cnt and release bio. */ @@ -370,15 +363,15 @@ static void iblock_submit_bios(struct bio_list *list, int rw) blk_finish_plug(&plug); } -static void iblock_end_io_flush(struct bio *bio, int err) +static void iblock_end_io_flush(struct bio *bio) { struct se_cmd *cmd = bio->bi_private; - if (err) - pr_err("IBLOCK: cache flush failed: %d\n", err); + if (bio->bi_error) + pr_err("IBLOCK: cache flush failed: %d\n", bio->bi_error); if (cmd) { - if (err) + if (bio->bi_error) target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); else target_complete_cmd(cmd, SAM_STAT_GOOD); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 08e9084ee615..de18790eb21c 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -852,7 +852,7 @@ static ssize_t pscsi_show_configfs_dev_params(struct se_device *dev, char *b) return bl; } -static void pscsi_bi_endio(struct bio *bio, int error) +static void pscsi_bi_endio(struct bio *bio) { bio_put(bio); } @@ -973,7 +973,7 @@ fail: while (*hbio) { bio = *hbio; *hbio = (*hbio)->bi_next; - bio_endio(bio, 0); /* XXX: should be error */ + bio_endio(bio); } return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } @@ -1061,7 +1061,7 @@ fail_free_bio: while (hbio) { struct bio *bio = hbio; hbio = hbio->bi_next; - bio_endio(bio, 0); /* XXX: should be error */ + bio_endio(bio); } ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; fail: diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index ce7dec88f4b8..541fbfaed276 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -343,7 +343,7 @@ static int btrfsic_process_written_superblock( struct btrfsic_state *state, struct btrfsic_block *const block, struct btrfs_super_block *const super_hdr); -static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status); +static void btrfsic_bio_end_io(struct bio *bp); static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate); static int btrfsic_is_block_ref_by_superblock(const struct btrfsic_state *state, const struct btrfsic_block *block, @@ -2207,7 +2207,7 @@ continue_loop: goto again; } -static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) +static void btrfsic_bio_end_io(struct bio *bp) { struct btrfsic_block *block = (struct btrfsic_block *)bp->bi_private; int iodone_w_error; @@ -2215,7 +2215,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) /* mutex is not held! This is not save if IO is not yet completed * on umount */ iodone_w_error = 0; - if (bio_error_status) + if (bp->bi_error) iodone_w_error = 1; BUG_ON(NULL == block); @@ -2230,7 +2230,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) printk(KERN_INFO "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n", - bio_error_status, + bp->bi_error, btrfsic_get_block_type(dev_state->state, block), block->logical_bytenr, dev_state->name, block->dev_bytenr, block->mirror_num); @@ -2252,7 +2252,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) block = next_block; } while (NULL != block); - bp->bi_end_io(bp, bio_error_status); + bp->bi_end_io(bp); } static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index ce62324c78e7..302266ec2cdb 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -152,7 +152,7 @@ fail: * The compressed pages are freed here, and it must be run * in process context */ -static void end_compressed_bio_read(struct bio *bio, int err) +static void end_compressed_bio_read(struct bio *bio) { struct compressed_bio *cb = bio->bi_private; struct inode *inode; @@ -160,7 +160,7 @@ static void end_compressed_bio_read(struct bio *bio, int err) unsigned long index; int ret; - if (err) + if (bio->bi_error) cb->errors = 1; /* if there are more bios still pending for this compressed @@ -210,7 +210,7 @@ csum_failed: bio_for_each_segment_all(bvec, cb->orig_bio, i) SetPageChecked(bvec->bv_page); - bio_endio(cb->orig_bio, 0); + bio_endio(cb->orig_bio); } /* finally free the cb struct */ @@ -266,7 +266,7 @@ static noinline void end_compressed_writeback(struct inode *inode, * This also calls the writeback end hooks for the file pages so that * metadata and checksums can be updated in the file. */ -static void end_compressed_bio_write(struct bio *bio, int err) +static void end_compressed_bio_write(struct bio *bio) { struct extent_io_tree *tree; struct compressed_bio *cb = bio->bi_private; @@ -274,7 +274,7 @@ static void end_compressed_bio_write(struct bio *bio, int err) struct page *page; unsigned long index; - if (err) + if (bio->bi_error) cb->errors = 1; /* if there are more bios still pending for this compressed @@ -293,7 +293,7 @@ static void end_compressed_bio_write(struct bio *bio, int err) cb->start, cb->start + cb->len - 1, NULL, - err ? 0 : 1); + bio->bi_error ? 0 : 1); cb->compressed_pages[0]->mapping = NULL; end_compressed_writeback(inode, cb); @@ -697,8 +697,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - if (ret) - bio_endio(comp_bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(comp_bio); + } bio_put(comp_bio); @@ -724,8 +726,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, } ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - if (ret) - bio_endio(comp_bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(comp_bio); + } bio_put(comp_bio); return 0; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a9aadb2ad525..a8c0de888a9d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -703,7 +703,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) return -EIO; /* we fixed nothing */ } -static void end_workqueue_bio(struct bio *bio, int err) +static void end_workqueue_bio(struct bio *bio) { struct btrfs_end_io_wq *end_io_wq = bio->bi_private; struct btrfs_fs_info *fs_info; @@ -711,7 +711,7 @@ static void end_workqueue_bio(struct bio *bio, int err) btrfs_work_func_t func; fs_info = end_io_wq->info; - end_io_wq->error = err; + end_io_wq->error = bio->bi_error; if (bio->bi_rw & REQ_WRITE) { if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) { @@ -808,7 +808,8 @@ static void run_one_async_done(struct btrfs_work *work) /* If an error occured we just want to clean up the bio and move on */ if (async->error) { - bio_endio(async->bio, async->error); + async->bio->bi_error = async->error; + bio_endio(async->bio); return; } @@ -908,8 +909,10 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, * submission context. Just jump into btrfs_map_bio */ ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); - if (ret) - bio_endio(bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -960,10 +963,13 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, __btree_submit_bio_done); } - if (ret) { + if (ret) + goto out_w_error; + return 0; + out_w_error: - bio_endio(bio, ret); - } + bio->bi_error = ret; + bio_endio(bio); return ret; } @@ -1735,16 +1741,15 @@ static void end_workqueue_fn(struct btrfs_work *work) { struct bio *bio; struct btrfs_end_io_wq *end_io_wq; - int error; end_io_wq = container_of(work, struct btrfs_end_io_wq, work); bio = end_io_wq->bio; - error = end_io_wq->error; + bio->bi_error = end_io_wq->error; bio->bi_private = end_io_wq->private; bio->bi_end_io = end_io_wq->end_io; kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq); - bio_endio(bio, error); + bio_endio(bio); } static int cleaner_kthread(void *arg) @@ -3323,10 +3328,8 @@ static int write_dev_supers(struct btrfs_device *device, * endio for the write_dev_flush, this will wake anyone waiting * for the barrier when it is done */ -static void btrfs_end_empty_barrier(struct bio *bio, int err) +static void btrfs_end_empty_barrier(struct bio *bio) { - if (err) - clear_bit(BIO_UPTODATE, &bio->bi_flags); if (bio->bi_private) complete(bio->bi_private); bio_put(bio); @@ -3354,8 +3357,8 @@ static int write_dev_flush(struct btrfs_device *device, int wait) wait_for_completion(&device->flush_wait); - if (!bio_flagged(bio, BIO_UPTODATE)) { - ret = -EIO; + if (bio->bi_error) { + ret = bio->bi_error; btrfs_dev_stat_inc_and_print(device, BTRFS_DEV_STAT_FLUSH_ERRS); } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 02d05817cbdf..c22f175ed024 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2486,7 +2486,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) * Scheduling is not allowed, so the extent state tree is expected * to have one and only one object corresponding to this IO. */ -static void end_bio_extent_writepage(struct bio *bio, int err) +static void end_bio_extent_writepage(struct bio *bio) { struct bio_vec *bvec; u64 start; @@ -2516,7 +2516,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err) start = page_offset(page); end = start + bvec->bv_offset + bvec->bv_len - 1; - if (end_extent_writepage(page, err, start, end)) + if (end_extent_writepage(page, bio->bi_error, start, end)) continue; end_page_writeback(page); @@ -2548,10 +2548,10 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len, * Scheduling is not allowed, so the extent state tree is expected * to have one and only one object corresponding to this IO. */ -static void end_bio_extent_readpage(struct bio *bio, int err) +static void end_bio_extent_readpage(struct bio *bio) { struct bio_vec *bvec; - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); struct extent_io_tree *tree; u64 offset = 0; @@ -2564,16 +2564,13 @@ static void end_bio_extent_readpage(struct bio *bio, int err) int ret; int i; - if (err) - uptodate = 0; - bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host; pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, " - "mirror=%u\n", (u64)bio->bi_iter.bi_sector, err, - io_bio->mirror_num); + "mirror=%u\n", (u64)bio->bi_iter.bi_sector, + bio->bi_error, io_bio->mirror_num); tree = &BTRFS_I(inode)->io_tree; /* We always issue full-page reads, but if some block @@ -2614,8 +2611,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) if (tree->ops && tree->ops->readpage_io_failed_hook) { ret = tree->ops->readpage_io_failed_hook(page, mirror); - if (!ret && !err && - test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!ret && !bio->bi_error) uptodate = 1; } else { /* @@ -2631,10 +2627,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) ret = bio_readpage_error(bio, offset, page, start, end, mirror); if (ret == 0) { - uptodate = - test_bit(BIO_UPTODATE, &bio->bi_flags); - if (err) - uptodate = 0; + uptodate = !bio->bi_error; offset += len; continue; } @@ -2684,7 +2677,7 @@ readpage_ok: endio_readpage_release_extent(tree, extent_start, extent_len, uptodate); if (io_bio->end_io) - io_bio->end_io(io_bio, err); + io_bio->end_io(io_bio, bio->bi_error); bio_put(bio); } @@ -3696,7 +3689,7 @@ static void set_btree_ioerr(struct page *page) } } -static void end_bio_extent_buffer_writepage(struct bio *bio, int err) +static void end_bio_extent_buffer_writepage(struct bio *bio) { struct bio_vec *bvec; struct extent_buffer *eb; @@ -3709,7 +3702,8 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err) BUG_ON(!eb); done = atomic_dec_and_test(&eb->io_pages); - if (err || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { + if (bio->bi_error || + test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { ClearPageUptodate(page); set_btree_ioerr(page); } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b33c0cf02668..6b8becfe2057 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1845,8 +1845,10 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, int ret; ret = btrfs_map_bio(root, rw, bio, mirror_num, 1); - if (ret) - bio_endio(bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -1906,8 +1908,10 @@ mapit: ret = btrfs_map_bio(root, rw, bio, mirror_num, 0); out: - if (ret < 0) - bio_endio(bio, ret); + if (ret < 0) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -7689,13 +7693,13 @@ struct btrfs_retry_complete { int uptodate; }; -static void btrfs_retry_endio_nocsum(struct bio *bio, int err) +static void btrfs_retry_endio_nocsum(struct bio *bio) { struct btrfs_retry_complete *done = bio->bi_private; struct bio_vec *bvec; int i; - if (err) + if (bio->bi_error) goto end; done->uptodate = 1; @@ -7744,7 +7748,7 @@ try_again: return 0; } -static void btrfs_retry_endio(struct bio *bio, int err) +static void btrfs_retry_endio(struct bio *bio) { struct btrfs_retry_complete *done = bio->bi_private; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); @@ -7753,7 +7757,7 @@ static void btrfs_retry_endio(struct bio *bio, int err) int ret; int i; - if (err) + if (bio->bi_error) goto end; uptodate = 1; @@ -7836,12 +7840,13 @@ static int btrfs_subio_endio_read(struct inode *inode, } } -static void btrfs_endio_direct_read(struct bio *bio, int err) +static void btrfs_endio_direct_read(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; struct inode *inode = dip->inode; struct bio *dio_bio; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); + int err = bio->bi_error; if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED) err = btrfs_subio_endio_read(inode, io_bio, err); @@ -7852,17 +7857,14 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) kfree(dip); - /* If we had a csum failure make sure to clear the uptodate flag */ - if (err) - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); - dio_end_io(dio_bio, err); + dio_end_io(dio_bio, bio->bi_error); if (io_bio->end_io) io_bio->end_io(io_bio, err); bio_put(bio); } -static void btrfs_endio_direct_write(struct bio *bio, int err) +static void btrfs_endio_direct_write(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; struct inode *inode = dip->inode; @@ -7876,7 +7878,8 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) again: ret = btrfs_dec_test_first_ordered_pending(inode, &ordered, &ordered_offset, - ordered_bytes, !err); + ordered_bytes, + !bio->bi_error); if (!ret) goto out_test; @@ -7899,10 +7902,7 @@ out_test: kfree(dip); - /* If we had an error make sure to clear the uptodate flag */ - if (err) - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); - dio_end_io(dio_bio, err); + dio_end_io(dio_bio, bio->bi_error); bio_put(bio); } @@ -7917,9 +7917,10 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw, return 0; } -static void btrfs_end_dio_bio(struct bio *bio, int err) +static void btrfs_end_dio_bio(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; + int err = bio->bi_error; if (err) btrfs_warn(BTRFS_I(dip->inode)->root->fs_info, @@ -7948,8 +7949,8 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) if (dip->errors) { bio_io_error(dip->orig_bio); } else { - set_bit(BIO_UPTODATE, &dip->dio_bio->bi_flags); - bio_endio(dip->orig_bio, 0); + dip->dio_bio->bi_error = 0; + bio_endio(dip->orig_bio); } out: bio_put(bio); @@ -8220,7 +8221,8 @@ free_ordered: * callbacks - they require an allocated dip and a clone of dio_bio. */ if (io_bio && dip) { - bio_endio(io_bio, ret); + io_bio->bi_error = -EIO; + bio_endio(io_bio); /* * The end io callbacks free our dip, do the final put on io_bio * and all the cleanup and final put for dio_bio (through @@ -8247,7 +8249,7 @@ free_ordered: unlock_extent(&BTRFS_I(inode)->io_tree, file_offset, file_offset + dio_bio->bi_iter.bi_size - 1); } - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); + dio_bio->bi_error = -EIO; /* * Releases and cleans up our dio_bio, no need to bio_put() * nor bio_endio()/bio_io_error() against dio_bio. diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index fa72068bd256..0a02e24900aa 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -851,7 +851,7 @@ static void free_raid_bio(struct btrfs_raid_bio *rbio) * this frees the rbio and runs through all the bios in the * bio_list and calls end_io on them */ -static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) +static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err) { struct bio *cur = bio_list_get(&rbio->bio_list); struct bio *next; @@ -864,9 +864,8 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) while (cur) { next = cur->bi_next; cur->bi_next = NULL; - if (uptodate) - set_bit(BIO_UPTODATE, &cur->bi_flags); - bio_endio(cur, err); + cur->bi_error = err; + bio_endio(cur); cur = next; } } @@ -875,9 +874,10 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) * end io function used by finish_rmw. When we finally * get here, we've written a full stripe */ -static void raid_write_end_io(struct bio *bio, int err) +static void raid_write_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; + int err = bio->bi_error; if (err) fail_bio_stripe(rbio, bio); @@ -893,7 +893,7 @@ static void raid_write_end_io(struct bio *bio, int err) if (atomic_read(&rbio->error) > rbio->bbio->max_errors) err = -EIO; - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); return; } @@ -1071,7 +1071,7 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, * devices or if they are not contiguous */ if (last_end == disk_start && stripe->dev->bdev && - test_bit(BIO_UPTODATE, &last->bi_flags) && + !last->bi_error && last->bi_bdev == stripe->dev->bdev) { ret = bio_add_page(last, page, PAGE_CACHE_SIZE, 0); if (ret == PAGE_CACHE_SIZE) @@ -1087,7 +1087,6 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, bio->bi_iter.bi_size = 0; bio->bi_bdev = stripe->dev->bdev; bio->bi_iter.bi_sector = disk_start >> 9; - set_bit(BIO_UPTODATE, &bio->bi_flags); bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); bio_list_add(bio_list, bio); @@ -1312,13 +1311,12 @@ write_data: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(WRITE, bio); } return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } /* @@ -1441,11 +1439,11 @@ static void set_bio_pages_uptodate(struct bio *bio) * This will usually kick off finish_rmw once all the bios are read in, but it * may trigger parity reconstruction if we had any errors along the way */ -static void raid_rmw_end_io(struct bio *bio, int err) +static void raid_rmw_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -1455,7 +1453,6 @@ static void raid_rmw_end_io(struct bio *bio, int err) if (!atomic_dec_and_test(&rbio->stripes_pending)) return; - err = 0; if (atomic_read(&rbio->error) > rbio->bbio->max_errors) goto cleanup; @@ -1469,7 +1466,7 @@ static void raid_rmw_end_io(struct bio *bio, int err) cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } static void async_rmw_stripe(struct btrfs_raid_bio *rbio) @@ -1572,14 +1569,13 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } /* the actual write will happen once the reads are done */ return 0; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return -EIO; finish: @@ -1964,7 +1960,7 @@ cleanup_io: else clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags); - rbio_orig_end_io(rbio, err, err == 0); + rbio_orig_end_io(rbio, err); } else if (err == 0) { rbio->faila = -1; rbio->failb = -1; @@ -1976,7 +1972,7 @@ cleanup_io: else BUG(); } else { - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); } } @@ -1984,7 +1980,7 @@ cleanup_io: * This is called only for stripes we've read from disk to * reconstruct the parity. */ -static void raid_recover_end_io(struct bio *bio, int err) +static void raid_recover_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; @@ -1992,7 +1988,7 @@ static void raid_recover_end_io(struct bio *bio, int err) * we only read stripe pages off the disk, set them * up to date if there were no errors */ - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -2002,7 +1998,7 @@ static void raid_recover_end_io(struct bio *bio, int err) return; if (atomic_read(&rbio->error) > rbio->bbio->max_errors) - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); else __raid_recover_end_io(rbio); } @@ -2094,7 +2090,6 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } out: @@ -2102,7 +2097,7 @@ out: cleanup: if (rbio->operation == BTRFS_RBIO_READ_REBUILD) - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return -EIO; } @@ -2277,11 +2272,12 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio) * end io function used by finish_rmw. When we finally * get here, we've written a full stripe */ -static void raid_write_parity_end_io(struct bio *bio, int err) +static void raid_write_parity_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; + int err = bio->bi_error; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); bio_put(bio); @@ -2294,7 +2290,7 @@ static void raid_write_parity_end_io(struct bio *bio, int err) if (atomic_read(&rbio->error)) err = -EIO; - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); } static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, @@ -2437,7 +2433,7 @@ submit_write: nr_data = bio_list_size(&bio_list); if (!nr_data) { /* Every parity is right */ - rbio_orig_end_io(rbio, 0, 0); + rbio_orig_end_io(rbio, 0); return; } @@ -2450,13 +2446,12 @@ submit_write: bio->bi_private = rbio; bio->bi_end_io = raid_write_parity_end_io; - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(WRITE, bio); } return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe) @@ -2524,7 +2519,7 @@ static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio) return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } /* @@ -2535,11 +2530,11 @@ cleanup: * This will usually kick off finish_rmw once all the bios are read in, but it * may trigger parity reconstruction if we had any errors along the way */ -static void raid56_parity_scrub_end_io(struct bio *bio, int err) +static void raid56_parity_scrub_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -2632,14 +2627,13 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } /* the actual write will happen once the reads are done */ return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return; finish: diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 94db0fa5225a..ebb8260186fe 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -278,7 +278,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, struct btrfs_device *dev, u64 flags, u64 gen, int mirror_num, u8 *csum, int force, u64 physical_for_dev_replace); -static void scrub_bio_end_io(struct bio *bio, int err); +static void scrub_bio_end_io(struct bio *bio); static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); static void scrub_remap_extent(struct btrfs_fs_info *fs_info, @@ -295,7 +295,7 @@ static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx); static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, struct scrub_page *spage); static void scrub_wr_submit(struct scrub_ctx *sctx); -static void scrub_wr_bio_end_io(struct bio *bio, int err); +static void scrub_wr_bio_end_io(struct bio *bio); static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); static int write_page_nocow(struct scrub_ctx *sctx, u64 physical_for_dev_replace, struct page *page); @@ -1429,11 +1429,11 @@ struct scrub_bio_ret { int error; }; -static void scrub_bio_wait_endio(struct bio *bio, int error) +static void scrub_bio_wait_endio(struct bio *bio) { struct scrub_bio_ret *ret = bio->bi_private; - ret->error = error; + ret->error = bio->bi_error; complete(&ret->event); } @@ -1790,12 +1790,12 @@ static void scrub_wr_submit(struct scrub_ctx *sctx) btrfsic_submit_bio(WRITE, sbio->bio); } -static void scrub_wr_bio_end_io(struct bio *bio, int err) +static void scrub_wr_bio_end_io(struct bio *bio) { struct scrub_bio *sbio = bio->bi_private; struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - sbio->err = err; + sbio->err = bio->bi_error; sbio->bio = bio; btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper, @@ -2098,7 +2098,7 @@ static void scrub_submit(struct scrub_ctx *sctx) */ printk_ratelimited(KERN_WARNING "BTRFS: scrub_submit(bio bdev == NULL) is unexpected!\n"); - bio_endio(sbio->bio, -EIO); + bio_io_error(sbio->bio); } else { btrfsic_submit_bio(READ, sbio->bio); } @@ -2260,12 +2260,12 @@ leave_nomem: return 0; } -static void scrub_bio_end_io(struct bio *bio, int err) +static void scrub_bio_end_io(struct bio *bio) { struct scrub_bio *sbio = bio->bi_private; struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - sbio->err = err; + sbio->err = bio->bi_error; sbio->bio = bio; btrfs_queue_work(fs_info->scrub_workers, &sbio->work); @@ -2672,11 +2672,11 @@ static void scrub_parity_bio_endio_worker(struct btrfs_work *work) scrub_pending_bio_dec(sctx); } -static void scrub_parity_bio_endio(struct bio *bio, int error) +static void scrub_parity_bio_endio(struct bio *bio) { struct scrub_parity *sparity = (struct scrub_parity *)bio->bi_private; - if (error) + if (bio->bi_error) bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap, sparity->nsectors); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fbe7c104531c..8f2ca18c71f4 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5741,23 +5741,23 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, return 0; } -static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int err) +static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio) { bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; - bio_endio(bio, err); + bio_endio(bio); btrfs_put_bbio(bbio); } -static void btrfs_end_bio(struct bio *bio, int err) +static void btrfs_end_bio(struct bio *bio) { struct btrfs_bio *bbio = bio->bi_private; int is_orig_bio = 0; - if (err) { + if (bio->bi_error) { atomic_inc(&bbio->error); - if (err == -EIO || err == -EREMOTEIO) { + if (bio->bi_error == -EIO || bio->bi_error == -EREMOTEIO) { unsigned int stripe_index = btrfs_io_bio(bio)->stripe_index; struct btrfs_device *dev; @@ -5795,17 +5795,16 @@ static void btrfs_end_bio(struct bio *bio, int err) * beyond the tolerance of the btrfs bio */ if (atomic_read(&bbio->error) > bbio->max_errors) { - err = -EIO; + bio->bi_error = -EIO; } else { /* * this bio is actually up to date, we didn't * go over the max number of errors */ - set_bit(BIO_UPTODATE, &bio->bi_flags); - err = 0; + bio->bi_error = 0; } - btrfs_end_bbio(bbio, bio, err); + btrfs_end_bbio(bbio, bio); } else if (!is_orig_bio) { bio_put(bio); } @@ -5826,7 +5825,7 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root, struct btrfs_pending_bios *pending_bios; if (device->missing || !device->bdev) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } @@ -5973,8 +5972,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; bio->bi_iter.bi_sector = logical >> 9; - - btrfs_end_bbio(bbio, bio, -EIO); + bio->bi_error = -EIO; + btrfs_end_bbio(bbio, bio); } } diff --git a/fs/buffer.c b/fs/buffer.c index 1cf7a53a0277..7a49bb84ecb5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2957,14 +2957,14 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, } EXPORT_SYMBOL(generic_block_bmap); -static void end_bio_bh_io_sync(struct bio *bio, int err) +static void end_bio_bh_io_sync(struct bio *bio) { struct buffer_head *bh = bio->bi_private; if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags))) set_bit(BH_Quiet, &bh->b_state); - bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); + bh->b_end_io(bh, !bio->bi_error); bio_put(bio); } diff --git a/fs/direct-io.c b/fs/direct-io.c index 745d2342651a..e1639c8c14d5 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -285,7 +285,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); /* * Asynchronous IO callback. */ -static void dio_bio_end_aio(struct bio *bio, int error) +static void dio_bio_end_aio(struct bio *bio) { struct dio *dio = bio->bi_private; unsigned long remaining; @@ -318,7 +318,7 @@ static void dio_bio_end_aio(struct bio *bio, int error) * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static void dio_bio_end_io(struct bio *bio, int error) +static void dio_bio_end_io(struct bio *bio) { struct dio *dio = bio->bi_private; unsigned long flags; @@ -345,9 +345,9 @@ void dio_end_io(struct bio *bio, int error) struct dio *dio = bio->bi_private; if (dio->is_async) - dio_bio_end_aio(bio, error); + dio_bio_end_aio(bio); else - dio_bio_end_io(bio, error); + dio_bio_end_io(bio); } EXPORT_SYMBOL_GPL(dio_end_io); @@ -457,11 +457,10 @@ static struct bio *dio_await_one(struct dio *dio) */ static int dio_bio_complete(struct dio *dio, struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; unsigned i; - if (!uptodate) + if (bio->bi_error) dio->io_error = -EIO; if (dio->is_async && dio->rw == READ) { @@ -476,7 +475,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) } bio_put(bio); } - return uptodate ? 0 : -EIO; + return bio->bi_error; } /* diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5602450f03f6..aa95566f14be 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -61,7 +61,6 @@ static void buffer_io_error(struct buffer_head *bh) static void ext4_finish_bio(struct bio *bio) { int i; - int error = !test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; bio_for_each_segment_all(bvec, bio, i) { @@ -88,7 +87,7 @@ static void ext4_finish_bio(struct bio *bio) } #endif - if (error) { + if (bio->bi_error) { SetPageError(page); set_bit(AS_EIO, &page->mapping->flags); } @@ -107,7 +106,7 @@ static void ext4_finish_bio(struct bio *bio) continue; } clear_buffer_async_write(bh); - if (error) + if (bio->bi_error) buffer_io_error(bh); } while ((bh = bh->b_this_page) != head); bit_spin_unlock(BH_Uptodate_Lock, &head->b_state); @@ -310,27 +309,25 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) } /* BIO completion function for page writeback */ -static void ext4_end_bio(struct bio *bio, int error) +static void ext4_end_bio(struct bio *bio) { ext4_io_end_t *io_end = bio->bi_private; sector_t bi_sector = bio->bi_iter.bi_sector; BUG_ON(!io_end); bio->bi_end_io = NULL; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = 0; - if (error) { + if (bio->bi_error) { struct inode *inode = io_end->inode; ext4_warning(inode->i_sb, "I/O error %d writing to inode %lu " "(offset %llu size %ld starting block %llu)", - error, inode->i_ino, + bio->bi_error, inode->i_ino, (unsigned long long) io_end->offset, (long) io_end->size, (unsigned long long) bi_sector >> (inode->i_blkbits - 9)); - mapping_set_error(inode->i_mapping, error); + mapping_set_error(inode->i_mapping, bio->bi_error); } if (io_end->flag & EXT4_IO_END_UNWRITTEN) { diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index ec3ef93a52db..5de5b871c178 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -98,7 +98,7 @@ static inline bool ext4_bio_encrypted(struct bio *bio) * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static void mpage_end_io(struct bio *bio, int err) +static void mpage_end_io(struct bio *bio) { struct bio_vec *bv; int i; @@ -106,7 +106,7 @@ static void mpage_end_io(struct bio *bio, int err) if (ext4_bio_encrypted(bio)) { struct ext4_crypto_ctx *ctx = bio->bi_private; - if (err) { + if (bio->bi_error) { ext4_release_crypto_ctx(ctx); } else { INIT_WORK(&ctx->r.work, completion_pages); @@ -118,7 +118,7 @@ static void mpage_end_io(struct bio *bio, int err) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (!err) { + if (!bio->bi_error) { SetPageUptodate(page); } else { ClearPageUptodate(page); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 9bedfa8dd3a5..8f0baa7ffb50 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -29,13 +29,13 @@ static struct kmem_cache *extent_tree_slab; static struct kmem_cache *extent_node_slab; -static void f2fs_read_end_io(struct bio *bio, int err) +static void f2fs_read_end_io(struct bio *bio) { struct bio_vec *bvec; int i; if (f2fs_bio_encrypted(bio)) { - if (err) { + if (bio->bi_error) { f2fs_release_crypto_ctx(bio->bi_private); } else { f2fs_end_io_crypto_work(bio->bi_private, bio); @@ -46,7 +46,7 @@ static void f2fs_read_end_io(struct bio *bio, int err) bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; - if (!err) { + if (!bio->bi_error) { SetPageUptodate(page); } else { ClearPageUptodate(page); @@ -57,7 +57,7 @@ static void f2fs_read_end_io(struct bio *bio, int err) bio_put(bio); } -static void f2fs_write_end_io(struct bio *bio, int err) +static void f2fs_write_end_io(struct bio *bio) { struct f2fs_sb_info *sbi = bio->bi_private; struct bio_vec *bvec; @@ -68,7 +68,7 @@ static void f2fs_write_end_io(struct bio *bio, int err) f2fs_restore_and_release_control_page(&page); - if (unlikely(err)) { + if (unlikely(bio->bi_error)) { set_page_dirty(page); set_bit(AS_EIO, &page->mapping->flags); f2fs_stop_checkpoint(sbi); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 2c1ae861dc94..c0a1b967deba 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -202,22 +202,22 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec, * */ -static void gfs2_end_log_write(struct bio *bio, int error) +static void gfs2_end_log_write(struct bio *bio) { struct gfs2_sbd *sdp = bio->bi_private; struct bio_vec *bvec; struct page *page; int i; - if (error) { - sdp->sd_log_error = error; - fs_err(sdp, "Error %d writing to log\n", error); + if (bio->bi_error) { + sdp->sd_log_error = bio->bi_error; + fs_err(sdp, "Error %d writing to log\n", bio->bi_error); } bio_for_each_segment_all(bvec, bio, i) { page = bvec->bv_page; if (page_has_buffers(page)) - gfs2_end_log_write_bh(sdp, bvec, error); + gfs2_end_log_write_bh(sdp, bvec, bio->bi_error); else mempool_free(page, gfs2_page_pool); } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 1e3a93f2f71d..02586e7eb964 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -171,14 +171,14 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent) return -EINVAL; } -static void end_bio_io_page(struct bio *bio, int error) +static void end_bio_io_page(struct bio *bio) { struct page *page = bio->bi_private; - if (!error) + if (!bio->bi_error) SetPageUptodate(page); else - pr_warn("error %d reading superblock\n", error); + pr_warn("error %d reading superblock\n", bio->bi_error); unlock_page(page); } diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index bc462dcd7a40..d301acfdb80d 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2011,7 +2011,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) /*check if journaling to disk has been disabled*/ if (log->no_integrity) { bio->bi_iter.bi_size = 0; - lbmIODone(bio, 0); + lbmIODone(bio); } else { submit_bio(READ_SYNC, bio); } @@ -2158,7 +2158,7 @@ static void lbmStartIO(struct lbuf * bp) /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_iter.bi_size = 0; - lbmIODone(bio, 0); + lbmIODone(bio); } else { submit_bio(WRITE_SYNC, bio); INCREMENT(lmStat.submitted); @@ -2196,7 +2196,7 @@ static int lbmIOWait(struct lbuf * bp, int flag) * * executed at INTIODONE level */ -static void lbmIODone(struct bio *bio, int error) +static void lbmIODone(struct bio *bio) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; @@ -2212,7 +2212,7 @@ static void lbmIODone(struct bio *bio, int error) bp->l_flag |= lbmDONE; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { bp->l_flag |= lbmERROR; jfs_err("lbmIODone: I/O error in JFS log"); diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 16a0922beb59..a3eb316b1ac3 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -276,11 +276,11 @@ static void last_read_complete(struct page *page) unlock_page(page); } -static void metapage_read_end_io(struct bio *bio, int err) +static void metapage_read_end_io(struct bio *bio) { struct page *page = bio->bi_private; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { printk(KERN_ERR "metapage_read_end_io: I/O error\n"); SetPageError(page); } @@ -331,13 +331,13 @@ static void last_write_complete(struct page *page) end_page_writeback(page); } -static void metapage_write_end_io(struct bio *bio, int err) +static void metapage_write_end_io(struct bio *bio) { struct page *page = bio->bi_private; BUG_ON(!PagePrivate(page)); - if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { printk(KERN_ERR "metapage_write_end_io: I/O error\n"); SetPageError(page); } diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 76279e11982d..cea0cc9878b7 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -53,16 +53,14 @@ static int bdev_readpage(void *_sb, struct page *page) static DECLARE_WAIT_QUEUE_HEAD(wq); -static void writeseg_end_io(struct bio *bio, int err) +static void writeseg_end_io(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; int i; struct super_block *sb = bio->bi_private; struct logfs_super *super = logfs_super(sb); - BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ - BUG_ON(err); + BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ bio_for_each_segment_all(bvec, bio, i) { end_page_writeback(bvec->bv_page); @@ -153,14 +151,12 @@ static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len) } -static void erase_end_io(struct bio *bio, int err) +static void erase_end_io(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct super_block *sb = bio->bi_private; struct logfs_super *super = logfs_super(sb); - BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ - BUG_ON(err); + BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ BUG_ON(bio->bi_vcnt == 0); bio_put(bio); if (atomic_dec_and_test(&super->s_pending_writes)) diff --git a/fs/mpage.c b/fs/mpage.c index ca0244b69de8..abac9361b3f1 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -42,14 +42,14 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static void mpage_end_io(struct bio *bio, int err) +static void mpage_end_io(struct bio *bio) { struct bio_vec *bv; int i; bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - page_endio(page, bio_data_dir(bio), err); + page_endio(page, bio_data_dir(bio), bio->bi_error); } bio_put(bio); diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index d2554fe140a3..9cd4eb3a1e22 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -116,7 +116,7 @@ bl_submit_bio(int rw, struct bio *bio) static struct bio * bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector, - void (*end_io)(struct bio *, int err), struct parallel_io *par) + bio_end_io_t end_io, struct parallel_io *par) { struct bio *bio; @@ -139,8 +139,7 @@ bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector, static struct bio * do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect, struct page *page, struct pnfs_block_dev_map *map, - struct pnfs_block_extent *be, - void (*end_io)(struct bio *, int err), + struct pnfs_block_extent *be, bio_end_io_t end_io, struct parallel_io *par, unsigned int offset, int *len) { struct pnfs_block_dev *dev = @@ -183,11 +182,11 @@ retry: return bio; } -static void bl_end_io_read(struct bio *bio, int err) +static void bl_end_io_read(struct bio *bio) { struct parallel_io *par = bio->bi_private; - if (err) { + if (bio->bi_error) { struct nfs_pgio_header *header = par->data; if (!header->pnfs_error) @@ -316,13 +315,12 @@ out: return PNFS_ATTEMPTED; } -static void bl_end_io_write(struct bio *bio, int err) +static void bl_end_io_write(struct bio *bio) { struct parallel_io *par = bio->bi_private; - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct nfs_pgio_header *header = par->data; - if (!uptodate) { + if (bio->bi_error) { if (!header->pnfs_error) header->pnfs_error = -EIO; pnfs_set_lo_fail(header->lseg); diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 42468e5ab3e7..550b10efb14e 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -338,12 +338,11 @@ void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed) /* * BIO operations */ -static void nilfs_end_bio_write(struct bio *bio, int err) +static void nilfs_end_bio_write(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct nilfs_segment_buffer *segbuf = bio->bi_private; - if (!uptodate) + if (bio->bi_error) atomic_inc(&segbuf->sb_err); bio_put(bio); diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 16eff45727ee..140de3c93d2e 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -372,14 +372,13 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, wait_for_completion(&wc->wc_io_complete); } -static void o2hb_bio_end_io(struct bio *bio, - int error) +static void o2hb_bio_end_io(struct bio *bio) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; - if (error) { - mlog(ML_ERROR, "IO Error %d\n", error); - wc->wc_error = error; + if (bio->bi_error) { + mlog(ML_ERROR, "IO Error %d\n", bio->bi_error); + wc->wc_error = bio->bi_error; } o2hb_bio_wait_dec(wc, 1); diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 3859f5e27a4d..3714844a81d8 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -351,12 +351,11 @@ xfs_imap_valid( */ STATIC void xfs_end_bio( - struct bio *bio, - int error) + struct bio *bio) { xfs_ioend_t *ioend = bio->bi_private; - ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; + ioend->io_error = bio->bi_error; /* Toss bio and pass work off to an xfsdatad thread */ bio->bi_private = NULL; diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index a4b7d92e946c..01bd6781974e 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1096,8 +1096,7 @@ xfs_bwrite( STATIC void xfs_buf_bio_end_io( - struct bio *bio, - int error) + struct bio *bio) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; @@ -1105,10 +1104,10 @@ xfs_buf_bio_end_io( * don't overwrite existing errors - otherwise we can lose errors on * buffers that require multiple bios to complete. */ - if (error) { + if (bio->bi_error) { spin_lock(&bp->b_lock); if (!bp->b_io_error) - bp->b_io_error = error; + bp->b_io_error = bio->bi_error; spin_unlock(&bp->b_lock); } diff --git a/include/linux/bio.h b/include/linux/bio.h index 5e963a6d7c14..6b918177002d 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -195,8 +195,6 @@ static inline bool bvec_gap_to_prev(struct bio_vec *bprv, unsigned int offset) return offset || ((bprv->bv_offset + bprv->bv_len) & (PAGE_SIZE - 1)); } -#define bio_io_error(bio) bio_endio((bio), -EIO) - /* * drivers should _never_ use the all version - the bio may have been split * before it got to the driver and the driver won't own all of it @@ -426,7 +424,14 @@ static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask) } -extern void bio_endio(struct bio *, int); +extern void bio_endio(struct bio *); + +static inline void bio_io_error(struct bio *bio) +{ + bio->bi_error = -EIO; + bio_endio(bio); +} + struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); @@ -717,7 +722,7 @@ extern void bio_integrity_free(struct bio *); extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); extern bool bio_integrity_enabled(struct bio *bio); extern int bio_integrity_prep(struct bio *); -extern void bio_integrity_endio(struct bio *, int); +extern void bio_integrity_endio(struct bio *); extern void bio_integrity_advance(struct bio *, unsigned int); extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 7303b3405520..6164fb8a817b 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -14,7 +14,7 @@ struct page; struct block_device; struct io_context; struct cgroup_subsys_state; -typedef void (bio_end_io_t) (struct bio *, int); +typedef void (bio_end_io_t) (struct bio *); typedef void (bio_destructor_t) (struct bio *); /* @@ -53,6 +53,7 @@ struct bio { struct bvec_iter bi_iter; + int bi_error; /* Number of segments in this BIO after * physical address coalescing is performed. */ @@ -111,7 +112,6 @@ struct bio { /* * bio flags */ -#define BIO_UPTODATE 0 /* ok after I/O completion */ #define BIO_SEG_VALID 1 /* bi_phys_segments valid */ #define BIO_CLONED 2 /* doesn't own data */ #define BIO_BOUNCED 3 /* bio is a bounce bio */ diff --git a/include/linux/swap.h b/include/linux/swap.h index 38874729dc5f..31496d201fdc 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -373,9 +373,9 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t entry) /* linux/mm/page_io.c */ extern int swap_readpage(struct page *); extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern void end_swap_bio_write(struct bio *bio, int err); +extern void end_swap_bio_write(struct bio *bio); extern int __swap_writepage(struct page *page, struct writeback_control *wbc, - void (*end_write_func)(struct bio *, int)); + bio_end_io_t end_write_func); extern int swap_set_page_dirty(struct page *page); int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 2f30ca91e4fa..b2066fb5b10f 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -227,27 +227,23 @@ static void hib_init_batch(struct hib_bio_batch *hb) hb->error = 0; } -static void hib_end_io(struct bio *bio, int error) +static void hib_end_io(struct bio *bio) { struct hib_bio_batch *hb = bio->bi_private; - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate || error) { + if (bio->bi_error) { printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), (unsigned long long)bio->bi_iter.bi_sector); - - if (!error) - error = -EIO; } if (bio_data_dir(bio) == WRITE) put_page(page); - if (error && !hb->error) - hb->error = error; + if (bio->bi_error && !hb->error) + hb->error = bio->bi_error; if (atomic_dec_and_test(&hb->count)) wake_up(&hb->wait); diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index b3e6b39b6cf9..90e72a0c3047 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -778,9 +778,6 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, if (likely(!bt)) return; - if (!error && !bio_flagged(bio, BIO_UPTODATE)) - error = EIO; - __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, what, error, 0, NULL); } @@ -887,8 +884,7 @@ static void blk_add_trace_split(void *ignore, __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, - !bio_flagged(bio, BIO_UPTODATE), - sizeof(rpdu), &rpdu); + bio->bi_error, sizeof(rpdu), &rpdu); } } @@ -920,8 +916,8 @@ static void blk_add_trace_bio_remap(void *ignore, r.sector_from = cpu_to_be64(from); __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, - bio->bi_rw, BLK_TA_REMAP, - !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); + bio->bi_rw, BLK_TA_REMAP, bio->bi_error, + sizeof(r), &r); } /** diff --git a/mm/page_io.c b/mm/page_io.c index 520baa4b04d7..338ce68942a0 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -43,12 +43,11 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, return bio; } -void end_swap_bio_write(struct bio *bio, int err) +void end_swap_bio_write(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate) { + if (bio->bi_error) { SetPageError(page); /* * We failed to write the page out to swap-space. @@ -69,12 +68,11 @@ void end_swap_bio_write(struct bio *bio, int err) bio_put(bio); } -static void end_swap_bio_read(struct bio *bio, int err) +static void end_swap_bio_read(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate) { + if (bio->bi_error) { SetPageError(page); ClearPageUptodate(page); printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", @@ -254,7 +252,7 @@ static sector_t swap_page_sector(struct page *page) } int __swap_writepage(struct page *page, struct writeback_control *wbc, - void (*end_write_func)(struct bio *, int)) + bio_end_io_t end_write_func) { struct bio *bio; int ret, rw = WRITE; -- cgit v1.2.3-59-g8ed1b From 351169933ea22592fb42b97c76c4c130fe287cca Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 8 Jul 2015 17:57:40 +0300 Subject: usb: phy: qcom: New APQ8016/MSM8916 USB transceiver driver Driver handles PHY initialization, clock management, power management and workarounds required after resetting the hardware. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/qcom,usb-8x16-phy.txt | 76 ++++ drivers/usb/phy/Kconfig | 14 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/phy-qcom-8x16-usb.c | 436 +++++++++++++++++++++ 4 files changed, 527 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt create mode 100644 drivers/usb/phy/phy-qcom-8x16-usb.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt new file mode 100644 index 000000000000..2cb2168cef41 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt @@ -0,0 +1,76 @@ +Qualcomm's APQ8016/MSM8916 USB transceiver controller + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-8x16-phy". + +- reg: + Usage: required + Value type: + Definition: USB PHY base address and length of the register map + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + two clock specifiers for interface and core controller + clocks. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "iface" and "core" strings. + +- vddcx-supply: + Usage: required + Value type: + Definition: phandle to the regulator VDCCX supply node. + +- v1p8-supply: + Usage: required + Value type: + Definition: phandle to the regulator 1.8V supply node. + +- v3p3-supply: + Usage: required + Value type: + Definition: phandle to the regulator 3.3V supply node. + +- resets: + Usage: required + Value type: + Definition: See reset.txt section "consumers". PHY reset specifier. + +- reset-names: + Usage: required + Value type: + Definition: Must contain "phy" string. + +- switch-gpio: + Usage: optional + Value type: + Definition: Some boards are using Dual SPDT USB Switch, witch is + controlled by GPIO to de/multiplex D+/D- USB lines + between connectors. + +Example: + usb_phy: phy@78d9000 { + compatible = "qcom,usb-8x16-phy"; + reg = <0x78d9000 0x400>; + + vddcx-supply = <&pm8916_s1_corner>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + + clocks = <&gcc GCC_USB_HS_AHB_CLK>, + <&gcc GCC_USB_HS_SYSTEM_CLK>; + clock-names = "iface", "core"; + + resets = <&gcc GCC_USB2A_PHY_BCR>; + reset-names = "phy"; + + // D+/D- lines: 1 - Routed to HUB, 0 - Device connector + switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>; + }; + diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 869c0cfcad98..7d3beee2a587 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -152,6 +152,20 @@ config USB_MSM_OTG This driver is not supported on boards like trout which has an external PHY. +config USB_QCOM_8X16_PHY + tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support" + depends on ARCH_QCOM || COMPILE_TEST + depends on RESET_CONTROLLER + select USB_PHY + select USB_ULPI_VIEWPORT + help + Enable this to support the USB transceiver on Qualcomm 8x16 chipsets. + It handles PHY initialization, clock management, power management, + and workarounds required after resetting the hardware. + + To compile this driver as a module, choose M here: the + module will be called phy-qcom-8x16-usb. + config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index e36ab1d46d8b..19c0dccbb116 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o +obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c new file mode 100644 index 000000000000..5d357a94599e --- /dev/null +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HSPHY_AHBBURST 0x0090 +#define HSPHY_AHBMODE 0x0098 +#define HSPHY_GENCONFIG 0x009c +#define HSPHY_GENCONFIG_2 0x00a0 + +#define HSPHY_USBCMD 0x0140 +#define HSPHY_ULPI_VIEWPORT 0x0170 +#define HSPHY_CTRL 0x0240 + +#define HSPHY_TXFIFO_IDLE_FORCE_DIS BIT(4) +#define HSPHY_SESS_VLD_CTRL_EN BIT(7) +#define HSPHY_POR_ASSERT BIT(0) +#define HSPHY_RETEN BIT(1) + +#define HSPHY_SESS_VLD_CTRL BIT(25) + +#define ULPI_PWR_CLK_MNG_REG 0x88 +#define ULPI_PWR_OTG_COMP_DISABLE BIT(0) + +#define ULPI_MISC_A 0x96 +#define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +#define ULPI_MISC_A_VBUSVLDEXT BIT(0) + +#define HSPHY_3P3_MIN 3050000 /* uV */ +#define HSPHY_3P3_MAX 3300000 /* uV */ + +#define HSPHY_1P8_MIN 1800000 /* uV */ +#define HSPHY_1P8_MAX 1800000 /* uV */ + +#define HSPHY_VDD_MIN 5 +#define HSPHY_VDD_MAX 7 + +struct phy_8x16 { + struct usb_phy phy; + void __iomem *regs; + struct clk *core_clk; + struct clk *iface_clk; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vdd; + + struct reset_control *phy_reset; + + struct extcon_specific_cable_nb vbus_cable; + struct notifier_block vbus_notify; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot_notify; +}; + +static int phy_8x16_regulators_enable(struct phy_8x16 *qphy) +{ + int ret; + + ret = regulator_set_voltage(qphy->vdd, HSPHY_VDD_MIN, HSPHY_VDD_MAX); + if (ret) + return ret; + + ret = regulator_enable(qphy->vdd); + if (ret) + return ret; + + ret = regulator_set_voltage(qphy->v3p3, HSPHY_3P3_MIN, HSPHY_3P3_MAX); + if (ret) + goto off_vdd; + + ret = regulator_enable(qphy->v3p3); + if (ret) + goto off_vdd; + + ret = regulator_set_voltage(qphy->v1p8, HSPHY_1P8_MIN, HSPHY_1P8_MAX); + if (ret) + goto off_3p3; + + ret = regulator_enable(qphy->v1p8); + if (ret) + goto off_3p3; + + return 0; + +off_3p3: + regulator_disable(qphy->v3p3); +off_vdd: + regulator_disable(qphy->vdd); + + return ret; +} + +static void phy_8x16_regulators_disable(struct phy_8x16 *qphy) +{ + regulator_disable(qphy->v1p8); + regulator_disable(qphy->v3p3); + regulator_disable(qphy->vdd); +} + +static int phy_8x16_notify_connect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT; + usb_phy_io_write(&qphy->phy, val, ULPI_SET(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val |= HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL; + usb_phy_io_write(&qphy->phy, val, ULPI_CLR(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val &= ~HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_vbus_on(struct phy_8x16 *qphy) +{ + phy_8x16_notify_connect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + return 0; +} + +static int phy_8x16_vbus_off(struct phy_8x16 *qphy) +{ + phy_8x16_notify_disconnect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to USB HUB */ + gpiod_set_value_cansleep(qphy->switch_gpio, 1); + + return 0; +} + +static int phy_8x16_vbus_notify(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct phy_8x16 *qphy = container_of(nb, struct phy_8x16, vbus_notify); + + if (event) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + return NOTIFY_DONE; +} + +static int phy_8x16_init(struct usb_phy *phy) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val, init[] = {0x44, 0x6B, 0x24, 0x13}; + u32 addr = ULPI_EXT_VENDOR_SPECIFIC; + int idx, state; + + for (idx = 0; idx < ARRAY_SIZE(init); idx++) + usb_phy_io_write(phy, init[idx], addr + idx); + + reset_control_reset(qphy->phy_reset); + + /* Assert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val |= HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + /* + * wait for minimum 10 microseconds as suggested in HPG. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + usleep_range(12, 15); + + /* Deassert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val &= ~HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + usleep_range(10, 15); + + writel(0x00, qphy->regs + HSPHY_AHBBURST); + writel(0x08, qphy->regs + HSPHY_AHBMODE); + + /* workaround for rx buffer collision issue */ + val = readl(qphy->regs + HSPHY_GENCONFIG); + val &= ~HSPHY_TXFIFO_IDLE_FORCE_DIS; + writel(val, qphy->regs + HSPHY_GENCONFIG); + + val = readl(qphy->regs + HSPHY_GENCONFIG_2); + val |= HSPHY_SESS_VLD_CTRL_EN; + writel(val, qphy->regs + HSPHY_GENCONFIG_2); + + val = ULPI_PWR_OTG_COMP_DISABLE; + usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG)); + + state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB"); + if (state) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + val = usb_phy_io_read(&qphy->phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NORMAL; + usb_phy_io_write(&qphy->phy, val, ULPI_FUNC_CTRL); + + return 0; +} + +static void phy_8x16_shutdown(struct usb_phy *phy) +{ + u32 val; + + /* Put the controller in non-driving mode */ + val = usb_phy_io_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + usb_phy_io_write(phy, val, ULPI_FUNC_CTRL); +} + +static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) +{ + struct regulator_bulk_data regs[3]; + struct device *dev = qphy->phy.dev; + int ret; + + qphy->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(qphy->core_clk)) + return PTR_ERR(qphy->core_clk); + + qphy->iface_clk = devm_clk_get(dev, "iface"); + if (IS_ERR(qphy->iface_clk)) + return PTR_ERR(qphy->iface_clk); + + regs[0].supply = "v3p3"; + regs[1].supply = "v1p8"; + regs[2].supply = "vddcx"; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs); + if (ret) + return ret; + + qphy->v3p3 = regs[0].consumer; + qphy->v1p8 = regs[1].consumer; + qphy->vdd = regs[2].consumer; + + qphy->phy_reset = devm_reset_control_get(dev, "phy"); + if (IS_ERR(qphy->phy_reset)) + return PTR_ERR(qphy->phy_reset); + + qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(qphy->switch_gpio)) + return PTR_ERR(qphy->switch_gpio); + + return 0; +} + +static int phy_8x16_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct phy_8x16 *qphy; + + qphy = container_of(this, struct phy_8x16, reboot_notify); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + return NOTIFY_DONE; +} + +static int phy_8x16_probe(struct platform_device *pdev) +{ + struct extcon_dev *edev; + struct phy_8x16 *qphy; + struct resource *res; + struct usb_phy *phy; + int ret; + + qphy = devm_kzalloc(&pdev->dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + platform_set_drvdata(pdev, qphy); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!qphy->regs) + return -ENOMEM; + + phy = &qphy->phy; + phy->dev = &pdev->dev; + phy->label = dev_name(&pdev->dev); + phy->init = phy_8x16_init; + phy->shutdown = phy_8x16_shutdown; + phy->notify_connect = phy_8x16_notify_connect; + phy->notify_disconnect = phy_8x16_notify_disconnect; + phy->io_priv = qphy->regs + HSPHY_ULPI_VIEWPORT; + phy->io_ops = &ulpi_viewport_access_ops; + phy->type = USB_PHY_TYPE_USB2; + + ret = phy_8x16_read_devicetree(qphy); + if (ret < 0) + return ret; + + edev = extcon_get_edev_by_phandle(phy->dev, 0); + if (IS_ERR(edev)) + return PTR_ERR(edev); + + ret = clk_set_rate(qphy->core_clk, INT_MAX); + if (ret < 0) + dev_dbg(phy->dev, "Can't boost core clock\n"); + + ret = clk_prepare_enable(qphy->core_clk); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(qphy->iface_clk); + if (ret < 0) + goto off_core; + + ret = phy_8x16_regulators_enable(qphy); + if (0 && ret) + goto off_clks; + + qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; + ret = extcon_register_interest(&qphy->vbus_cable, edev->name, + "USB", &qphy->vbus_notify); + if (ret < 0) + goto off_power; + + ret = usb_add_phy_dev(&qphy->phy); + if (ret) + goto off_extcon; + + qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify; + register_reboot_notifier(&qphy->reboot_notify); + + return 0; + +off_extcon: + extcon_unregister_interest(&qphy->vbus_cable); +off_power: + phy_8x16_regulators_disable(qphy); +off_clks: + clk_disable_unprepare(qphy->iface_clk); +off_core: + clk_disable_unprepare(qphy->core_clk); + return ret; +} + +static int phy_8x16_remove(struct platform_device *pdev) +{ + struct phy_8x16 *qphy = platform_get_drvdata(pdev); + + unregister_reboot_notifier(&qphy->reboot_notify); + extcon_unregister_interest(&qphy->vbus_cable); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + usb_remove_phy(&qphy->phy); + + clk_disable_unprepare(qphy->iface_clk); + clk_disable_unprepare(qphy->core_clk); + phy_8x16_regulators_disable(qphy); + return 0; +} + +static const struct of_device_id phy_8x16_dt_match[] = { + { .compatible = "qcom,usb-8x16-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, phy_8x16_dt_match); + +static struct platform_driver phy_8x16_driver = { + .probe = phy_8x16_probe, + .remove = phy_8x16_remove, + .driver = { + .name = "phy-qcom-8x16-usb", + .of_match_table = phy_8x16_dt_match, + }, +}; +module_platform_driver(phy_8x16_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm APQ8016/MSM8916 chipsets USB transceiver driver"); -- cgit v1.2.3-59-g8ed1b From 744543c599c420bcddca08cd2e2713b82a008328 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:38 +0200 Subject: usb: musb: sunxi: Add support for the Allwinner sunxi musb controller This is based on initial code to get the Allwinner sunxi musb controller supported by Chen-Yu Tsai and Roman Byshko. This adds support for the Allwinner sunxi musb controller in both host only and otg mode. Peripheral only mode is not supported, as no boards use that. This has been tested on a cubietruck (A20 SoC) and an UTOO P66 tablet (A13 SoC) with a variety of devices in host mode and with the g_serial gadget driver in peripheral mode, plugging otg / host cables in/out a lot of times in all possible imaginable plug orders. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../bindings/usb/allwinner,sun4i-a10-musb.txt | 27 + drivers/usb/musb/Kconfig | 13 +- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/sunxi.c | 703 +++++++++++++++++++++ 4 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt create mode 100644 drivers/usb/musb/sunxi.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt new file mode 100644 index 000000000000..9254a6c81808 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -0,0 +1,27 @@ +Allwinner sun4i A10 musb DRC/OTG controller +------------------------------------------- + +Required properties: + - compatible : "allwinner,sun4i-a10-musb" + - reg : mmio address range of the musb controller + - clocks : clock specifier for the musb controller ahb gate clock + - interrupts : interrupt to which the musb controller is connected + - interrupt-names : must be "mc" + - phys : phy specifier for the otg phy + - phy-names : must be "usb" + - dr_mode : Dual-Role mode must be "host" or "otg" + - extcon : extcon specifier for the otg phy + +Example: + + usb_otg: usb@01c13000 { + compatible = "allwinner,sun4i-a10-musb"; + reg = <0x01c13000 0x0400>; + clocks = <&ahb_gates 0>; + interrupts = <38>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 39db8b603627..37081ed8f295 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -5,7 +5,7 @@ # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' + tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)' depends on (USB || USB_GADGET) help Say Y here if your system has a dual role high speed USB @@ -20,6 +20,8 @@ config USB_MUSB_HDRC Analog Devices parts using this IP include Blackfin BF54x, BF525 and BF527. + Allwinner SoCs using this IP include A10, A13, A20, ... + If you do not know what this is, please say N. To compile this driver as a module, choose M here; the @@ -60,6 +62,15 @@ endchoice comment "Platform Glue Layer" +config USB_MUSB_SUNXI + tristate "Allwinner (sunxi)" + depends on ARCH_SUNXI + depends on NOP_USB_XCEIV + depends on PHY_SUN4I_USB + depends on EXTCON + depends on GENERIC_PHY + select SUNXI_SRAM + config USB_MUSB_DAVINCI tristate "DaVinci" depends on ARCH_DAVINCI_DMx diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index ba495018b416..f95befe18cc1 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o +obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c new file mode 100644 index 000000000000..00d7248a4840 --- /dev/null +++ b/drivers/usb/musb/sunxi.c @@ -0,0 +1,703 @@ +/* + * Allwinner sun4i MUSB Glue Layer + * + * Copyright (C) 2015 Hans de Goede + * + * Based on code from + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "musb_core.h" + +/* + * Register offsets, note sunxi musb has a different layout then most + * musb implementations, we translate the layout in musb_readb & friends. + */ +#define SUNXI_MUSB_POWER 0x0040 +#define SUNXI_MUSB_DEVCTL 0x0041 +#define SUNXI_MUSB_INDEX 0x0042 +#define SUNXI_MUSB_VEND0 0x0043 +#define SUNXI_MUSB_INTRTX 0x0044 +#define SUNXI_MUSB_INTRRX 0x0046 +#define SUNXI_MUSB_INTRTXE 0x0048 +#define SUNXI_MUSB_INTRRXE 0x004a +#define SUNXI_MUSB_INTRUSB 0x004c +#define SUNXI_MUSB_INTRUSBE 0x0050 +#define SUNXI_MUSB_FRAME 0x0054 +#define SUNXI_MUSB_TXFIFOSZ 0x0090 +#define SUNXI_MUSB_TXFIFOADD 0x0092 +#define SUNXI_MUSB_RXFIFOSZ 0x0094 +#define SUNXI_MUSB_RXFIFOADD 0x0096 +#define SUNXI_MUSB_FADDR 0x0098 +#define SUNXI_MUSB_TXFUNCADDR 0x0098 +#define SUNXI_MUSB_TXHUBADDR 0x009a +#define SUNXI_MUSB_TXHUBPORT 0x009b +#define SUNXI_MUSB_RXFUNCADDR 0x009c +#define SUNXI_MUSB_RXHUBADDR 0x009e +#define SUNXI_MUSB_RXHUBPORT 0x009f +#define SUNXI_MUSB_CONFIGDATA 0x00c0 + +/* VEND0 bits */ +#define SUNXI_MUSB_VEND0_PIO_MODE 0 + +/* flags */ +#define SUNXI_MUSB_FL_ENABLED 0 +#define SUNXI_MUSB_FL_HOSTMODE 1 +#define SUNXI_MUSB_FL_HOSTMODE_PEND 2 +#define SUNXI_MUSB_FL_VBUS_ON 3 +#define SUNXI_MUSB_FL_PHY_ON 4 + +/* Our read/write methods need access and do not get passed in a musb ref :| */ +static struct musb *sunxi_musb; + +struct sunxi_glue { + struct device *dev; + struct platform_device *musb; + struct clk *clk; + struct phy *phy; + struct platform_device *usb_phy; + struct usb_phy *xceiv; + unsigned long flags; + struct work_struct work; + struct extcon_dev *extcon; + struct notifier_block host_nb; +}; + +/* phy_power_on / off may sleep, so we use a workqueue */ +static void sunxi_musb_work(struct work_struct *work) +{ + struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work); + bool vbus_on, phy_on; + + if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { + struct musb *musb = platform_get_drvdata(glue->musb); + unsigned long flags; + u8 devctl; + + spin_lock_irqsave(&musb->lock, flags); + + devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL); + if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 1; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + devctl |= MUSB_DEVCTL_SESSION; + } else { + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 0; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + devctl &= ~MUSB_DEVCTL_SESSION; + } + writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL); + + spin_unlock_irqrestore(&musb->lock, flags); + } + + vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + + if (phy_on != vbus_on) { + if (vbus_on) { + phy_power_on(glue->phy); + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } else { + phy_power_off(glue->phy); + clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } + } +} + +static void sunxi_musb_set_vbus(struct musb *musb, int is_on) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + if (is_on) + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + + schedule_work(&glue->work); +} + +static void sunxi_musb_pre_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, false); +} + +static void sunxi_musb_post_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, true); +} + +static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) +{ + struct musb *musb = __hci; + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB); + if (musb->int_usb) + writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB); + + /* + * sunxi musb often signals babble on low / full speed device + * disconnect, without ever raising MUSB_INTR_DISCONNECT, since + * normally babble never happens treat it as disconnect. + */ + if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) { + musb->int_usb &= ~MUSB_INTR_BABBLE; + musb->int_usb |= MUSB_INTR_DISCONNECT; + } + + if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) { + /* ep0 FADDR must be 0 when (re)entering peripheral mode */ + musb_ep_select(musb->mregs, 0); + musb_writeb(musb->mregs, MUSB_FADDR, 0); + } + + musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX); + if (musb->int_tx) + writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX); + + musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX); + if (musb->int_rx) + writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX); + + musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return IRQ_HANDLED; +} + +static int sunxi_musb_host_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb); + + if (event) + set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + + set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags); + schedule_work(&glue->work); + + return NOTIFY_DONE; +} + +static int sunxi_musb_init(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + int ret; + + sunxi_musb = musb; + musb->phy = glue->phy; + musb->xceiv = glue->xceiv; + + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + + ret = clk_prepare_enable(glue->clk); + if (ret) + goto error_sram_release; + + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); + + /* Register notifier before calling phy_init() */ + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) { + ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + if (ret) + goto error_clk_disable; + } + + ret = phy_init(glue->phy); + if (ret) + goto error_unregister_notifier; + + if (musb->port_mode == MUSB_PORT_MODE_HOST) { + ret = phy_power_on(glue->phy); + if (ret) + goto error_phy_exit; + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + /* Stop musb work from turning vbus off again */ + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + } + + musb->isr = sunxi_musb_interrupt; + + /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ + pm_runtime_get(musb->controller); + + return 0; + +error_phy_exit: + phy_exit(glue->phy); +error_unregister_notifier: + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); +error_clk_disable: + clk_disable_unprepare(glue->clk); +error_sram_release: + sunxi_sram_release(musb->controller->parent); + return ret; +} + +static int sunxi_musb_exit(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + pm_runtime_put(musb->controller); + + cancel_work_sync(&glue->work); + if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags)) + phy_power_off(glue->phy); + + phy_exit(glue->phy); + + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + + clk_disable_unprepare(glue->clk); + sunxi_sram_release(musb->controller->parent); + + return 0; +} + +static void sunxi_musb_enable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + /* musb_core does not call us in a balanced manner */ + if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + schedule_work(&glue->work); +} + +static void sunxi_musb_disable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags); +} + +/* + * sunxi musb register layout + * 0x00 - 0x17 fifo regs, 1 long per fifo + * 0x40 - 0x57 generic control regs (power - frame) + * 0x80 - 0x8f ep control regs (addressed through hw_ep->regs, indexed) + * 0x90 - 0x97 fifo control regs (indexed) + * 0x98 - 0x9f multipoint / busctl regs (indexed) + * 0xc0 configdata reg + */ + +static u32 sunxi_musb_fifo_offset(u8 epnum) +{ + return (epnum * 4); +} + +static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset) +{ + WARN_ONCE(offset != 0, + "sunxi_musb_ep_offset called with non 0 offset\n"); + + return 0x80; /* indexed, so ignore epnum */ +} + +static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) +{ + return SUNXI_MUSB_TXFUNCADDR + offset; +} + +static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return readb(addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return readb(addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return readb(addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return readb(addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return readb(addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + return 0; /* No testmode on sunxi */ + case MUSB_DEVCTL: + return readb(addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return readb(addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return readb(addr + SUNXI_MUSB_RXFIFOSZ); + case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + return readb(addr + SUNXI_MUSB_CONFIGDATA); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return readb(addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readb offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + /* sunxi has a 2 byte hole before the txtype register */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return readb(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return writeb(data, addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return writeb(data, addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return writeb(data, addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return writeb(data, addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return writeb(data, addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + if (data) + dev_warn(sunxi_musb->controller->parent, + "sunxi-musb does not have testmode\n"); + return; + case MUSB_DEVCTL: + return writeb(data, addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return writeb(data, addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return writeb(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static u16 sunxi_musb_readw(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return readw(addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return readw(addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return readw(addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return readw(addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return readw(addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return readw(addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return readw(addr + SUNXI_MUSB_RXFIFOADD); + case MUSB_HWVERS: + return 0; /* sunxi musb version is not known */ + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readw offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return readw(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readw at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return writew(data, addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return writew(data, addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return writew(data, addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return writew(data, addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return writew(data, addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return writew(data, addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return writew(data, addr + SUNXI_MUSB_RXFIFOADD); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writew offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return writew(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writew at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static const struct musb_platform_ops sunxi_musb_ops = { + .quirks = MUSB_INDEXED_EP, + .init = sunxi_musb_init, + .exit = sunxi_musb_exit, + .enable = sunxi_musb_enable, + .disable = sunxi_musb_disable, + .fifo_offset = sunxi_musb_fifo_offset, + .ep_offset = sunxi_musb_ep_offset, + .busctl_offset = sunxi_musb_busctl_offset, + .readb = sunxi_musb_readb, + .writeb = sunxi_musb_writeb, + .readw = sunxi_musb_readw, + .writew = sunxi_musb_writew, + .set_vbus = sunxi_musb_set_vbus, + .pre_root_reset_end = sunxi_musb_pre_root_reset_end, + .post_root_reset_end = sunxi_musb_post_root_reset_end, +}; + +/* Allwinner OTG supports up to 5 endpoints */ +#define SUNXI_MUSB_MAX_EP_NUM 6 +#define SUNXI_MUSB_RAM_BITS 11 + +static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { + MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), +}; + +static struct musb_hdrc_config sunxi_musb_hdrc_config = { + .fifo_cfg = sunxi_musb_mode_cfg, + .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), + .multipoint = true, + .dyn_fifo = true, + .soft_con = true, + .num_eps = SUNXI_MUSB_MAX_EP_NUM, + .ram_bits = SUNXI_MUSB_RAM_BITS, + .dma = 0, +}; + +static int sunxi_musb_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data pdata; + struct platform_device_info pinfo; + struct sunxi_glue *glue; + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!np) { + dev_err(&pdev->dev, "Error no device tree node found\n"); + return -EINVAL; + } + + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + memset(&pdata, 0, sizeof(pdata)); + switch (of_usb_get_dr_mode(np)) { +#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST + case USB_DR_MODE_HOST: + pdata.mode = MUSB_PORT_MODE_HOST; + break; +#endif +#ifdef CONFIG_USB_MUSB_DUAL_ROLE + case USB_DR_MODE_OTG: + glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); + if (IS_ERR(glue->extcon)) { + if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Invalid or missing extcon\n"); + return PTR_ERR(glue->extcon); + } + pdata.mode = MUSB_PORT_MODE_DUAL_ROLE; + break; +#endif + default: + dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n"); + return -EINVAL; + } + pdata.platform_ops = &sunxi_musb_ops; + pdata.config = &sunxi_musb_hdrc_config; + + glue->dev = &pdev->dev; + INIT_WORK(&glue->work, sunxi_musb_work); + glue->host_nb.notifier_call = sunxi_musb_host_notifier; + + glue->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(glue->clk)) { + dev_err(&pdev->dev, "Error getting clock: %ld\n", + PTR_ERR(glue->clk)); + return PTR_ERR(glue->clk); + } + + glue->phy = devm_phy_get(&pdev->dev, "usb"); + if (IS_ERR(glue->phy)) { + if (PTR_ERR(glue->phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting phy %ld\n", + PTR_ERR(glue->phy)); + return PTR_ERR(glue->phy); + } + + glue->usb_phy = usb_phy_generic_register(); + if (IS_ERR(glue->usb_phy)) { + dev_err(&pdev->dev, "Error registering usb-phy %ld\n", + PTR_ERR(glue->usb_phy)); + return PTR_ERR(glue->usb_phy); + } + + glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + if (IS_ERR(glue->xceiv)) { + ret = PTR_ERR(glue->xceiv); + dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret); + goto err_unregister_usb_phy; + } + + platform_set_drvdata(pdev, glue); + + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.name = "musb-hdrc"; + pinfo.id = PLATFORM_DEVID_AUTO; + pinfo.parent = &pdev->dev; + pinfo.res = pdev->resource; + pinfo.num_res = pdev->num_resources; + pinfo.data = &pdata; + pinfo.size_data = sizeof(pdata); + + glue->musb = platform_device_register_full(&pinfo); + if (IS_ERR(glue->musb)) { + ret = PTR_ERR(glue->musb); + dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); + goto err_unregister_usb_phy; + } + + return 0; + +err_unregister_usb_phy: + usb_phy_generic_unregister(glue->usb_phy); + return ret; +} + +static int sunxi_musb_remove(struct platform_device *pdev) +{ + struct sunxi_glue *glue = platform_get_drvdata(pdev); + struct platform_device *usb_phy = glue->usb_phy; + + platform_device_unregister(glue->musb); /* Frees glue ! */ + usb_phy_generic_unregister(usb_phy); + + return 0; +} + +static const struct of_device_id sunxi_musb_match[] = { + { .compatible = "allwinner,sun4i-a10-musb", }, + {} +}; + +static struct platform_driver sunxi_musb_driver = { + .probe = sunxi_musb_probe, + .remove = sunxi_musb_remove, + .driver = { + .name = "musb-sunxi", + .of_match_table = sunxi_musb_match, + }, +}; +module_platform_driver(sunxi_musb_driver); + +MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 132e23775779cc895c37f7883c33a60a1a8a7cdd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:39 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A31 SoC The A31 SoC uses the same musb controller as found in earlier SoCs, but it is hooked up slightly different. Its SRAM is private and no longer controlled through the SRAM controller, and its reset is controlled via a separate reset controller. This commit adds support for this setup. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../bindings/usb/allwinner,sun4i-a10-musb.txt | 3 +- drivers/usb/musb/sunxi.c | 50 +++++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index 9254a6c81808..fde180bfb162 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,9 +2,10 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" + - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock + - reset : reset specifier for the ahb reset (A31 and newer only) - interrupts : interrupt to which the musb controller is connected - interrupt-names : must be "mc" - phys : phy specifier for the otg phy diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 00d7248a4840..df2f75eb9895 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ #define SUNXI_MUSB_FL_HOSTMODE_PEND 2 #define SUNXI_MUSB_FL_VBUS_ON 3 #define SUNXI_MUSB_FL_PHY_ON 4 +#define SUNXI_MUSB_FL_HAS_SRAM 5 +#define SUNXI_MUSB_FL_HAS_RESET 6 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -78,6 +81,7 @@ struct sunxi_glue { struct device *dev; struct platform_device *musb; struct clk *clk; + struct reset_control *rst; struct phy *phy; struct platform_device *usb_phy; struct usb_phy *xceiv; @@ -229,14 +233,22 @@ static int sunxi_musb_init(struct musb *musb) musb->phy = glue->phy; musb->xceiv = glue->xceiv; - ret = sunxi_sram_claim(musb->controller->parent); - if (ret) - return ret; + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) { + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + } ret = clk_prepare_enable(glue->clk); if (ret) goto error_sram_release; + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + ret = reset_control_deassert(glue->rst); + if (ret) + goto error_clk_disable; + } + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ @@ -244,7 +256,7 @@ static int sunxi_musb_init(struct musb *musb) ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); if (ret) - goto error_clk_disable; + goto error_reset_assert; } ret = phy_init(glue->phy); @@ -273,10 +285,14 @@ error_unregister_notifier: if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); +error_reset_assert: + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); error_clk_disable: clk_disable_unprepare(glue->clk); error_sram_release: - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return ret; } @@ -296,8 +312,12 @@ static int sunxi_musb_exit(struct musb *musb) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); + clk_disable_unprepare(glue->clk); - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return 0; } @@ -617,6 +637,12 @@ static int sunxi_musb_probe(struct platform_device *pdev) INIT_WORK(&glue->work, sunxi_musb_work); glue->host_nb.notifier_call = sunxi_musb_host_notifier; + if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb")) + set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags); + + if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -624,6 +650,17 @@ static int sunxi_musb_probe(struct platform_device *pdev) return PTR_ERR(glue->clk); } + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + glue->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(glue->rst)) { + if (PTR_ERR(glue->rst) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting reset %ld\n", + PTR_ERR(glue->rst)); + return PTR_ERR(glue->rst); + } + } + glue->phy = devm_phy_get(&pdev->dev, "usb"); if (IS_ERR(glue->phy)) { if (PTR_ERR(glue->phy) == -EPROBE_DEFER) @@ -685,6 +722,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, + { .compatible = "allwinner,sun6i-a31-musb", }, {} }; -- cgit v1.2.3-59-g8ed1b From d91de093d94eca6e280e50c24b172ed598bb5724 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:40 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A33 SoC The A33 SoC uses the same musb controller as found on the A31 and later, but allwinner has removed the configdata register, this commit adds special handling for this. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt | 3 ++- drivers/usb/musb/sunxi.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index fde180bfb162..862cd7c79805 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,7 +2,8 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" + - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb" + or "allwinner,sun8i-a33-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock - reset : reset specifier for the ahb reset (A31 and newer only) diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index df2f75eb9895..f9f6304ad854 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -73,6 +73,7 @@ #define SUNXI_MUSB_FL_PHY_ON 4 #define SUNXI_MUSB_FL_HAS_SRAM 5 #define SUNXI_MUSB_FL_HAS_RESET 6 +#define SUNXI_MUSB_FL_NO_CONFIGDATA 7 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -370,6 +371,8 @@ static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) { + struct sunxi_glue *glue; + if (addr == sunxi_musb->mregs) { /* generic control or fifo control reg access */ switch (offset) { @@ -392,6 +395,12 @@ static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) case MUSB_RXFIFOSZ: return readb(addr + SUNXI_MUSB_RXFIFOSZ); case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + glue = dev_get_drvdata(sunxi_musb->controller->parent); + /* A33 saves a reg, and we get to hardcode this */ + if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, + &glue->flags)) + return 0xde; + return readb(addr + SUNXI_MUSB_CONFIGDATA); /* Offset for these is fixed by sunxi_musb_busctl_offset() */ case SUNXI_MUSB_TXFUNCADDR: @@ -643,6 +652,11 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) { + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags); + } + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -723,6 +737,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, { .compatible = "allwinner,sun6i-a31-musb", }, + { .compatible = "allwinner,sun8i-a33-musb", }, {} }; -- cgit v1.2.3-59-g8ed1b From b5513dede7c90ba2370ab5eb547568a22991907b Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:43 +0800 Subject: doc: dt-binding: usb: add otg related properties Add otg version, srp, hnp and adp support for usb OTG port, then those OTG features don't have to be decided by usb gadget drivers. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/generic.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt index 477d5bb5e51c..bba825711873 100644 --- a/Documentation/devicetree/bindings/usb/generic.txt +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -11,6 +11,19 @@ Optional properties: "peripheral" and "otg". In case this attribute isn't passed via DT, USB DRD controllers should default to OTG. + - otg-rev: tells usb driver the release number of the OTG and EH supplement + with which the device and its descriptors are compliant, + in binary-coded decimal (i.e. 2.0 is 0200H). This + property is used if any real OTG features(HNP/SRP/ADP) + is enabled, if ADP is required, otg-rev should be + 0x0200 or above. + - hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP + is the basic function of real OTG except you want it + to be a srp-capable only B device. + - srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is + optional for OTG device. + - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is + optional for OTG device. This is an attribute to a USB controller such as: @@ -21,4 +34,6 @@ dwc3@4a030000 { usb-phy = <&usb2_phy>, <&usb3,phy>; maximum-speed = "super-speed"; dr_mode = "otg"; + otg-rev = <0x0200>; + adp-disable; }; -- cgit v1.2.3-59-g8ed1b From 72c10fef98fc3b3c924ee022e451872517e61ecf Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Jul 2015 20:20:29 -0700 Subject: soc: qcom: Add device tree binding for Shared Memory Device Add device tree binding documentation for the Qualcomm Shared Memory Device, used for communication between the various CPUs in the Qualcomm SoCs. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- .../devicetree/bindings/soc/qcom/qcom,smd.txt | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt new file mode 100644 index 000000000000..f65c76db9859 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt @@ -0,0 +1,79 @@ +Qualcomm Shared Memory Driver (SMD) binding + +This binding describes the Qualcomm Shared Memory Driver, a fifo based +communication channel for sending data between the various subsystems in +Qualcomm platforms. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,smd" + += EDGES + +Each subnode of the SMD node represents a remote subsystem or a remote +processor of some sort - or in SMD language an "edge". The name of the edges +are not important. +The edge is described by the following properties: + +- interrupts: + Usage: required + Value type: + Definition: should specify the IRQ used by the remote processor to + signal this processor about communication related updates + +- qcom,ipc: + Usage: required + Value type: + Definition: three entries specifying the outgoing ipc bit used for + signaling the remote processor: + - phandle to a syscon node representing the apcs registers + - u32 representing offset to the register within the syscon + - u32 representing the ipc bit within the register + +- qcom,smd-edge: + Usage: required + Value type: + Definition: the identifier of the remote processor in the smd channel + allocation table + += SMD DEVICES + +In turn, subnodes of the "edges" represent devices tied to SMD channels on that +"edge". The names of the devices are not important. The properties of these +nodes are defined by the individual bindings for the SMD devices - but must +contain the following property: + +- qcom,smd-channels: + Usage: required + Value type: + Definition: a list of channels tied to this device, used for matching + the device to channels + += EXAMPLE + +The following example represents a smd node, with one edge representing the +"rpm" subsystem. For the "rpm" subsystem we have a device tied to the +"rpm_request" channel. + + apcs: syscon@f9011000 { + compatible = "syscon"; + reg = <0xf9011000 0x1000>; + }; + + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8974"; + qcom,smd-channels = "rpm_requests"; + + ... + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From ba68227e610cec8e0bef7da7e04af3f479d9797d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Jul 2015 20:20:31 -0700 Subject: devicetree: soc: Add Qualcomm SMD based RPM DT binding Add binding documentation for the Qualcomm Resource Power Manager (RPM) using shared memory (Qualcomm SMD) as transport mechanism. This is found in 8974 and newer based devices. The binding currently describes the rpm itself and the regulator subnodes. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- .../devicetree/bindings/soc/qcom,smd-rpm.txt | 117 +++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt new file mode 100644 index 000000000000..e27f5c4c54fd --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt @@ -0,0 +1,117 @@ +Qualcomm Resource Power Manager (RPM) over SMD + +This driver is used to interface with the Resource Power Manager (RPM) found in +various Qualcomm platforms. The RPM allows each component in the system to vote +for state of the system resources, such as clocks, regulators and bus +frequencies. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-msm8974" + +- qcom,smd-channels: + Usage: required + Value type: + Definition: Shared Memory channel used for communication with the RPM + += SUBDEVICES + +The RPM exposes resources to its subnodes. The below bindings specify the set +of valid subnodes that can operate on these resources. + +== Regulators + +Regulator nodes are identified by their compatible: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-pm8841-regulators" + "qcom,rpm-pm8941-regulators" + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: + Usage: optional (pm8841 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_l1_l3-supply: +- vdd_l2_lvs1_2_3-supply: +- vdd_l4_l11-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l14_l15-supply: +- vdd_l8_l16_l18_l19-supply: +- vdd_l9_l10_l17_l22-supply: +- vdd_l13_l20_l23_l24-supply: +- vdd_l21-supply: +- vin_5vs-supply: + Usage: optional (pm8941 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +The regulator node houses sub-nodes for each regulator within the device. Each +sub-node is identified using the node's name, with valid values listed for each +of the pmics below. + +pm8841: + s1, s2, s3, s4, s5, s6, s7, s8 + +pm8941: + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, + lvs3, 5vs1, 5vs2 + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt. + += EXAMPLE + + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8974"; + qcom,smd-channels = "rpm_requests"; + + pm8941-regulators { + compatible = "qcom,rpm-pm8941-regulators"; + vdd_l13_l20_l23_l24-supply = <&pm8941_boost>; + + pm8941_s3: s3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8941_boost: s4 { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + pm8941_l20: l20 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + }; + }; + }; + }; + -- cgit v1.2.3-59-g8ed1b From 6aad8bf99338fca5a6ef602f2d7e04546f79fd03 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 27 Jul 2015 15:42:21 -0700 Subject: arm64: dts: Add Broadcom North Star 2 support Add Broadcom NS2 device tree binding document. Also add initial device tree dtsi for Broadcom North Star 2 (NS2) SoC and board support for NS2 SVK board Signed-off-by: Jon Mason Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Olof Johansson --- Documentation/devicetree/bindings/arm/bcm/ns2.txt | 9 ++ arch/arm64/boot/dts/Makefile | 1 + arch/arm64/boot/dts/broadcom/Makefile | 5 + arch/arm64/boot/dts/broadcom/ns2-svk.dts | 59 +++++++++++ arch/arm64/boot/dts/broadcom/ns2.dtsi | 118 ++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/bcm/ns2.txt create mode 100644 arch/arm64/boot/dts/broadcom/Makefile create mode 100644 arch/arm64/boot/dts/broadcom/ns2-svk.dts create mode 100644 arch/arm64/boot/dts/broadcom/ns2.dtsi (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/bcm/ns2.txt b/Documentation/devicetree/bindings/arm/bcm/ns2.txt new file mode 100644 index 000000000000..35f056f4a1c3 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm/ns2.txt @@ -0,0 +1,9 @@ +Broadcom North Star 2 (NS2) device tree bindings +------------------------------------------------ + +Boards with NS2 shall have the following properties: + +Required root node property: + +NS2 SVK board +compatible = "brcm,ns2-svk", "brcm,ns2"; diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 0c57290c8ba9..1560478d6eb2 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -1,6 +1,7 @@ dts-dirs += amd dts-dirs += apm dts-dirs += arm +dts-dirs += broadcom dts-dirs += cavium dts-dirs += exynos dts-dirs += freescale diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile new file mode 100644 index 000000000000..e21fe66f1837 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/Makefile @@ -0,0 +1,5 @@ +dtb-$(CONFIG_ARCH_BCM_IPROC) += ns2-svk.dtb + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts new file mode 100644 index 000000000000..244baf879dc9 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts @@ -0,0 +1,59 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2015 Broadcom Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/dts-v1/; + +#include "ns2.dtsi" + +/ { + model = "Broadcom NS2 SVK"; + compatible = "brcm,ns2-svk", "brcm,ns2"; + + aliases { + serial0 = &uart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + device_type = "memory"; + reg = <0x000000000 0x80000000 0x00000000 0x40000000>; + }; + + soc: soc { + uart3: serial@66130000 { + status = "ok"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi new file mode 100644 index 000000000000..3c92d92278e5 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi @@ -0,0 +1,118 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2015 Broadcom Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/memreserve/ 0x84b00000 0x00000008; + +/ { + compatible = "brcm,ns2"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0 0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x84b00000>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0 1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x84b00000>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0 2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x84b00000>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0 3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x84b00000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + + gic: interrupt-controller@65210000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x65210000 0x1000>, + <0x65220000 0x1000>, + <0x65240000 0x2000>, + <0x65260000 0x1000>; + }; + + uart3: serial@66130000 { + compatible = "snps,dw-apb-uart"; + reg = <0x66130000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <23961600>; + status = "disabled"; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From ee2b7f60a5c5e391fdde907ac61f135d87e74622 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Thu, 16 Jul 2015 16:55:31 -0700 Subject: ARM: dts: qcom: Add binding for the qcom coincell charger This binding is used to configure the driver for the coincell charger found in Qualcomm PMICs. Signed-off-by: Tim Bird Reviewed-by: Andy Gross Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../bindings/power/qcom,coincell-charger.txt | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/qcom,coincell-charger.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/qcom,coincell-charger.txt b/Documentation/devicetree/bindings/power/qcom,coincell-charger.txt new file mode 100644 index 000000000000..0e6d8754e7ec --- /dev/null +++ b/Documentation/devicetree/bindings/power/qcom,coincell-charger.txt @@ -0,0 +1,48 @@ +Qualcomm Coincell Charger: + +The hardware block controls charging for a coincell or capacitor that is +used to provide power backup for certain features of the power management +IC (PMIC) + +- compatible: + Usage: required + Value type: + Definition: must be: "qcom,pm8941-coincell" + +- reg: + Usage: required + Value type: + Definition: base address of the coincell charger registers + +- qcom,rset-ohms: + Usage: required + Value type: + Definition: resistance (in ohms) for current-limiting resistor + must be one of: 800, 1200, 1700, 2100 + +- qcom,vset-millivolts: + Usage: required + Value type: + Definition: voltage (in millivolts) to apply for charging + must be one of: 2500, 3000, 3100, 3200 + +- qcom,charger-disable: + Usage: optional + Value type: + Definition: definining this property disables charging + +This charger is a sub-node of one of the 8941 PMIC blocks, and is specified +as a child node in DTS of that node. See ../mfd/qcom,spmi-pmic.txt and +../mfd/qcom-pm8xxx.txt + +Example: + + pm8941@0 { + coincell@2800 { + compatible = "qcom,pm8941-coincell"; + reg = <0x2800>; + + qcom,rset-ohms = <2100>; + qcom,vset-millivolts = <3000>; + }; + }; -- cgit v1.2.3-59-g8ed1b From 6f98f545b0b4effdf67e83e214a4eb13cd41fba2 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 28 Jul 2015 11:10:22 +0300 Subject: usb: phy: msm: Add D+/D- lines route control apq8016-sbc board is using Dual SPDT USB Switch (TC7USB40MU), witch is controlled by GPIO to de/multiplex D+/D- USB lines to USB2513B Hub and uB connector. Add support for this. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/msm-hsusb.txt | 4 ++ drivers/usb/phy/phy-msm-usb.c | 47 ++++++++++++++++++++++ include/linux/usb/msm_hsusb.h | 7 ++++ 3 files changed, 58 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index bd8d9e753029..8654a3ec23e4 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -52,6 +52,10 @@ Required properties: Optional properties: - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" +- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual + SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex + D+/D- USB lines between connectors. + - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device Mode Eye Diagram test. Start address at which these values will be written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 61d86d8bf5b7..c58c3c0dbe35 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include @@ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event, else clear_bit(B_SESS_VLD, &motg->inputs); + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + schedule_work(&motg->sm_work); return NOTIFY_DONE; @@ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); + motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(motg->switch_gpio)) + return PTR_ERR(motg->switch_gpio); + ext_id = ERR_PTR(-ENODEV); ext_vbus = ERR_PTR(-ENODEV); if (of_property_read_bool(node, "extcon")) { @@ -1617,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) return 0; } +static int msm_otg_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct msm_otg *motg = container_of(this, struct msm_otg, reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + return NOTIFY_DONE; +} + static int msm_otg_probe(struct platform_device *pdev) { struct regulator_bulk_data regs[3]; @@ -1781,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Can not create mode change file\n"); } + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + + motg->reboot.notifier_call = msm_otg_reboot_notify; + register_reboot_notifier(&motg->reboot); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1807,6 +1846,14 @@ static int msm_otg_remove(struct platform_device *pdev) if (phy->otg->host || phy->otg->gadget) return -EBUSY; + unregister_reboot_notifier(&motg->reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 5df2c8f59aa0..8c8f6854c993 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -155,6 +155,10 @@ struct msm_usb_cable { * starting controller using usbcmd run/stop bit. * @vbus: VBUS signal state trakining, using extcon framework * @id: ID signal state trakining, using extcon framework + * @switch_gpio: Descriptor for GPIO used to control external Dual + * SPDT USB Switch. + * @reboot: Used to inform the driver to route USB D+/D- line to Device + * connector */ struct msm_otg { struct usb_phy phy; @@ -188,6 +192,9 @@ struct msm_otg { struct msm_usb_cable vbus; struct msm_usb_cable id; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot; }; #endif -- cgit v1.2.3-59-g8ed1b From 1837649fd350bf25e20d05dbdd4449160ad0219b Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Thu, 27 Nov 2014 20:47:33 +0530 Subject: Documentation: devicetree: Add ECC information to synopsys ddr controller Add ECC information to synopsys ddr memory controller. Signed-off-by: Punnaiah Choudary Kalluri Signed-off-by: Michal Simek --- Documentation/devicetree/bindings/memory-controllers/synopsys.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index f9c6454146b6..a43d26d41e04 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,5 +1,9 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller +This controller has an optional ECC support in half-bus width (16-bit) +configuration. The ECC controller corrects one bit error and detects +two bit errors. + Required properties: - compatible: Should be 'xlnx,zynq-ddrc-a05' - reg: Base address and size of the controllers memory area -- cgit v1.2.3-59-g8ed1b From 8cd50626823c00ca7472b2f61cb8c0eb9798ddc0 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:28 +0800 Subject: Doc: ABI: testing: configfs-usb-gadget-loopback Fix the name of attribute Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-loopback | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-loopback b/Documentation/ABI/testing/configfs-usb-gadget-loopback index 9aae5bfb9908..06beefbcf061 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-loopback +++ b/Documentation/ABI/testing/configfs-usb-gadget-loopback @@ -5,4 +5,4 @@ Description: The attributes: qlen - depth of loopback queue - bulk_buflen - buffer length + buflen - buffer length -- cgit v1.2.3-59-g8ed1b From 4bc58eb16bb2352854b9c664cc36c1c68d2bfbb7 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:29 +0800 Subject: Doc: ABI: testing: configfs-usb-gadget-sourcesink Fix the name of attribute Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-sourcesink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink index 29477c319f61..bc7ff731aa0c 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink +++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink @@ -9,4 +9,4 @@ Description: isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss) isoc_mult - 0..2 (hs/ss only) isoc_maxburst - 0..15 (ss only) - qlen - buffer length + buflen - buffer length -- cgit v1.2.3-59-g8ed1b From f811a38300be3cdb603171aea5ad3fb42b71ca53 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:30 +0800 Subject: doc: usb: gadget-testing: using the updated testusb.c testusb.c at http://www.linux-usb.org/usbtest/ is out of date, using the one at the kernel source folder. Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- Documentation/usb/gadget-testing.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 592678009c15..b24d3ef89166 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -237,9 +237,7 @@ Testing the LOOPBACK function ----------------------------- device: run the gadget -host: test-usb - -http://www.linux-usb.org/usbtest/testusb.c +host: test-usb (tools/usb/testusb.c) 8. MASS STORAGE function ======================== @@ -586,9 +584,8 @@ Testing the SOURCESINK function ------------------------------- device: run the gadget -host: test-usb +host: test-usb (tools/usb/testusb.c) -http://www.linux-usb.org/usbtest/testusb.c 16. UAC1 function ================= -- cgit v1.2.3-59-g8ed1b From 885fb909dc17f9240ab3e3420f7f135ae82be01f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 16 Mar 2015 15:47:12 +0100 Subject: PM / Domains: Correct unit address in power-controller example In example 2 of the generic PM domains DT bindings, the unit address of the device node representing the child power controller doesn't match its "reg" property. Correct it. Signed-off-by: Geert Uytterhoeven Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- Documentation/devicetree/bindings/power/power_domain.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 0f8ed3710c66..025b5e7df61c 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -48,7 +48,7 @@ Example 2: #power-domain-cells = <1>; }; - child: power-controller@12340000 { + child: power-controller@12341000 { compatible = "foo,power-controller"; reg = <0x12341000 0x1000>; power-domains = <&parent 0>; -- cgit v1.2.3-59-g8ed1b From c934b3612747bde6c81cf10c2bbde956c6690aec Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Jul 2015 16:47:22 +0300 Subject: phy: ti-pipe3: i783 workaround for SATA lockup after dpll unlock/relock SATA_PLL_SOFT_RESET bit of CTRL_CORE_SMA_SW_0 must be toggled between a SATA DPLL unlock and re-lock to prevent SATA lockup. Introduce a new DT parameter 'syscon-pllreset' to provide the syscon regmap access to this register which sits in the control module. If the register is not provided we fallback to the old behaviour i.e. SATA DPLL refclk will not be disabled and we prevent SoC low power states. Signed-off-by: Roger Quadros Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/ti-phy.txt | 16 +++++++ drivers/phy/phy-ti-pipe3.c | 61 +++++++++++++++++++++--- 2 files changed, 71 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 305e3df3d9b1..9cf9446eaf2e 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -82,6 +82,9 @@ Optional properties: - id: If there are multiple instance of the same type, in order to differentiate between each instance "id" can be used (e.g., multi-lane PCIe PHY). If "id" is not provided, it is set to default value of '1'. + - syscon-pllreset: Handle to system control region that contains the + CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0 + register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy. This is usually a subnode of ocp2scp to which it is connected. @@ -100,3 +103,16 @@ usb3phy@4a084400 { "sysclk", "refclk"; }; + +sata_phy: phy@4A096000 { + compatible = "ti,phy-pipe3-sata"; + reg = <0x4A096000 0x80>, /* phy_rx */ + <0x4A096400 0x64>, /* phy_tx */ + <0x4A096800 0x40>; /* pll_ctrl */ + reg-names = "phy_rx", "phy_tx", "pll_ctrl"; + ctrl-module = <&omap_control_sata>; + clocks = <&sys_clkin1>, <&sata_ref_clk>; + clock-names = "sysclk", "refclk"; + syscon-pllreset = <&scm_conf 0x3fc>; + #phy-cells = <0>; +}; diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 3510b81db3fa..08020dc2c7c8 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #define PLL_STATUS 0x00000004 #define PLL_GO 0x00000008 @@ -52,6 +54,8 @@ #define PLL_LOCK 0x2 #define PLL_IDLE 0x1 +#define SATA_PLL_SOFT_RESET BIT(18) + /* * This is an Empirical value that works, need to confirm the actual * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status @@ -82,6 +86,9 @@ struct ti_pipe3 { struct clk *refclk; struct clk *div_clk; struct pipe3_dpll_map *dpll_map; + struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */ + unsigned int dpll_reset_reg; /* reg. index within syscon */ + bool sata_refclk_enabled; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x) u32 val; unsigned long timeout; - /* SATA DPLL can't be powered down due to Errata i783 */ - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) + /* If dpll_reset_syscon is not present we wont power down SATA DPLL + * due to Errata i783 + */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") && + !phy->dpll_reset_syscon) return 0; /* PCIe doesn't have internal DPLL */ @@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x) } } + /* i783: SATA needs control bit toggle after PLL unlock */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) { + regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, + SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); + regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, + SATA_PLL_SOFT_RESET, 0); + } + ti_pipe3_disable_clocks(phy); return 0; @@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev) } } else { phy->wkupclk = ERR_PTR(-ENODEV); + phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, + "syscon-pllreset"); + if (IS_ERR(phy->dpll_reset_syscon)) { + dev_info(&pdev->dev, + "can't get syscon-pllreset, sata dpll won't idle\n"); + phy->dpll_reset_syscon = NULL; + } else { + if (of_property_read_u32_index(node, + "syscon-pllreset", 1, + &phy->dpll_reset_reg)) { + dev_err(&pdev->dev, + "couldn't get pllreset reg. offset\n"); + return -EINVAL; + } + } } if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { @@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); pm_runtime_enable(phy->dev); - /* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */ - if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) - if (!IS_ERR(phy->refclk)) + + /* + * Prevent auto-disable of refclk for SATA PHY due to Errata i783 + */ + if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) { + if (!IS_ERR(phy->refclk)) { clk_prepare_enable(phy->refclk); + phy->sata_refclk_enabled = true; + } + } generic_phy = devm_phy_create(phy->dev, NULL, &ops); if (IS_ERR(generic_phy)) @@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) { if (!IS_ERR(phy->wkupclk)) clk_disable_unprepare(phy->wkupclk); - if (!IS_ERR(phy->refclk)) + if (!IS_ERR(phy->refclk)) { clk_disable_unprepare(phy->refclk); + /* + * SATA refclk needs an additional disable as we left it + * on in probe to avoid Errata i783 + */ + if (phy->sata_refclk_enabled) { + clk_disable_unprepare(phy->refclk); + phy->sata_refclk_enabled = false; + } + } + if (!IS_ERR(phy->div_clk)) clk_disable_unprepare(phy->div_clk); } -- cgit v1.2.3-59-g8ed1b From 9b0a18626288ecd62ad09a9c36a5ba318ea30087 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 13 Jul 2015 08:58:51 +0200 Subject: PM / devfreq: event: Remove incorrect property in exynos-ppmu DT binding The exynos-ppmu driver is only a clock consumer and not a clock provider but its Device Tree binding listed #clock-cells as an optional property. Signed-off-by: Javier Martinez Canillas Reviewed-by: Chanwoo Choi Signed-off-by: MyungJoo Ham --- Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt index b54bf3a2ff57..aed486692880 100644 --- a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt +++ b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt @@ -17,7 +17,6 @@ Required properties: Optional properties: - clock-names : the name of clock used by the PPMU, "ppmu" - clocks : phandles for clock specified in "clock-names" property -- #clock-cells: should be 1. Example1 : PPMU nodes in exynos3250.dtsi are listed below. -- cgit v1.2.3-59-g8ed1b From a622789aeebdeaa52d68bbc3930edbc3e820b54a Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 24 Jul 2015 13:17:25 +0900 Subject: PM / devfreq: exynos-ppmu: Update documentation to support PPMUv2 This patch updates the documentation to include the information of PPMUv2. The PPMUv2 is used for Exynos5433 and Exynos7420 to monitor the performance of each IP in Exynos SoC. Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Chanwoo Choi --- .../bindings/devfreq/event/exynos-ppmu.txt | 42 ++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt index aed486692880..3e36c1d11386 100644 --- a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt +++ b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt @@ -11,14 +11,14 @@ to various devfreq devices. The devfreq devices would use the event data when derterming the current state of each IP. Required properties: -- compatible: Should be "samsung,exynos-ppmu". +- compatible: Should be "samsung,exynos-ppmu" or "samsung,exynos-ppmu-v2. - reg: physical base address of each PPMU and length of memory mapped region. Optional properties: - clock-names : the name of clock used by the PPMU, "ppmu" - clocks : phandles for clock specified in "clock-names" property -Example1 : PPMU nodes in exynos3250.dtsi are listed below. +Example1 : PPMUv1 nodes in exynos3250.dtsi are listed below. ppmu_dmc0: ppmu_dmc0@106a0000 { compatible = "samsung,exynos-ppmu"; @@ -107,3 +107,41 @@ Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below. }; }; }; + +Example3 : PPMUv2 nodes in exynos5433.dtsi are listed below. + + ppmu_d0_cpu: ppmu_d0_cpu@10480000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x10480000 0x2000>; + status = "disabled"; + }; + + ppmu_d0_general: ppmu_d0_general@10490000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x10490000 0x2000>; + status = "disabled"; + }; + + ppmu_d0_rt: ppmu_d0_rt@104a0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104a0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_cpu: ppmu_d1_cpu@104b0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104b0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_general: ppmu_d1_general@104c0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104c0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_rt: ppmu_d1_rt@104d0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104d0000 0x2000>; + status = "disabled"; + }; -- cgit v1.2.3-59-g8ed1b From efdf5aa8f175c18def6407bb2b51643e4da88259 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 13 Feb 2015 12:20:49 +0100 Subject: ARM: STi: DT: Move reset controller constants into common location By popular vote, the DT binding includes for reset controllers are located in include/dt-bindings/reset/. Move the STi reset constants in there, too, to avoid confusion. Signed-off-by: Philipp Zabel Acked-by: Patrice Chotard --- .../bindings/reset/st,sti-picophyreset.txt | 2 +- .../devicetree/bindings/reset/st,sti-powerdown.txt | 4 +- .../devicetree/bindings/reset/st,sti-softreset.txt | 4 +- arch/arm/boot/dts/stih407-family.dtsi | 2 +- arch/arm/boot/dts/stih415.dtsi | 2 +- arch/arm/boot/dts/stih416.dtsi | 2 +- drivers/reset/sti/reset-stih407.c | 2 +- drivers/reset/sti/reset-stih415.c | 2 +- drivers/reset/sti/reset-stih416.c | 2 +- .../dt-bindings/reset-controller/stih407-resets.h | 61 ---------------------- .../dt-bindings/reset-controller/stih415-resets.h | 27 ---------- .../dt-bindings/reset-controller/stih416-resets.h | 51 ------------------ include/dt-bindings/reset/stih407-resets.h | 61 ++++++++++++++++++++++ include/dt-bindings/reset/stih415-resets.h | 27 ++++++++++ include/dt-bindings/reset/stih416-resets.h | 51 ++++++++++++++++++ 15 files changed, 150 insertions(+), 150 deletions(-) delete mode 100644 include/dt-bindings/reset-controller/stih407-resets.h delete mode 100644 include/dt-bindings/reset-controller/stih415-resets.h delete mode 100644 include/dt-bindings/reset-controller/stih416-resets.h create mode 100644 include/dt-bindings/reset/stih407-resets.h create mode 100644 include/dt-bindings/reset/stih415-resets.h create mode 100644 include/dt-bindings/reset/stih416-resets.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt index 54ae9f747e45..9ca27761f811 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt @@ -39,4 +39,4 @@ Example: }; Macro definitions for the supported reset channels can be found in: -include/dt-bindings/reset-controller/stih407-resets.h +include/dt-bindings/reset/stih407-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt index 5ab26b7e9d35..1cfd21d1dfa1 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt @@ -43,5 +43,5 @@ example: Macro definitions for the supported reset channels can be found in: -include/dt-bindings/reset-controller/stih415-resets.h -include/dt-bindings/reset-controller/stih416-resets.h +include/dt-bindings/reset/stih415-resets.h +include/dt-bindings/reset/stih416-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt index a8d3d3c25ca2..891a2fd85ed6 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt @@ -42,5 +42,5 @@ example: Macro definitions for the supported reset channels can be found in: -include/dt-bindings/reset-controller/stih415-resets.h -include/dt-bindings/reset-controller/stih416-resets.h +include/dt-bindings/reset/stih415-resets.h +include/dt-bindings/reset/stih416-resets.h diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi index 838b812cbda1..eab3477e0a0e 100644 --- a/arch/arm/boot/dts/stih407-family.dtsi +++ b/arch/arm/boot/dts/stih407-family.dtsi @@ -9,7 +9,7 @@ #include "stih407-pinctrl.dtsi" #include #include -#include +#include #include / { #address-cells = <1>; diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index 19b019b5f30e..12427e651e5e 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -10,7 +10,7 @@ #include "stih415-clock.dtsi" #include "stih415-pinctrl.dtsi" #include -#include +#include / { L2: cache-controller { diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index 9dca173e694a..9e3170ccd18c 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -12,7 +12,7 @@ #include #include -#include +#include #include / { L2: cache-controller { diff --git a/drivers/reset/sti/reset-stih407.c b/drivers/reset/sti/reset-stih407.c index d83db5d72d08..f7a6cb093983 100644 --- a/drivers/reset/sti/reset-stih407.c +++ b/drivers/reset/sti/reset-stih407.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "reset-syscfg.h" /* STiH407 Peripheral powerdown definitions. */ diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c index 8dad603d863c..f7b49d5a62dc 100644 --- a/drivers/reset/sti/reset-stih415.c +++ b/drivers/reset/sti/reset-stih415.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "reset-syscfg.h" diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c index 79aed70a26c0..d65a82e74004 100644 --- a/drivers/reset/sti/reset-stih416.c +++ b/drivers/reset/sti/reset-stih416.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "reset-syscfg.h" diff --git a/include/dt-bindings/reset-controller/stih407-resets.h b/include/dt-bindings/reset-controller/stih407-resets.h deleted file mode 100644 index 02d4328fe479..000000000000 --- a/include/dt-bindings/reset-controller/stih407-resets.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This header provides constants for the reset controller - * based peripheral powerdown requests on the STMicroelectronics - * STiH407 SoC. - */ -#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH407 -#define _DT_BINDINGS_RESET_CONTROLLER_STIH407 - -/* Powerdown requests control 0 */ -#define STIH407_EMISS_POWERDOWN 0 -#define STIH407_NAND_POWERDOWN 1 - -/* Synp GMAC PowerDown */ -#define STIH407_ETH1_POWERDOWN 2 - -/* Powerdown requests control 1 */ -#define STIH407_USB3_POWERDOWN 3 -#define STIH407_USB2_PORT1_POWERDOWN 4 -#define STIH407_USB2_PORT0_POWERDOWN 5 -#define STIH407_PCIE1_POWERDOWN 6 -#define STIH407_PCIE0_POWERDOWN 7 -#define STIH407_SATA1_POWERDOWN 8 -#define STIH407_SATA0_POWERDOWN 9 - -/* Reset defines */ -#define STIH407_ETH1_SOFTRESET 0 -#define STIH407_MMC1_SOFTRESET 1 -#define STIH407_PICOPHY_SOFTRESET 2 -#define STIH407_IRB_SOFTRESET 3 -#define STIH407_PCIE0_SOFTRESET 4 -#define STIH407_PCIE1_SOFTRESET 5 -#define STIH407_SATA0_SOFTRESET 6 -#define STIH407_SATA1_SOFTRESET 7 -#define STIH407_MIPHY0_SOFTRESET 8 -#define STIH407_MIPHY1_SOFTRESET 9 -#define STIH407_MIPHY2_SOFTRESET 10 -#define STIH407_SATA0_PWR_SOFTRESET 11 -#define STIH407_SATA1_PWR_SOFTRESET 12 -#define STIH407_DELTA_SOFTRESET 13 -#define STIH407_BLITTER_SOFTRESET 14 -#define STIH407_HDTVOUT_SOFTRESET 15 -#define STIH407_HDQVDP_SOFTRESET 16 -#define STIH407_VDP_AUX_SOFTRESET 17 -#define STIH407_COMPO_SOFTRESET 18 -#define STIH407_HDMI_TX_PHY_SOFTRESET 19 -#define STIH407_JPEG_DEC_SOFTRESET 20 -#define STIH407_VP8_DEC_SOFTRESET 21 -#define STIH407_GPU_SOFTRESET 22 -#define STIH407_HVA_SOFTRESET 23 -#define STIH407_ERAM_HVA_SOFTRESET 24 -#define STIH407_LPM_SOFTRESET 25 -#define STIH407_KEYSCAN_SOFTRESET 26 -#define STIH407_USB2_PORT0_SOFTRESET 27 -#define STIH407_USB2_PORT1_SOFTRESET 28 - -/* Picophy reset defines */ -#define STIH407_PICOPHY0_RESET 0 -#define STIH407_PICOPHY1_RESET 1 -#define STIH407_PICOPHY2_RESET 2 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH407 */ diff --git a/include/dt-bindings/reset-controller/stih415-resets.h b/include/dt-bindings/reset-controller/stih415-resets.h deleted file mode 100644 index c2329fe29cf6..000000000000 --- a/include/dt-bindings/reset-controller/stih415-resets.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This header provides constants for the reset controller - * based peripheral powerdown requests on the STMicroelectronics - * STiH415 SoC. - */ -#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH415 -#define _DT_BINDINGS_RESET_CONTROLLER_STIH415 - -#define STIH415_EMISS_POWERDOWN 0 -#define STIH415_NAND_POWERDOWN 1 -#define STIH415_KEYSCAN_POWERDOWN 2 -#define STIH415_USB0_POWERDOWN 3 -#define STIH415_USB1_POWERDOWN 4 -#define STIH415_USB2_POWERDOWN 5 -#define STIH415_SATA0_POWERDOWN 6 -#define STIH415_SATA1_POWERDOWN 7 -#define STIH415_PCIE_POWERDOWN 8 - -#define STIH415_ETH0_SOFTRESET 0 -#define STIH415_ETH1_SOFTRESET 1 -#define STIH415_IRB_SOFTRESET 2 -#define STIH415_USB0_SOFTRESET 3 -#define STIH415_USB1_SOFTRESET 4 -#define STIH415_USB2_SOFTRESET 5 -#define STIH415_KEYSCAN_SOFTRESET 6 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ diff --git a/include/dt-bindings/reset-controller/stih416-resets.h b/include/dt-bindings/reset-controller/stih416-resets.h deleted file mode 100644 index fcf9af1ac0b2..000000000000 --- a/include/dt-bindings/reset-controller/stih416-resets.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This header provides constants for the reset controller - * based peripheral powerdown requests on the STMicroelectronics - * STiH416 SoC. - */ -#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH416 -#define _DT_BINDINGS_RESET_CONTROLLER_STIH416 - -#define STIH416_EMISS_POWERDOWN 0 -#define STIH416_NAND_POWERDOWN 1 -#define STIH416_KEYSCAN_POWERDOWN 2 -#define STIH416_USB0_POWERDOWN 3 -#define STIH416_USB1_POWERDOWN 4 -#define STIH416_USB2_POWERDOWN 5 -#define STIH416_USB3_POWERDOWN 6 -#define STIH416_SATA0_POWERDOWN 7 -#define STIH416_SATA1_POWERDOWN 8 -#define STIH416_PCIE0_POWERDOWN 9 -#define STIH416_PCIE1_POWERDOWN 10 - -#define STIH416_ETH0_SOFTRESET 0 -#define STIH416_ETH1_SOFTRESET 1 -#define STIH416_IRB_SOFTRESET 2 -#define STIH416_USB0_SOFTRESET 3 -#define STIH416_USB1_SOFTRESET 4 -#define STIH416_USB2_SOFTRESET 5 -#define STIH416_USB3_SOFTRESET 6 -#define STIH416_SATA0_SOFTRESET 7 -#define STIH416_SATA1_SOFTRESET 8 -#define STIH416_PCIE0_SOFTRESET 9 -#define STIH416_PCIE1_SOFTRESET 10 -#define STIH416_AUD_DAC_SOFTRESET 11 -#define STIH416_HDTVOUT_SOFTRESET 12 -#define STIH416_VTAC_M_RX_SOFTRESET 13 -#define STIH416_VTAC_A_RX_SOFTRESET 14 -#define STIH416_SYNC_HD_SOFTRESET 15 -#define STIH416_SYNC_SD_SOFTRESET 16 -#define STIH416_BLITTER_SOFTRESET 17 -#define STIH416_GPU_SOFTRESET 18 -#define STIH416_VTAC_M_TX_SOFTRESET 19 -#define STIH416_VTAC_A_TX_SOFTRESET 20 -#define STIH416_VTG_AUX_SOFTRESET 21 -#define STIH416_JPEG_DEC_SOFTRESET 22 -#define STIH416_HVA_SOFTRESET 23 -#define STIH416_COMPO_M_SOFTRESET 24 -#define STIH416_COMPO_A_SOFTRESET 25 -#define STIH416_VP8_DEC_SOFTRESET 26 -#define STIH416_VTG_MAIN_SOFTRESET 27 -#define STIH416_KEYSCAN_SOFTRESET 28 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ diff --git a/include/dt-bindings/reset/stih407-resets.h b/include/dt-bindings/reset/stih407-resets.h new file mode 100644 index 000000000000..02d4328fe479 --- /dev/null +++ b/include/dt-bindings/reset/stih407-resets.h @@ -0,0 +1,61 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH407 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH407 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH407 + +/* Powerdown requests control 0 */ +#define STIH407_EMISS_POWERDOWN 0 +#define STIH407_NAND_POWERDOWN 1 + +/* Synp GMAC PowerDown */ +#define STIH407_ETH1_POWERDOWN 2 + +/* Powerdown requests control 1 */ +#define STIH407_USB3_POWERDOWN 3 +#define STIH407_USB2_PORT1_POWERDOWN 4 +#define STIH407_USB2_PORT0_POWERDOWN 5 +#define STIH407_PCIE1_POWERDOWN 6 +#define STIH407_PCIE0_POWERDOWN 7 +#define STIH407_SATA1_POWERDOWN 8 +#define STIH407_SATA0_POWERDOWN 9 + +/* Reset defines */ +#define STIH407_ETH1_SOFTRESET 0 +#define STIH407_MMC1_SOFTRESET 1 +#define STIH407_PICOPHY_SOFTRESET 2 +#define STIH407_IRB_SOFTRESET 3 +#define STIH407_PCIE0_SOFTRESET 4 +#define STIH407_PCIE1_SOFTRESET 5 +#define STIH407_SATA0_SOFTRESET 6 +#define STIH407_SATA1_SOFTRESET 7 +#define STIH407_MIPHY0_SOFTRESET 8 +#define STIH407_MIPHY1_SOFTRESET 9 +#define STIH407_MIPHY2_SOFTRESET 10 +#define STIH407_SATA0_PWR_SOFTRESET 11 +#define STIH407_SATA1_PWR_SOFTRESET 12 +#define STIH407_DELTA_SOFTRESET 13 +#define STIH407_BLITTER_SOFTRESET 14 +#define STIH407_HDTVOUT_SOFTRESET 15 +#define STIH407_HDQVDP_SOFTRESET 16 +#define STIH407_VDP_AUX_SOFTRESET 17 +#define STIH407_COMPO_SOFTRESET 18 +#define STIH407_HDMI_TX_PHY_SOFTRESET 19 +#define STIH407_JPEG_DEC_SOFTRESET 20 +#define STIH407_VP8_DEC_SOFTRESET 21 +#define STIH407_GPU_SOFTRESET 22 +#define STIH407_HVA_SOFTRESET 23 +#define STIH407_ERAM_HVA_SOFTRESET 24 +#define STIH407_LPM_SOFTRESET 25 +#define STIH407_KEYSCAN_SOFTRESET 26 +#define STIH407_USB2_PORT0_SOFTRESET 27 +#define STIH407_USB2_PORT1_SOFTRESET 28 + +/* Picophy reset defines */ +#define STIH407_PICOPHY0_RESET 0 +#define STIH407_PICOPHY1_RESET 1 +#define STIH407_PICOPHY2_RESET 2 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH407 */ diff --git a/include/dt-bindings/reset/stih415-resets.h b/include/dt-bindings/reset/stih415-resets.h new file mode 100644 index 000000000000..c2329fe29cf6 --- /dev/null +++ b/include/dt-bindings/reset/stih415-resets.h @@ -0,0 +1,27 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH415 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH415 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH415 + +#define STIH415_EMISS_POWERDOWN 0 +#define STIH415_NAND_POWERDOWN 1 +#define STIH415_KEYSCAN_POWERDOWN 2 +#define STIH415_USB0_POWERDOWN 3 +#define STIH415_USB1_POWERDOWN 4 +#define STIH415_USB2_POWERDOWN 5 +#define STIH415_SATA0_POWERDOWN 6 +#define STIH415_SATA1_POWERDOWN 7 +#define STIH415_PCIE_POWERDOWN 8 + +#define STIH415_ETH0_SOFTRESET 0 +#define STIH415_ETH1_SOFTRESET 1 +#define STIH415_IRB_SOFTRESET 2 +#define STIH415_USB0_SOFTRESET 3 +#define STIH415_USB1_SOFTRESET 4 +#define STIH415_USB2_SOFTRESET 5 +#define STIH415_KEYSCAN_SOFTRESET 6 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ diff --git a/include/dt-bindings/reset/stih416-resets.h b/include/dt-bindings/reset/stih416-resets.h new file mode 100644 index 000000000000..fcf9af1ac0b2 --- /dev/null +++ b/include/dt-bindings/reset/stih416-resets.h @@ -0,0 +1,51 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH416 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH416 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH416 + +#define STIH416_EMISS_POWERDOWN 0 +#define STIH416_NAND_POWERDOWN 1 +#define STIH416_KEYSCAN_POWERDOWN 2 +#define STIH416_USB0_POWERDOWN 3 +#define STIH416_USB1_POWERDOWN 4 +#define STIH416_USB2_POWERDOWN 5 +#define STIH416_USB3_POWERDOWN 6 +#define STIH416_SATA0_POWERDOWN 7 +#define STIH416_SATA1_POWERDOWN 8 +#define STIH416_PCIE0_POWERDOWN 9 +#define STIH416_PCIE1_POWERDOWN 10 + +#define STIH416_ETH0_SOFTRESET 0 +#define STIH416_ETH1_SOFTRESET 1 +#define STIH416_IRB_SOFTRESET 2 +#define STIH416_USB0_SOFTRESET 3 +#define STIH416_USB1_SOFTRESET 4 +#define STIH416_USB2_SOFTRESET 5 +#define STIH416_USB3_SOFTRESET 6 +#define STIH416_SATA0_SOFTRESET 7 +#define STIH416_SATA1_SOFTRESET 8 +#define STIH416_PCIE0_SOFTRESET 9 +#define STIH416_PCIE1_SOFTRESET 10 +#define STIH416_AUD_DAC_SOFTRESET 11 +#define STIH416_HDTVOUT_SOFTRESET 12 +#define STIH416_VTAC_M_RX_SOFTRESET 13 +#define STIH416_VTAC_A_RX_SOFTRESET 14 +#define STIH416_SYNC_HD_SOFTRESET 15 +#define STIH416_SYNC_SD_SOFTRESET 16 +#define STIH416_BLITTER_SOFTRESET 17 +#define STIH416_GPU_SOFTRESET 18 +#define STIH416_VTAC_M_TX_SOFTRESET 19 +#define STIH416_VTAC_A_TX_SOFTRESET 20 +#define STIH416_VTG_AUX_SOFTRESET 21 +#define STIH416_JPEG_DEC_SOFTRESET 22 +#define STIH416_HVA_SOFTRESET 23 +#define STIH416_COMPO_M_SOFTRESET 24 +#define STIH416_COMPO_A_SOFTRESET 25 +#define STIH416_VP8_DEC_SOFTRESET 26 +#define STIH416_VTG_MAIN_SOFTRESET 27 +#define STIH416_KEYSCAN_SOFTRESET 28 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ -- cgit v1.2.3-59-g8ed1b From 27dc2fb18fe814fab0a5035859c77b279cdaec80 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 6 May 2015 00:10:27 +0200 Subject: doc: dt: add documentation for lpc1850-rgu reset driver Add device tree binding documentation for the Reset Generation Unit (RGU) found on NXP LPC18xx and LPC43xx devies. This documentation also includes a table which shows the RGU reset number and the connected peripheral. Signed-off-by: Joachim Eastwood Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/nxp,lpc1850-rgu.txt | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/nxp,lpc1850-rgu.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/nxp,lpc1850-rgu.txt b/Documentation/devicetree/bindings/reset/nxp,lpc1850-rgu.txt new file mode 100644 index 000000000000..b4e96a278445 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/nxp,lpc1850-rgu.txt @@ -0,0 +1,84 @@ +NXP LPC1850 Reset Generation Unit (RGU) +======================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "nxp,lpc1850-rgu" +- reg: register base and length +- clocks: phandle and clock specifier to RGU clocks +- clock-names: should contain "delay" and "reg" +- #reset-cells: should be 1 + +See table below for valid peripheral reset numbers. Numbers not +in the table below are either reserved or not applicable for +normal operation. + +Reset Peripheral + 9 System control unit (SCU) + 12 ARM Cortex-M0 subsystem core (LPC43xx only) + 13 CPU core + 16 LCD controller + 17 USB0 + 18 USB1 + 19 DMA + 20 SDIO + 21 External memory controller (EMC) + 22 Ethernet + 25 Flash bank A + 27 EEPROM + 28 GPIO + 29 Flash bank B + 32 Timer0 + 33 Timer1 + 34 Timer2 + 35 Timer3 + 36 Repetitive Interrupt timer (RIT) + 37 State Configurable Timer (SCT) + 38 Motor control PWM (MCPWM) + 39 QEI + 40 ADC0 + 41 ADC1 + 42 DAC + 44 USART0 + 45 UART1 + 46 USART2 + 47 USART3 + 48 I2C0 + 49 I2C1 + 50 SSP0 + 51 SSP1 + 52 I2S0 and I2S1 + 53 Serial Flash Interface (SPIFI) + 54 C_CAN1 + 55 C_CAN0 + 56 ARM Cortex-M0 application core (LPC4370 only) + 57 SGPIO (LPC43xx only) + 58 SPI (LPC43xx only) + 60 ADCHS (12-bit ADC) (LPC4370 only) + +Refer to NXP LPC18xx or LPC43xx user manual for more details about +the reset signals and the connected block/peripheral. + +Reset provider example: +rgu: reset-controller@40053000 { + compatible = "nxp,lpc1850-rgu"; + reg = <0x40053000 0x1000>; + clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_BUS>; + clock-names = "delay", "reg"; + #reset-cells = <1>; +}; + +Reset consumer example: +mac: ethernet@40010000 { + compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac"; + reg = <0x40010000 0x2000>; + interrupts = <5>; + interrupt-names = "macirq"; + clocks = <&ccu1 CLK_CPU_ETHERNET>; + clock-names = "stmmaceth"; + resets = <&rgu 22>; + reset-names = "stmmaceth"; + status = "disabled"; +}; -- cgit v1.2.3-59-g8ed1b From 073e570d7c2caae9910a993d56f340be4548a4a8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Aug 2015 14:06:24 -0700 Subject: Input: alps - only Dell laptops have separate button bits for v2 dualpoint sticks It turns out that only Dell laptops have the separate button bits for v2 dualpoint sticks and that commit 92bac83dd79e ("Input: alps - non interleaved V2 dualpoint has separate stick button bits") causes regressions on Toshiba laptops. This commit adds a check for Dell laptops to the code for handling these extra button bits, fixing this regression. This patch has been tested on a Dell Latitude D620 to make sure that it does not reintroduce the original problem. Reported-and-tested-by: Douglas Christman Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- Documentation/input/alps.txt | 6 ++++-- drivers/input/mouse/alps.c | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index e301887d8523..765d99cdadbb 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2 byte 5: 0 z6 z5 z4 z3 z2 z1 z0 Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for -the DualPoint Stick. For non interleaved dualpoint devices the pointingstick -buttons get reported separately in the PSM, PSR and PSL bits. +the DualPoint Stick. The M, R and L bits signal the combined status of both +the pointingstick and touchpad buttons, except for Dell dualpoint devices +where the pointingstick buttons get reported separately in the PSM, PSR +and PSL bits. Dualpoint device -- interleaved packet format --------------------------------------------- diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 113d6f1516a5..4d246861d692 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "psmouse.h" #include "alps.h" @@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 6-byte ALPS packet */ +#define ALPS_DELL 0x100 /* device is a Dell laptop */ #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ static const struct alps_model_info alps_model_data[] = { @@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) return; } - /* Non interleaved V2 dualpoint has separate stick button bits */ + /* Dell non interleaved V2 dualpoint has separate stick button bits */ if (priv->proto_version == ALPS_PROTO_V2 && - priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) { + priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) { left |= packet[0] & 1; right |= packet[0] & 2; middle |= packet[0] & 4; @@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->byte0 = protocol->byte0; priv->mask0 = protocol->mask0; priv->flags = protocol->flags; + if (dmi_name_in_vendors("Dell")) + priv->flags |= ALPS_DELL; priv->x_max = 2000; priv->y_max = 1400; -- cgit v1.2.3-59-g8ed1b From a2e66ad34c10b27c6e408db50e6472c2aae2b5e8 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 29 Jul 2015 09:08:53 +0200 Subject: Documentation: sysfs-bus-usb: s/CONFIG_PM_RUNTIME/CONFIG_PM/ PM_RUNTIME has been replaced with PM by commit 464ed18ebdb6 ("PM: Eliminate CONFIG_PM_RUNTIME") hence substitute the reference on PM_RUNTIME with PM and re-arrange the text to 80 column break. Signed-off-by: Valentin Rothberg Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index e935625f5995..864637f25bee 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -118,12 +118,12 @@ What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm Date: June 2015 Contact: Kevin Strasser Description: - If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is - plugged in to a xHCI host which supports link PM, it will check - if U1 and U2 exit latencies have been set in the BOS - descriptor; if the check is is passed and the host supports - USB3 hardware LPM, USB3 hardware LPM will be enabled for the - device and the USB device directory will contain a file named + If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged + in to a xHCI host which supports link PM, it will check if U1 + and U2 exit latencies have been set in the BOS descriptor; if + the check is is passed and the host supports USB3 hardware LPM, + USB3 hardware LPM will be enabled for the device and the USB + device directory will contain a file named power/usb3_hardware_lpm. The file holds a string value (enable or disable) indicating whether or not USB3 hardware LPM is enabled for the device. -- cgit v1.2.3-59-g8ed1b From 3c7c8468e5d993dfe377a67e41cbb23cda93af9e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:20 +0300 Subject: mei: add async event notification ioctls Add ioctl IOCTL_MEI_NOTIFY_SET for enabling and disabling async event notification. Add ioctl IOCTL_MEI_NOTIFY_GET for receiving and acking an event notification. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- Documentation/ioctl/ioctl-number.txt | 2 + Documentation/misc-devices/mei/mei.txt | 45 ++++++++++++++++++++++- drivers/misc/mei/main.c | 67 ++++++++++++++++++++++++++++++++++ include/uapi/linux/mei.h | 19 ++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d24..141f847c7648 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -124,6 +124,8 @@ Code Seq#(hex) Include File Comments 'H' 00-7F linux/hiddev.h conflict! 'H' 00-0F linux/hidraw.h conflict! 'H' 01 linux/mei.h conflict! +'H' 02 linux/mei.h conflict! +'H' 03 linux/mei.h conflict! 'H' 00-0F sound/asound.h conflict! 'H' 20-40 sound/asound_fm.h conflict! 'H' 80-8F sound/sfnt_info.h conflict! diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt index 8d47501bba0a..91c1fa34f48b 100644 --- a/Documentation/misc-devices/mei/mei.txt +++ b/Documentation/misc-devices/mei/mei.txt @@ -96,7 +96,7 @@ A code snippet for an application communicating with Intel AMTHI client: IOCTL ===== -The Intel MEI Driver supports the following IOCTL command: +The Intel MEI Driver supports the following IOCTL commands: IOCTL_MEI_CONNECT_CLIENT Connect to firmware Feature (client). usage: @@ -125,6 +125,49 @@ The Intel MEI Driver supports the following IOCTL command: data that can be sent or received. (e.g. if MTU=2K, can send requests up to bytes 2k and received responses up to 2k bytes). + IOCTL_MEI_NOTIFY_SET: enable or disable event notifications + + Usage: + uint32_t enable; + ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable); + + Inputs: + uint32_t enable = 1; + or + uint32_t enable[disable] = 0; + + Error returns: + EINVAL Wrong IOCTL Number + ENODEV Device is not initialized or the client not connected + ENOMEM Unable to allocate memory to client internal data. + EFAULT Fatal Error (e.g. Unable to access user input data) + EOPNOTSUPP if the device doesn't support the feature + + Notes: + The client must be connected in order to enable notification events + + + IOCTL_MEI_NOTIFY_GET : retrieve event + + Usage: + uint32_t event; + ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event); + + Outputs: + 1 - if an event is pending + 0 - if there is no even pending + + Error returns: + EINVAL Wrong IOCTL Number + ENODEV Device is not initialized or the client not connected + ENOMEM Unable to allocate memory to client internal data. + EFAULT Fatal Error (e.g. Unable to access user input data) + EOPNOTSUPP if the device doesn't support the feature + + Notes: + The client must be connected and event notification has to be enabled + in order to receive an event + Intel ME Applications ===================== diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e9513d651cd3..ffa70035af29 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -445,6 +445,45 @@ end: return rets; } +/** + * mei_ioctl_client_notify_request - + * propagate event notification request to client + * + * @file: pointer to file structure + * @request: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_request(struct file *file, u32 request) +{ + struct mei_cl *cl = file->private_data; + + return mei_cl_notify_request(cl, file, request); +} + +/** + * mei_ioctl_client_notify_get - wait for notification request + * + * @file: pointer to file structure + * @notify_get: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get) +{ + struct mei_cl *cl = file->private_data; + bool notify_ev; + bool block = (file->f_flags & O_NONBLOCK) == 0; + int rets; + + rets = mei_cl_notify_get(cl, block, ¬ify_ev); + if (rets) + return rets; + + *notify_get = notify_ev ? 1 : 0; + return 0; +} + /** * mei_ioctl - the IOCTL function * @@ -459,6 +498,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) struct mei_device *dev; struct mei_cl *cl = file->private_data; struct mei_connect_client_data connect_data; + u32 notify_get, notify_req; int rets; @@ -499,6 +539,33 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; + case IOCTL_MEI_NOTIFY_SET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n"); + if (copy_from_user(¬ify_req, + (char __user *)data, sizeof(notify_req))) { + dev_dbg(dev->dev, "failed to copy data from userland\n"); + rets = -EFAULT; + goto out; + } + rets = mei_ioctl_client_notify_request(file, notify_req); + break; + + case IOCTL_MEI_NOTIFY_GET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n"); + rets = mei_ioctl_client_notify_get(file, ¬ify_get); + if (rets) + goto out; + + dev_dbg(dev->dev, "copy connect data to user\n"); + if (copy_to_user((char __user *)data, + ¬ify_get, sizeof(notify_get))) { + dev_dbg(dev->dev, "failed to copy data to userland\n"); + rets = -EFAULT; + goto out; + + } + break; + default: dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h index bc0d8b69c49e..7c3b64f6a215 100644 --- a/include/uapi/linux/mei.h +++ b/include/uapi/linux/mei.h @@ -107,4 +107,23 @@ struct mei_connect_client_data { }; }; +/** + * DOC: set and unset event notification for a connected client + * + * The IOCTL argument is 1 for enabling event notification and 0 for + * disabling the service + * Return: -EOPNOTSUPP if the devices doesn't support the feature + */ +#define IOCTL_MEI_NOTIFY_SET _IOW('H', 0x02, __u32) + +/** + * DOC: retrieve notification + * + * The IOCTL output argument is 1 if an event was is pending and 0 otherwise + * the ioctl has to be called in order to acknowledge pending event + * + * Return: -EOPNOTSUPP if the devices doesn't support the feature + */ +#define IOCTL_MEI_NOTIFY_GET _IOR('H', 0x03, __u32) + #endif /* _LINUX_MEI_H */ -- cgit v1.2.3-59-g8ed1b From f25b5edac7be7d405965fb68c6b6f65d8852d860 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 3 Aug 2015 19:23:51 +0200 Subject: devicetree: Add bindings for the ATH79 reset controller Signed-off-by: Alban Bedel Acked-by: Ralf Baechle Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/ath79-reset.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/ath79-reset.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/ath79-reset.txt b/Documentation/devicetree/bindings/reset/ath79-reset.txt new file mode 100644 index 000000000000..4c56330bf398 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/ath79-reset.txt @@ -0,0 +1,20 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX reset controller + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required Properties: +- compatible: has to be "qca,-reset", "qca,ar7100-reset" + as fallback +- reg: Base address and size of the controllers memory area +- #reset-cells : Specifies the number of cells needed to encode reset + line, should be 1 + +Example: + + reset-controller@1806001c { + compatible = "qca,ar9132-reset", "qca,ar7100-reset"; + reg = <0x1806001c 0x4>; + + #reset-cells = <1>; + }; -- cgit v1.2.3-59-g8ed1b From f6e45c24f401f3d0e648bfba304c83b64d763559 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 3 Aug 2015 09:08:05 +0200 Subject: crypto: doc - AEAD API conversion The AEAD API changes are now reflected in the crypto API doc book. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 4 ++-- include/crypto/aead.h | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 0992531ffefb..8e17a41df4c3 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -585,7 +585,7 @@ kernel crypto API | IPSEC Layer +-----------+ | | | (1) | aead | <----------------------------------- esp_output -| (seqniv) | ---+ +| (seqiv) | ---+ +-----------+ | | (2) +-----------+ | @@ -1687,7 +1687,7 @@ read(opfd, out, outlen); !Pinclude/linux/crypto.h Block Cipher Algorithm Definitions !Finclude/linux/crypto.h crypto_alg !Finclude/linux/crypto.h ablkcipher_alg -!Finclude/linux/crypto.h aead_alg +!Finclude/crypto/aead.h aead_alg !Finclude/linux/crypto.h blkcipher_alg !Finclude/linux/crypto.h cipher_alg !Finclude/crypto/rng.h rng_alg diff --git a/include/crypto/aead.h b/include/crypto/aead.h index 7169ad04acc0..14e35364cdfa 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -45,6 +45,30 @@ * a breach in the integrity of the message. In essence, that -EBADMSG error * code is the key bonus an AEAD cipher has over "standard" block chaining * modes. + * + * Memory Structure: + * + * To support the needs of the most prominent user of AEAD ciphers, namely + * IPSEC, the AEAD ciphers have a special memory layout the caller must adhere + * to. + * + * The scatter list pointing to the input data must contain: + * + * * for RFC4106 ciphers, the concatenation of + * associated authentication data || IV || plaintext or ciphertext. Note, the + * same IV (buffer) is also set with the aead_request_set_crypt call. Note, + * the API call of aead_request_set_ad must provide the length of the AAD and + * the IV. The API call of aead_request_set_crypt only points to the size of + * the input plaintext or ciphertext. + * + * * for "normal" AEAD ciphers, the concatenation of + * associated authentication data || plaintext or ciphertext. + * + * It is important to note that if multiple scatter gather list entries form + * the input data mentioned above, the first entry must not point to a NULL + * buffer. If there is any potential where the AAD buffer can be NULL, the + * calling code must contain a precaution to ensure that this does not result + * in the first scatter gather list entry pointing to a NULL buffer. */ /** -- cgit v1.2.3-59-g8ed1b From 575c215c00140e83b32ca6c01443b8a458e55c73 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 30 Jul 2015 18:13:54 -0700 Subject: docs: dts: Added documentation for Xilinx Zynq Reset Controller bindings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Moritz Fischer Reviewed-by: Michal Simek Acked-by: Sören Brinkmann Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/zynq-reset.txt | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/zynq-reset.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/zynq-reset.txt b/Documentation/devicetree/bindings/reset/zynq-reset.txt new file mode 100644 index 000000000000..5860120e3064 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/zynq-reset.txt @@ -0,0 +1,68 @@ +Xilinx Zynq Reset Manager + +The Zynq AP-SoC has several different resets. + +See Chapter 26 of the Zynq TRM (UG585) for more information about Zynq resets. + +Required properties: +- compatible: "xlnx,zynq-reset" +- reg: SLCR offset and size taken via syscon <0x200 0x48> +- syscon: <&slcr> + This should be a phandle to the Zynq's SLCR registers. +- #reset-cells: Must be 1 + +The Zynq Reset Manager needs to be a childnode of the SLCR. + +Example: + rstc: rstc@200 { + compatible = "xlnx,zynq-reset"; + reg = <0x200 0x48>; + #reset-cells = <1>; + syscon = <&slcr>; + }; + +Reset outputs: + 0 : soft reset + 32 : ddr reset + 64 : topsw reset + 96 : dmac reset + 128: usb0 reset + 129: usb1 reset + 160: gem0 reset + 161: gem1 reset + 164: gem0 rx reset + 165: gem1 rx reset + 166: gem0 ref reset + 167: gem1 ref reset + 192: sdio0 reset + 193: sdio1 reset + 196: sdio0 ref reset + 197: sdio1 ref reset + 224: spi0 reset + 225: spi1 reset + 226: spi0 ref reset + 227: spi1 ref reset + 256: can0 reset + 257: can1 reset + 258: can0 ref reset + 259: can1 ref reset + 288: i2c0 reset + 289: i2c1 reset + 320: uart0 reset + 321: uart1 reset + 322: uart0 ref reset + 323: uart1 ref reset + 352: gpio reset + 384: lqspi reset + 385: qspi ref reset + 416: smc reset + 417: smc ref reset + 448: ocm reset + 512: fpga0 out reset + 513: fpga1 out reset + 514: fpga2 out reset + 515: fpga3 out reset + 544: a9 reset 0 + 545: a9 reset 1 + 552: peri reset + -- cgit v1.2.3-59-g8ed1b From 12d560f4ea87030667438a169912380be00cea4b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 14 Jul 2015 18:35:23 -0700 Subject: rcu,locking: Privatize smp_mb__after_unlock_lock() RCU is the only thing that uses smp_mb__after_unlock_lock(), and is likely the only thing that ever will use it, so this commit makes this macro private to RCU. Signed-off-by: Paul E. McKenney Cc: Will Deacon Cc: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: "linux-arch@vger.kernel.org" --- Documentation/memory-barriers.txt | 71 +++---------------------------------- arch/powerpc/include/asm/spinlock.h | 2 -- include/linux/spinlock.h | 10 ------ kernel/rcu/tree.h | 12 +++++++ 4 files changed, 16 insertions(+), 79 deletions(-) (limited to 'Documentation') diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 318523872db5..eafa6a53f72c 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1854,16 +1854,10 @@ RELEASE are to the same lock variable, but only from the perspective of another CPU not holding that lock. In short, a ACQUIRE followed by an RELEASE may -not- be assumed to be a full memory barrier. -Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not -imply a full memory barrier. If it is necessary for a RELEASE-ACQUIRE -pair to produce a full barrier, the ACQUIRE can be followed by an -smp_mb__after_unlock_lock() invocation. This will produce a full barrier -(including transitivity) if either (a) the RELEASE and the ACQUIRE are -executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on -the same variable. The smp_mb__after_unlock_lock() primitive is free -on many architectures. Without smp_mb__after_unlock_lock(), the CPU's -execution of the critical sections corresponding to the RELEASE and the -ACQUIRE can cross, so that: +Similarly, the reverse case of a RELEASE followed by an ACQUIRE does +not imply a full memory barrier. Therefore, the CPU's execution of the +critical sections corresponding to the RELEASE and the ACQUIRE can cross, +so that: *A = a; RELEASE M @@ -1901,29 +1895,6 @@ the RELEASE would simply complete, thereby avoiding the deadlock. a sleep-unlock race, but the locking primitive needs to resolve such races properly in any case. -With smp_mb__after_unlock_lock(), the two critical sections cannot overlap. -For example, with the following code, the store to *A will always be -seen by other CPUs before the store to *B: - - *A = a; - RELEASE M - ACQUIRE N - smp_mb__after_unlock_lock(); - *B = b; - -The operations will always occur in one of the following orders: - - STORE *A, RELEASE, ACQUIRE, smp_mb__after_unlock_lock(), STORE *B - STORE *A, ACQUIRE, RELEASE, smp_mb__after_unlock_lock(), STORE *B - ACQUIRE, STORE *A, RELEASE, smp_mb__after_unlock_lock(), STORE *B - -If the RELEASE and ACQUIRE were instead both operating on the same lock -variable, only the first of these alternatives can occur. In addition, -the more strongly ordered systems may rule out some of the above orders. -But in any case, as noted earlier, the smp_mb__after_unlock_lock() -ensures that the store to *A will always be seen as happening before -the store to *B. - Locks and semaphores may not provide any guarantee of ordering on UP compiled systems, and so cannot be counted on in such a situation to actually achieve anything at all - especially with respect to I/O accesses - unless combined @@ -2154,40 +2125,6 @@ But it won't see any of: *E, *F or *G following RELEASE Q -However, if the following occurs: - - CPU 1 CPU 2 - =============================== =============================== - WRITE_ONCE(*A, a); - ACQUIRE M [1] - WRITE_ONCE(*B, b); - WRITE_ONCE(*C, c); - RELEASE M [1] - WRITE_ONCE(*D, d); WRITE_ONCE(*E, e); - ACQUIRE M [2] - smp_mb__after_unlock_lock(); - WRITE_ONCE(*F, f); - WRITE_ONCE(*G, g); - RELEASE M [2] - WRITE_ONCE(*H, h); - -CPU 3 might see: - - *E, ACQUIRE M [1], *C, *B, *A, RELEASE M [1], - ACQUIRE M [2], *H, *F, *G, RELEASE M [2], *D - -But assuming CPU 1 gets the lock first, CPU 3 won't see any of: - - *B, *C, *D, *F, *G or *H preceding ACQUIRE M [1] - *A, *B or *C following RELEASE M [1] - *F, *G or *H preceding ACQUIRE M [2] - *A, *B, *C, *E, *F or *G following RELEASE M [2] - -Note that the smp_mb__after_unlock_lock() is critically important -here: Without it CPU 3 might see some of the above orderings. -Without smp_mb__after_unlock_lock(), the accesses are not guaranteed -to be seen in order unless CPU 3 holds lock M. - ACQUIRES VS I/O ACCESSES ------------------------ diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index 4dbe072eecbe..523673d7583c 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -28,8 +28,6 @@ #include #include -#define smp_mb__after_unlock_lock() smp_mb() /* Full ordering for lock. */ - #ifdef CONFIG_PPC64 /* use 0x800000yy when locked, where yy == CPU number */ #ifdef __BIG_ENDIAN__ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 0063b24b4f36..16c5ed5a627c 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -130,16 +130,6 @@ do { \ #define smp_mb__before_spinlock() smp_wmb() #endif -/* - * Place this after a lock-acquisition primitive to guarantee that - * an UNLOCK+LOCK pair act as a full barrier. This guarantee applies - * if the UNLOCK and LOCK are executed by the same CPU or if the - * UNLOCK and LOCK operate on the same lock variable. - */ -#ifndef smp_mb__after_unlock_lock -#define smp_mb__after_unlock_lock() do { } while (0) -#endif - /** * raw_spin_unlock_wait - wait until the spinlock gets unlocked * @lock: the spinlock in question. diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 0412030ca882..2e991f8361e4 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -653,3 +653,15 @@ static inline void rcu_nocb_q_lengths(struct rcu_data *rdp, long *ql, long *qll) #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ } #endif /* #ifdef CONFIG_RCU_TRACE */ + +/* + * Place this after a lock-acquisition primitive to guarantee that + * an UNLOCK+LOCK pair act as a full barrier. This guarantee applies + * if the UNLOCK and LOCK are executed by the same CPU or if the + * UNLOCK and LOCK operate on the same lock variable. + */ +#ifdef CONFIG_PPC +#define smp_mb__after_unlock_lock() smp_mb() /* Full ordering for lock. */ +#else /* #ifdef CONFIG_PPC */ +#define smp_mb__after_unlock_lock() do { } while (0) +#endif /* #else #ifdef CONFIG_PPC */ -- cgit v1.2.3-59-g8ed1b From 6abc8ca19df0078de17dc38340db3002ed489ce7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 4 Aug 2015 15:20:55 -0400 Subject: cgroup: define controller file conventions Traditionally, each cgroup controller implemented whatever interface it wanted leading to interfaces which are widely inconsistent. Examining the requirements of the controllers readily yield that there are only a few control schemes shared among all. Two major controllers already had to implement new interface for the unified hierarchy due to significant structural changes. Let's take the chance to establish common conventions throughout all controllers. This patch defines CGROUP_WEIGHT_MIN/DFL/MAX to be used on all weight based control knobs and documents the conventions that controllers should follow on the unified hierarchy. Except for io.weight knob, all existing unified hierarchy knobs are already compliant. A follow-up patch will update io.weight. v2: Added descriptions of min, low and high knobs. Signed-off-by: Tejun Heo Acked-by: Johannes Weiner Cc: Li Zefan Cc: Peter Zijlstra --- Documentation/cgroups/unified-hierarchy.txt | 80 ++++++++++++++++++++++++++--- include/linux/cgroup.h | 9 ++++ 2 files changed, 81 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/unified-hierarchy.txt b/Documentation/cgroups/unified-hierarchy.txt index 86847a7647ab..1ee9caf29e57 100644 --- a/Documentation/cgroups/unified-hierarchy.txt +++ b/Documentation/cgroups/unified-hierarchy.txt @@ -23,10 +23,13 @@ CONTENTS 5. Other Changes 5-1. [Un]populated Notification 5-2. Other Core Changes - 5-3. Per-Controller Changes - 5-3-1. blkio - 5-3-2. cpuset - 5-3-3. memory + 5-3. Controller File Conventions + 5-3-1. Format + 5-3-2. Control Knobs + 5-4. Per-Controller Changes + 5-4-1. blkio + 5-4-2. cpuset + 5-4-3. memory 6. Planned Changes 6-1. CAP for resource control @@ -372,14 +375,75 @@ supported and the interface files "release_agent" and - The "cgroup.clone_children" file is removed. -5-3. Per-Controller Changes +5-3. Controller File Conventions -5-3-1. blkio +5-3-1. Format + +In general, all controller files should be in one of the following +formats whenever possible. + +- Values only files + + VAL0 VAL1...\n + +- Flat keyed files + + KEY0 VAL0\n + KEY1 VAL1\n + ... + +- Nested keyed files + + KEY0 SUB_KEY0=VAL00 SUB_KEY1=VAL01... + KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11... + ... + +For a writeable file, the format for writing should generally match +reading; however, controllers may allow omitting later fields or +implement restricted shortcuts for most common use cases. + +For both flat and nested keyed files, only the values for a single key +can be written at a time. For nested keyed files, the sub key pairs +may be specified in any order and not all pairs have to be specified. + + +5-3-2. Control Knobs + +- Settings for a single feature should generally be implemented in a + single file. + +- In general, the root cgroup should be exempt from resource control + and thus shouldn't have resource control knobs. + +- If a controller implements ratio based resource distribution, the + control knob should be named "weight" and have the range [1, 10000] + and 100 should be the default value. The values are chosen to allow + enough and symmetric bias in both directions while keeping it + intuitive (the default is 100%). + +- If a controller implements an absolute resource guarantee and/or + limit, the control knobs should be named "min" and "max" + respectively. If a controller implements best effort resource + gurantee and/or limit, the control knobs should be named "low" and + "high" respectively. + + In the above four control files, the special token "max" should be + used to represent upward infinity for both reading and writing. + +- If a setting has configurable default value and specific overrides, + the default settings should be keyed with "default" and appear as + the first entry in the file. Specific entries can use "default" as + its value to indicate inheritance of the default value. + + +5-4. Per-Controller Changes + +5-4-1. blkio - blk-throttle becomes properly hierarchical. -5-3-2. cpuset +5-4-2. cpuset - Tasks are kept in empty cpusets after hotplug and take on the masks of the nearest non-empty ancestor, instead of being moved to it. @@ -388,7 +452,7 @@ supported and the interface files "release_agent" and masks of the nearest non-empty ancestor. -5-3-3. memory +5-4-3. memory - use_hierarchy is on by default and the cgroup file for the flag is not created. diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index a593e299162e..c6bf9d30c270 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -22,6 +22,15 @@ #ifdef CONFIG_CGROUPS +/* + * All weight knobs on the default hierarhcy should use the following min, + * default and max values. The default value is the logarithmic center of + * MIN and MAX and allows 100x to be expressed in both directions. + */ +#define CGROUP_WEIGHT_MIN 1 +#define CGROUP_WEIGHT_DFL 100 +#define CGROUP_WEIGHT_MAX 10000 + /* a css_task_iter should be treated as an opaque object */ struct css_task_iter { struct cgroup_subsys *ss; -- cgit v1.2.3-59-g8ed1b From aca3c3546396b305fff79f09883cff48a908aac0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: allow max_current to be managed via sysfs. 'max_current' sysfs attributes are created which allow the max to be set. Whenever a current source changes, the default is restored. This will be followed by a uevent, so user-space can decide to update again. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 15 +++++ drivers/power/twl4030_charger.c | 72 ++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030 (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 new file mode 100644 index 000000000000..0331bba4605d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -0,0 +1,15 @@ +What: /sys/class/power_supply/twl4030_ac/max_current + /sys/class/power_supply/twl4030_usb/max_current +Description: + Read/Write limit on current which may + be drawn from the ac (Accessory Charger) or + USB port. + + Value is in micro-Amps. + + Value is set automatically to an appropriate + value when a cable is plugged or unplugged. + + Value can the set by writing to the attribute. + The change will only persist until the next + plug event. These event are reported via udev. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 982675df21b7..b0a50adebfda 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -482,6 +482,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) struct twl4030_bci *bci = arg; dev_dbg(bci->dev, "CHG_PRES irq\n"); + /* reset current on each 'plug' event */ + bci->ac_cur = 500000; twl4030_charger_update_current(bci); power_supply_changed(bci->ac); power_supply_changed(bci->usb); @@ -536,6 +538,63 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) return IRQ_HANDLED; } +/* + * Provide "max_current" attribute in sysfs. + */ +static ssize_t +twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int cur = 0; + int status = 0; + status = kstrtoint(buf, 10, &cur); + if (status) + return status; + if (cur < 0) + return -EINVAL; + if (dev == &bci->ac->dev) + bci->ac_cur = cur; + else + bci->usb_cur = cur; + + twl4030_charger_update_current(bci); + return n; +} + +/* + * sysfs max_current show + */ +static ssize_t twl4030_bci_max_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int status = 0; + int cur = -1; + u8 bcictl1; + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + + if (dev == &bci->ac->dev) { + if (!bci->ac_is_active) + cur = bci->ac_cur; + } else { + if (bci->ac_is_active) + cur = bci->usb_cur; + } + if (cur < 0) { + cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); + if (cur < 0) + return cur; + status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); + if (status < 0) + return status; + cur = regval2ua(cur, bcictl1 & TWL4030_CGAIN); + } + return scnprintf(buf, PAGE_SIZE, "%u\n", cur); +} + +static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show, + twl4030_bci_max_current_store); + static void twl4030_bci_usb_work(struct work_struct *data) { struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); @@ -558,6 +617,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, dev_dbg(bci->dev, "OTG notify %lu\n", val); + /* reset current on each 'plug' event */ + if (allow_usb) + bci->usb_cur = 500000; + else + bci->usb_cur = 100000; + bci->event = val; schedule_work(&bci->work); @@ -831,6 +896,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); twl4030_charger_update_current(bci); + if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + twl4030_charger_enable_ac(true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, @@ -855,6 +925,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); + device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v1.2.3-59-g8ed1b From 22d4c33f7335ddf6deda26630c78650e133bfe72 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: enable manual enable/disable of usb charging. 'off' or 'auto' to /sys/class/power/twl4030_usb/mode will now enable or disable charging from USB port. Normally this is enabled on 'plug' and disabled on 'unplug'. Unplug will still disable charging. 'plug' will only enable it if 'auto' if selected. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 11 ++++ drivers/power/twl4030_charger.c | 59 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 0331bba4605d..40e0f919cbde 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -13,3 +13,14 @@ Description: Value can the set by writing to the attribute. The change will only persist until the next plug event. These event are reported via udev. + + +What: /sys/class/power_supply/twl4030_usb/mode +Description: + Changing mode for USB port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index b0a50adebfda..6fa928ed3128 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -109,10 +109,16 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; + int usb_mode; /* charging mode requested */ +#define CHARGE_OFF 0 +#define CHARGE_AUTO 1 unsigned long event; }; +/* strings for 'usb_mode' values */ +static char *modes[] = { "off", "auto" }; + /* * clear and set bits on an given register on a given module */ @@ -386,6 +392,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->usb_mode == CHARGE_OFF) + enable = false; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { twl4030_charger_update_current(bci); @@ -629,6 +637,53 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } +/* + * sysfs charger enabled store + */ +static ssize_t +twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int mode; + int status; + + if (sysfs_streq(buf, modes[0])) + mode = 0; + else if (sysfs_streq(buf, modes[1])) + mode = 1; + else + return -EINVAL; + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + return (status == 0) ? n : status; +} + +/* + * sysfs charger enabled show + */ +static ssize_t +twl4030_bci_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(modes); i++) + if (bci->usb_mode == i) + len += snprintf(buf+len, PAGE_SIZE-len, + "[%s] ", modes[i]); + else + len += snprintf(buf+len, PAGE_SIZE-len, + "%s ", modes[i]); + buf[len-1] = '\n'; + return len; +} +static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show, + twl4030_bci_mode_store); + static int twl4030_charger_get_current(void) { int curr; @@ -815,6 +870,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->usb_cur = 500000; /* 500mA */ else bci->usb_cur = 100000; /* 100mA */ + bci->usb_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -898,6 +954,8 @@ static int twl4030_bci_probe(struct platform_device *pdev) twl4030_charger_update_current(bci); if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->usb->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); @@ -926,6 +984,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, -- cgit v1.2.3-59-g8ed1b From 7f4a633d21331155ee06c5ee44749ed35a3a3cc5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add software controlled linear charging mode. Add a 'continuous' option for usb charging which enables the "linear" charging mode of the twl4030. Linear charging does a good job with not-so-reliable power sources. Auto mode does not work well as it switches off when voltage drops momentarily. Care must be taken not to over-charge. It was used with a bike hub dynamo since a year or so. In that case there are automatically charging stops when the cyclist needs a break. Original-by: Andreas Kemnade Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 9 ++++ drivers/power/twl4030_charger.c | 55 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 40e0f919cbde..e8baa36aaa2b 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -24,3 +24,12 @@ Description: "auto" - draw power as appropriate for detected power source and battery status. "off" - do not draw any power. + "continuous" + - activate mode described as "linear" in + TWL data sheets. This uses whatever + current is available and doesn't switch off + when voltage drops. + + This is useful for unstable power sources + such as bicycle dynamo, but care should + be taken that battery is not over-charged. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 6fa928ed3128..de5430deaf23 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -24,6 +24,8 @@ #include #include +#define TWL4030_BCIMDEN 0x00 +#define TWL4030_BCIMDKEY 0x01 #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 #define TWL4030_BCIVAC 0x0a @@ -35,13 +37,16 @@ #define TWL4030_BCIIREF1 0x27 #define TWL4030_BCIIREF2 0x28 #define TWL4030_BCIMFKEY 0x11 +#define TWL4030_BCIMFEN3 0x14 #define TWL4030_BCIMFTH8 0x1d #define TWL4030_BCIMFTH9 0x1e +#define TWL4030_BCIWDKEY 0x21 #define TWL4030_BCIMFSTS1 0x01 #define TWL4030_BCIAUTOWEN BIT(5) #define TWL4030_CONFIG_DONE BIT(4) +#define TWL4030_CVENAC BIT(2) #define TWL4030_BCIAUTOUSB BIT(1) #define TWL4030_BCIAUTOAC BIT(0) #define TWL4030_CGAIN BIT(5) @@ -112,12 +117,13 @@ struct twl4030_bci { int usb_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 +#define CHARGE_LINEAR 2 unsigned long event; }; /* strings for 'usb_mode' values */ -static char *modes[] = { "off", "auto" }; +static char *modes[] = { "off", "auto", "continuous" }; /* * clear and set bits on an given register on a given module @@ -404,16 +410,42 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) bci->usb_enabled = 1; } - /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ - ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); - if (ret < 0) - return ret; + if (bci->usb_mode == CHARGE_AUTO) + /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ + ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0, TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); + if (bci->usb_mode == CHARGE_LINEAR) { + twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0); + /* Watch dog key: WOVF acknowledge */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33, + TWL4030_BCIWDKEY); + /* 0x24 + EKEY6: off mode */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); + /* EKEY2: Linear charge: USB path */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26, + TWL4030_BCIMDKEY); + /* WDKEY5: stop watchdog count */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3, + TWL4030_BCIWDKEY); + /* enable MFEN3 access */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c, + TWL4030_BCIMFKEY); + /* ICHGEOCEN - end-of-charge monitor (current < 80mA) + * (charging continues) + * ICHGLOWEN - current level monitor (charge continues) + * don't monitor over-current or heat save + */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0, + TWL4030_BCIMFEN3); + } } else { ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); + ret |= twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); if (bci->usb_enabled) { pm_runtime_mark_last_busy(bci->transceiver->dev); pm_runtime_put_autosuspend(bci->transceiver->dev); @@ -652,6 +684,8 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 0; else if (sysfs_streq(buf, modes[1])) mode = 1; + else if (sysfs_streq(buf, modes[2])) + mode = 2; else return -EINVAL; twl4030_charger_enable_usb(bci, false); @@ -750,6 +784,17 @@ static int twl4030_bci_get_property(struct power_supply *psy, is_charging = state & TWL4030_MSTATEC_USB; else is_charging = state & TWL4030_MSTATEC_AC; + if (!is_charging) { + u8 s; + twl4030_bci_read(TWL4030_BCIMDEN, &s); + if (psy->desc->type == POWER_SUPPLY_TYPE_USB) + is_charging = s & 1; + else + is_charging = s & 2; + if (is_charging) + /* A little white lie */ + state = TWL4030_MSTATEC_QUICK1; + } switch (psp) { case POWER_SUPPLY_PROP_STATUS: -- cgit v1.2.3-59-g8ed1b From b04b908d8a2901c2cc59db87defd9c08bd4293cc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add ac/mode to match usb/mode This allows AC charging to be turned off, much like usb charging. "continuous" mode is not available though. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 10 +++++++ drivers/power/twl4030_charger.c | 35 +++++++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index e8baa36aaa2b..be26af0f1895 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -33,3 +33,13 @@ Description: This is useful for unstable power sources such as bicycle dynamo, but care should be taken that battery is not over-charged. + +What: /sys/class/power_supply/twl4030_ac/mode +Description: + Changing mode for 'ac' port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index de5430deaf23..68117ad23564 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -114,7 +114,7 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; - int usb_mode; /* charging mode requested */ + int usb_mode, ac_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 #define CHARGE_LINEAR 2 @@ -459,10 +459,13 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) /* * Enable/Disable AC Charge funtionality. */ -static int twl4030_charger_enable_ac(bool enable) +static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->ac_mode == CHARGE_OFF) + enable = false; + if (enable) ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC); else @@ -688,9 +691,17 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 2; else return -EINVAL; - twl4030_charger_enable_usb(bci, false); - bci->usb_mode = mode; - status = twl4030_charger_enable_usb(bci, true); + if (dev == &bci->ac->dev) { + if (mode == 2) + return -EINVAL; + twl4030_charger_enable_ac(bci, false); + bci->ac_mode = mode; + status = twl4030_charger_enable_ac(bci, true); + } else { + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + } return (status == 0) ? n : status; } @@ -704,9 +715,13 @@ twl4030_bci_mode_show(struct device *dev, struct twl4030_bci *bci = dev_get_drvdata(dev->parent); int len = 0; int i; + int mode = bci->usb_mode; + + if (dev == &bci->ac->dev) + mode = bci->ac_mode; for (i = 0; i < ARRAY_SIZE(modes); i++) - if (bci->usb_mode == i) + if (mode == i) len += snprintf(buf+len, PAGE_SIZE-len, "[%s] ", modes[i]); else @@ -916,6 +931,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) else bci->usb_cur = 100000; /* 100mA */ bci->usb_mode = CHARGE_AUTO; + bci->ac_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -1001,10 +1017,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->usb->dev, &dev_attr_mode)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); - twl4030_charger_enable_ac(true); + twl4030_charger_enable_ac(bci, true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, bci->transceiver->last_event, @@ -1024,13 +1042,14 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) { struct twl4030_bci *bci = platform_get_drvdata(pdev); - twl4030_charger_enable_ac(false); + twl4030_charger_enable_ac(bci, false); twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_mode); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v1.2.3-59-g8ed1b From 7b9c5162c1829686baea1962177842c3fa1ea81c Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Sat, 25 Jul 2015 02:02:46 +0200 Subject: serial: etraxfs-uart: use mctrl_gpio helpers for handling modem signals In order to use the mctrl_gpio helpers, we change the DT bindings: ri-gpios renamed to rng-gpios. cd-gpios renamed to dcd-gpios. However, no in-tree dts/dtsi specifies these, so no worries. Signed-off-by: Niklas Cassel Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/axis,etraxfs-uart.txt | 6 +++- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/etraxfs-uart.c | 40 ++++++---------------- 3 files changed, 16 insertions(+), 31 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt index ebcbb62c0a76..51b3c9e80ad9 100644 --- a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt +++ b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt @@ -6,7 +6,7 @@ Required properties: - interrupts: device interrupt Optional properties: -- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD +- {dtr,dsr,rng,dcd}-gpios: specify a GPIO for DTR/DSR/RI/DCD line respectively. Example: @@ -16,4 +16,8 @@ serial@b00260000 { reg = <0xb0026000 0x1000>; interrupts = <68>; status = "disabled"; + dtr-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>; + dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>; + rng-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>; + dcd-gpios = <&sysgpio 3 GPIO_ACTIVE_LOW>; }; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4c8662ea7bb0..cbde6b77ef77 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1067,6 +1067,7 @@ config SERIAL_ETRAXFS bool "ETRAX FS serial port support" depends on ETRAX_ARCH_V32 && OF select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_ETRAXFS_CONSOLE bool "ETRAX FS serial console support" diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c index 8f242dc84cea..6813e316e9ff 100644 --- a/drivers/tty/serial/etraxfs-uart.c +++ b/drivers/tty/serial/etraxfs-uart.c @@ -10,6 +10,8 @@ #include #include +#include "serial_mctrl_gpio.h" + #define DRV_NAME "etraxfs-uart" #define UART_NR CONFIG_ETRAX_SERIAL_PORTS @@ -28,10 +30,7 @@ struct uart_cris_port { void __iomem *regi_ser; - struct gpio_desc *dtr_pin; - struct gpio_desc *dsr_pin; - struct gpio_desc *ri_pin; - struct gpio_desc *cd_pin; + struct mctrl_gpios *gpios; int write_ongoing; }; @@ -389,21 +388,9 @@ static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port) ret = 0; if (crisv32_serial_get_rts(up)) ret |= TIOCM_RTS; - /* DTR is active low */ - if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin)) - ret |= TIOCM_DTR; - /* CD is active low */ - if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin)) - ret |= TIOCM_CD; - /* RI is active low */ - if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin)) - ret |= TIOCM_RI; - /* DSR is active low */ - if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin)) - ret |= TIOCM_DSR; if (crisv32_serial_get_cts(up)) ret |= TIOCM_CTS; - return ret; + return mctrl_gpio_get(up->gpios, &ret); } static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -411,15 +398,7 @@ static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_cris_port *up = (struct uart_cris_port *)port; crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0); - /* DTR is active low */ - if (up->dtr_pin) - gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1); - /* RI is active low */ - if (up->ri_pin) - gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1); - /* CD is active low */ - if (up->cd_pin) - gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1); + mctrl_gpio_set(up->gpios, mctrl); } static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state) @@ -913,11 +892,12 @@ static int etraxfs_uart_probe(struct platform_device *pdev) up->irq = irq_of_parse_and_map(np, 0); up->regi_ser = of_iomap(np, 0); - up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr"); - up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr"); - up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri"); - up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd"); up->port.dev = &pdev->dev; + + up->gpios = mctrl_gpio_init(&pdev->dev, 0); + if (IS_ERR(up->gpios)) + return PTR_ERR(up->gpios); + cris_serial_port_init(&up->port, dev_id); etraxfs_uart_ports[dev_id] = up; -- cgit v1.2.3-59-g8ed1b From c268a743103aebba8d81d3365107f7170653099e Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 30 Jul 2015 19:12:12 +0200 Subject: ARM: at91/soc: add basic support for new sama5d2 SoC Add Kconfig entries, header file changes and addition to the documentation. The early debug infrastructure is also added for easy development. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: Olof Johansson --- Documentation/arm/Atmel/README | 5 +++++ Documentation/devicetree/bindings/arm/atmel-at91.txt | 2 ++ arch/arm/Kconfig.debug | 6 ++++++ arch/arm/include/debug/at91.S | 5 ++++- arch/arm/mach-at91/Kconfig | 12 ++++++++++++ arch/arm/mach-at91/sama5.c | 3 +++ arch/arm/mach-at91/soc.h | 3 +++ 7 files changed, 35 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README index c53a19b4aab2..0931cf7e2e56 100644 --- a/Documentation/arm/Atmel/README +++ b/Documentation/arm/Atmel/README @@ -90,6 +90,11 @@ the Atmel website: http://www.atmel.com. + Datasheet http://www.atmel.com/Images/Atmel-11238-32-bit-Cortex-A5-Microcontroller-SAMA5D4_Datasheet.pdf + - sama5d2 family + - sama5d27 + + Datasheet + Coming soon + Linux kernel information ------------------------ diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8cbfa08..7f04b8ae4ca9 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -27,6 +27,8 @@ compatible: must be one of: o "atmel,at91sam9xe" * "atmel,sama5" for SoCs using a Cortex-A5, shall be extended with the specific SoC family: + o "atmel,sama5d2" shall be extended with the specific SoC compatible: + - "atmel,sama5d27" o "atmel,sama5d3" shall be extended with the specific SoC compatible: - "atmel,sama5d31" - "atmel,sama5d33" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index a2e16f940394..946c8c0fa1fb 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -141,6 +141,12 @@ choice depends on ARCH_AT91 depends on SOC_SAMA5 + config AT91_DEBUG_LL_DBGU3 + bool "Kernel low-level debugging on sama5d2" + select DEBUG_AT91_UART + depends on ARCH_AT91 + depends on SOC_SAMA5 + config DEBUG_BCM2835 bool "Kernel low-level debugging on BCM2835 PL011 UART" depends on ARCH_BCM2835 diff --git a/arch/arm/include/debug/at91.S b/arch/arm/include/debug/at91.S index c3c45e628e33..2556a8801c8c 100644 --- a/arch/arm/include/debug/at91.S +++ b/arch/arm/include/debug/at91.S @@ -13,9 +13,12 @@ #define AT91_DBGU 0xfffff200 /* AT91_BASE_DBGU0 */ #elif defined(CONFIG_AT91_DEBUG_LL_DBGU1) #define AT91_DBGU 0xffffee00 /* AT91_BASE_DBGU1 */ -#else +#elif defined(CONFIG_AT91_DEBUG_LL_DBGU2) /* On sama5d4, use USART3 as low level serial console */ #define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */ +#else +/* On sama5d2, use UART1 as low level serial console */ +#define AT91_DBGU 0xf8020000 #endif #ifdef CONFIG_MMU diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index fd95f34945f4..89a755b90db2 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -8,6 +8,18 @@ menuconfig ARCH_AT91 select SOC_BUS if ARCH_AT91 +config SOC_SAMA5D2 + bool "SAMA5D2 family" if ARCH_MULTI_V7 + select SOC_SAMA5 + select CACHE_L2X0 + select HAVE_FB_ATMEL + select HAVE_AT91_UTMI + select HAVE_AT91_USB_CLK + select HAVE_AT91_H32MX + select HAVE_AT91_GENERATED_CLK + help + Select this if ou are using one of Atmel's SAMA5D2 family SoC. + config SOC_SAMA5D3 bool "SAMA5D3 family" if ARCH_MULTI_V7 select SOC_SAMA5 diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index 41d829d8e7d5..90c3c3051ae7 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -18,6 +18,8 @@ #include "soc.h" static const struct at91_soc sama5_socs[] = { + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27_EXID_MATCH, + "sama5d27", "sama5d2"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, "sama5d31", "sama5d3"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, @@ -64,6 +66,7 @@ DT_MACHINE_START(sama5_dt, "Atmel SAMA5") MACHINE_END static const char *sama5_alt_dt_board_compat[] __initconst = { + "atmel,sama5d2", "atmel,sama5d4", NULL }; diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h index be23c400596b..8ede0ef86172 100644 --- a/arch/arm/mach-at91/soc.h +++ b/arch/arm/mach-at91/soc.h @@ -62,6 +62,9 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 +#define SAMA5D2_CIDR_MATCH 0x0a5c08c0 +#define SAMA5D27_EXID_MATCH 0x00000021 + #define SAMA5D3_CIDR_MATCH 0x0a5c07c0 #define SAMA5D31_EXID_MATCH 0x00444300 #define SAMA5D33_EXID_MATCH 0x00414300 -- cgit v1.2.3-59-g8ed1b From 61186371570e3ca62585e29e307f7a9c42ab789a Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 26 Jul 2015 23:37:51 +0200 Subject: dt-binding: document the binding for mxc rtc This adds documentation of device tree bindings for the mxc rtc. Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: devicetree@vger.kernel.org Signed-off-by: Philippe Reynes Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/rtc/rtc-mxc.txt | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/rtc-mxc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-mxc.txt b/Documentation/devicetree/bindings/rtc/rtc-mxc.txt new file mode 100644 index 000000000000..5bcd31d995b0 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-mxc.txt @@ -0,0 +1,26 @@ +* Real Time Clock of the i.MX SoCs + +RTC controller for the i.MX SoCs + +Required properties: +- compatible: Should be "fsl,imx1-rtc" or "fsl,imx21-rtc". +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the RTC. +- clocks: should contain two entries: + * one for the input reference + * one for the the SoC RTC +- clock-names: should contain: + * "ref" for the input reference clock + * "ipg" for the SoC RTC clock + +Example: + +rtc@10007000 { + compatible = "fsl,imx21-rtc"; + reg = <0x10007000 0x1000>; + interrupts = <22>; + clocks = <&clks IMX27_CLK_CKIL>, + <&clks IMX27_CLK_RTC_IPG_GATE>; + clock-names = "ref", "ipg"; +}; -- cgit v1.2.3-59-g8ed1b From 54bf725e5d21022b25fe0d3c103fe82ed13b870b Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 5 Aug 2015 00:52:45 -0700 Subject: Drivers: hv: vmbus: document the VMBus sysfs files The 4 sysfs files should be stable ABIs to the user space. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-vmbus | 29 +++++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 30 insertions(+) create mode 100644 Documentation/ABI/stable/sysfs-bus-vmbus (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus new file mode 100644 index 000000000000..636e938d5e33 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-bus-vmbus @@ -0,0 +1,29 @@ +What: /sys/bus/vmbus/devices/vmbus_*/id +Date: Jul 2009 +KernelVersion: 2.6.31 +Contact: K. Y. Srinivasan +Description: The VMBus child_relid of the device's primary channel +Users: tools/hv/lsvmbus + +What: /sys/bus/vmbus/devices/vmbus_*/class_id +Date: Jul 2009 +KernelVersion: 2.6.31 +Contact: K. Y. Srinivasan +Description: The VMBus interface type GUID of the device +Users: tools/hv/lsvmbus + +What: /sys/bus/vmbus/devices/vmbus_*/device_id +Date: Jul 2009 +KernelVersion: 2.6.31 +Contact: K. Y. Srinivasan +Description: The VMBus interface instance GUID of the device +Users: tools/hv/lsvmbus + +What: /sys/bus/vmbus/devices/vmbus_*/channel_vp_mapping +Date: Jul 2015 +KernelVersion: 4.2.0 +Contact: K. Y. Srinivasan +Description: The mapping of which primary/sub channels are bound to which + Virtual Processors. + Format: +Users: tools/hv/lsvmbus diff --git a/MAINTAINERS b/MAINTAINERS index 9289ecb57b68..cde3eceea4e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4957,6 +4957,7 @@ F: drivers/scsi/storvsc_drv.c F: drivers/video/fbdev/hyperv_fb.c F: include/linux/hyperv.h F: tools/hv/ +F: Documentation/ABI/stable/sysfs-bus-vmbus I2C OVER PARALLEL PORT M: Jean Delvare -- cgit v1.2.3-59-g8ed1b From 89af7ba5740b5937d10c8de93e79e71e5a933041 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 5 Aug 2015 00:52:46 -0700 Subject: cpu-hotplug: convert cpu_hotplug_disabled to a counter As a prerequisite to exporting cpu_hotplug_enable/cpu_hotplug_disable functions to modules we need to convert cpu_hotplug_disabled to a counter to properly support disable -> disable -> enable call sequences. E.g. after Hyper-V vmbus module (which is supposed to be the first user of exported cpu_hotplug_enable/cpu_hotplug_disable) did cpu_hotplug_disable() hibernate path calls disable_nonboot_cpus() and if we hit an error in _cpu_down() enable_nonboot_cpus() will be called on the failure path (thus making cpu_hotplug_disabled = 0 and leaving cpu hotplug in 'enabled' state). Same problem is possible if more than 1 module use cpu_hotplug_disable/cpu_hotplug_enable on their load/unload paths. When one of these modules is been unloaded it is logical to leave cpu hotplug in 'disabled' state. To support the change we need to increse cpu_hotplug_disabled counter in disable_nonboot_cpus() unconditionally as all users of disable_nonboot_cpus() are supposed to do enable_nonboot_cpus() in case an error was returned. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Thomas Gleixner Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- Documentation/power/suspend-and-cpuhotplug.txt | 6 +++--- kernel/cpu.c | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/power/suspend-and-cpuhotplug.txt b/Documentation/power/suspend-and-cpuhotplug.txt index 2850df3bf957..2fc909502db5 100644 --- a/Documentation/power/suspend-and-cpuhotplug.txt +++ b/Documentation/power/suspend-and-cpuhotplug.txt @@ -72,7 +72,7 @@ More details follow: | v Disable regular cpu hotplug - by setting cpu_hotplug_disabled=1 + by increasing cpu_hotplug_disabled | v Release cpu_add_remove_lock @@ -89,7 +89,7 @@ Resuming back is likewise, with the counterparts being (in the order of execution during resume): * enable_nonboot_cpus() which involves: | Acquire cpu_add_remove_lock - | Reset cpu_hotplug_disabled to 0, thereby enabling regular cpu hotplug + | Decrease cpu_hotplug_disabled, thereby enabling regular cpu hotplug | Call _cpu_up() [for all those cpus in the frozen_cpus mask, in a loop] | Release cpu_add_remove_lock v @@ -120,7 +120,7 @@ after the entire cycle is complete (i.e., suspend + resume). Acquire cpu_add_remove_lock | v - If cpu_hotplug_disabled is 1 + If cpu_hotplug_disabled > 0 return gracefully | | diff --git a/kernel/cpu.c b/kernel/cpu.c index 5644ec5582b9..0fca2ba96138 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -191,14 +191,14 @@ void cpu_hotplug_done(void) void cpu_hotplug_disable(void) { cpu_maps_update_begin(); - cpu_hotplug_disabled = 1; + cpu_hotplug_disabled++; cpu_maps_update_done(); } void cpu_hotplug_enable(void) { cpu_maps_update_begin(); - cpu_hotplug_disabled = 0; + WARN_ON(--cpu_hotplug_disabled < 0); cpu_maps_update_done(); } @@ -608,13 +608,18 @@ int disable_nonboot_cpus(void) } } - if (!error) { + if (!error) BUG_ON(num_online_cpus() > 1); - /* Make sure the CPUs won't be enabled by someone else */ - cpu_hotplug_disabled = 1; - } else { + else pr_err("Non-boot CPUs are not disabled\n"); - } + + /* + * Make sure the CPUs won't be enabled by someone else. We need to do + * this even in case of failure as all disable_nonboot_cpus() users are + * supposed to do enable_nonboot_cpus() on the failure path. + */ + cpu_hotplug_disabled++; + cpu_maps_update_done(); return error; } @@ -633,7 +638,7 @@ void __ref enable_nonboot_cpus(void) /* Allow everyone to use the CPU hotplug again */ cpu_maps_update_begin(); - cpu_hotplug_disabled = 0; + WARN_ON(--cpu_hotplug_disabled < 0); if (cpumask_empty(frozen_cpus)) goto out; -- cgit v1.2.3-59-g8ed1b From e5742ef1279e4cfe52fee7056b15a848ffe5c723 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 31 Jul 2015 09:37:21 -0600 Subject: coresight: binding for ETMv4 coresight drivers Adding compatible string for new coresight ETMv4 tracer. Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/coresight.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 65a6db2271a2..62938eb9697f 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -17,6 +17,7 @@ its hardware characteristcs. - "arm,coresight-tmc", "arm,primecell"; - "arm,coresight-funnel", "arm,primecell"; - "arm,coresight-etm3x", "arm,primecell"; + - "arm,coresight-etm4x", "arm,primecell"; - "qcom,coresight-replicator1x", "arm,primecell"; * reg: physical base address and length of the register -- cgit v1.2.3-59-g8ed1b From 414a1417d7b35e0e72edb16e45840e242cb6b52e Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:24 -0600 Subject: coresight-etm3x: Change the name of the ctxid_val to ctxid_pid 'ctxid_val' array was used to store the value of ETM context ID comparator which actually stores the process ID to be traced, so using 'ctxid_pid' as its name instead make it easier to understand. This patch also changes the ABI, it is normally not allowed, but fortunately it is a testing ABI and very new for now. Nevertheless, if you don't think it should be changed, we could always add an alias for userspace. Signed-off-by: Chunyan Zhang Reviewed-by: Mark Brown Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-coresight-devices-etm3x | 2 +- drivers/hwtracing/coresight/coresight-etm.h | 4 ++-- drivers/hwtracing/coresight/coresight-etm3x.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x index b4d0b99afffb..d72ca1736ba4 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x @@ -112,7 +112,7 @@ KernelVersion: 3.19 Contact: Mathieu Poirier Description: (RW) Mask to apply to all the context ID comparator. -What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_val +What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_pid Date: November 2014 KernelVersion: 3.19 Contact: Mathieu Poirier diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 098ffbec0a44..52af5f0adbed 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h @@ -183,7 +183,7 @@ * @seq_13_event: event causing the transition from 1 to 3. * @seq_curr_state: current value of the sequencer register. * @ctxid_idx: index for the context ID registers. - * @ctxid_val: value for the context ID to trigger on. + * @ctxid_pid: value for the context ID to trigger on. * @ctxid_mask: mask applicable to all the context IDs. * @sync_freq: Synchronisation frequency. * @timestamp_event: Defines an event that requests the insertion @@ -235,7 +235,7 @@ struct etm_drvdata { u32 seq_13_event; u32 seq_curr_state; u8 ctxid_idx; - u32 ctxid_val[ETM_MAX_CTXID_CMP]; + u32 ctxid_pid[ETM_MAX_CTXID_CMP]; u32 ctxid_mask; u32 sync_freq; u32 timestamp_event; diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index cca98a8b2527..361b82068dda 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -238,7 +238,7 @@ static void etm_set_default(struct etm_drvdata *drvdata) drvdata->seq_curr_state = 0x0; drvdata->ctxid_idx = 0x0; for (i = 0; i < drvdata->nr_ctxid_cmp; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask = 0x0; } @@ -289,7 +289,7 @@ static void etm_enable_hw(void *info) for (i = 0; i < drvdata->nr_ext_out; i++) etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i)); for (i = 0; i < drvdata->nr_ctxid_cmp; i++) - etm_writel(drvdata, drvdata->ctxid_val[i], ETMCIDCVRn(i)); + etm_writel(drvdata, drvdata->ctxid_pid[i], ETMCIDCVRn(i)); etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR); etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR); /* No external input selected */ @@ -1386,20 +1386,20 @@ static ssize_t ctxid_idx_store(struct device *dev, } static DEVICE_ATTR_RW(ctxid_idx); -static ssize_t ctxid_val_show(struct device *dev, +static ssize_t ctxid_pid_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); spin_lock(&drvdata->spinlock); - val = drvdata->ctxid_val[drvdata->ctxid_idx]; + val = drvdata->ctxid_pid[drvdata->ctxid_idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); } -static ssize_t ctxid_val_store(struct device *dev, +static ssize_t ctxid_pid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -1412,12 +1412,12 @@ static ssize_t ctxid_val_store(struct device *dev, return ret; spin_lock(&drvdata->spinlock); - drvdata->ctxid_val[drvdata->ctxid_idx] = val; + drvdata->ctxid_pid[drvdata->ctxid_idx] = val; spin_unlock(&drvdata->spinlock); return size; } -static DEVICE_ATTR_RW(ctxid_val); +static DEVICE_ATTR_RW(ctxid_pid); static ssize_t ctxid_mask_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1609,7 +1609,7 @@ static struct attribute *coresight_etm_attrs[] = { &dev_attr_seq_13_event.attr, &dev_attr_seq_curr_state.attr, &dev_attr_ctxid_idx.attr, - &dev_attr_ctxid_val.attr, + &dev_attr_ctxid_pid.attr, &dev_attr_ctxid_mask.attr, &dev_attr_sync_freq.attr, &dev_attr_timestamp_event.attr, -- cgit v1.2.3-59-g8ed1b From cd196ac3fa5a574f3ddf37b66fbe8c58225c3355 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:25 -0600 Subject: coresight-etm4x: Change the name of the ctxid_val to ctxid_pid 'ctxid_val' array was used to store the value of ETM context ID comparator which actually stores the process ID to be traced, so using 'ctxid_pid' as its name instead make it easier to understand. This patch also changes the ABI, it is normally not allowed, but fortunately it is a testing ABI and very new for now. Nevertheless, if you don't think it should be changed, we could always add an alias for userspace. Signed-off-by: Chunyan Zhang Reviewed-by: Mark Brown Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-coresight-devices-etm4x | 2 +- drivers/hwtracing/coresight/coresight-etm4x.c | 20 ++++++++++---------- drivers/hwtracing/coresight/coresight-etm4x.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x index 2fe2e3dae487..2355ed8ae31f 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x @@ -249,7 +249,7 @@ KernelVersion: 4.01 Contact: Mathieu Poirier Description: (RW) Select which context ID comparator to work with. -What: /sys/bus/coresight/devices/.etm/ctxid_val +What: /sys/bus/coresight/devices/.etm/ctxid_pid Date: April 2015 KernelVersion: 4.01 Contact: Mathieu Poirier diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 1312e993c501..9afbda54b013 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -155,7 +155,7 @@ static void etm4_enable_hw(void *info) drvdata->base + TRCACATRn(i)); } for (i = 0; i < drvdata->numcidc; i++) - writeq_relaxed(drvdata->ctxid_val[i], + writeq_relaxed(drvdata->ctxid_pid[i], drvdata->base + TRCCIDCVRn(i)); writel_relaxed(drvdata->ctxid_mask0, drvdata->base + TRCCIDCCTLR0); writel_relaxed(drvdata->ctxid_mask1, drvdata->base + TRCCIDCCTLR1); @@ -507,7 +507,7 @@ static ssize_t reset_store(struct device *dev, drvdata->ctxid_idx = 0x0; for (i = 0; i < drvdata->numcidc; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; @@ -1815,7 +1815,7 @@ static ssize_t ctxid_idx_store(struct device *dev, } static DEVICE_ATTR_RW(ctxid_idx); -static ssize_t ctxid_val_show(struct device *dev, +static ssize_t ctxid_pid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1825,12 +1825,12 @@ static ssize_t ctxid_val_show(struct device *dev, spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - val = (unsigned long)drvdata->ctxid_val[idx]; + val = (unsigned long)drvdata->ctxid_pid[idx]; spin_unlock(&drvdata->spinlock); return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); } -static ssize_t ctxid_val_store(struct device *dev, +static ssize_t ctxid_pid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -1850,11 +1850,11 @@ static ssize_t ctxid_val_store(struct device *dev, spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - drvdata->ctxid_val[idx] = (u64)val; + drvdata->ctxid_pid[idx] = (u64)val; spin_unlock(&drvdata->spinlock); return size; } -static DEVICE_ATTR_RW(ctxid_val); +static DEVICE_ATTR_RW(ctxid_pid); static ssize_t ctxid_masks_show(struct device *dev, struct device_attribute *attr, @@ -1949,7 +1949,7 @@ static ssize_t ctxid_masks_store(struct device *dev, */ for (j = 0; j < 8; j++) { if (maskbyte & 1) - drvdata->ctxid_val[i] &= ~(0xFF << (j * 8)); + drvdata->ctxid_pid[i] &= ~(0xFF << (j * 8)); maskbyte >>= 1; } /* Select the next ctxid comparator mask value */ @@ -2193,7 +2193,7 @@ static struct attribute *coresight_etmv4_attrs[] = { &dev_attr_res_idx.attr, &dev_attr_res_ctrl.attr, &dev_attr_ctxid_idx.attr, - &dev_attr_ctxid_val.attr, + &dev_attr_ctxid_pid.attr, &dev_attr_ctxid_masks.attr, &dev_attr_vmid_idx.attr, &dev_attr_vmid_val.attr, @@ -2514,7 +2514,7 @@ static void etm4_init_default_data(struct etmv4_drvdata *drvdata) } for (i = 0; i < drvdata->numcidc; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index e08e983dd2d9..1e8fb369daaf 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -265,7 +265,7 @@ * @addr_type: Current status of the comparator register. * @ctxid_idx: Context ID index selector. * @ctxid_size: Size of the context ID field to consider. - * @ctxid_val: Value of the context ID comparator. + * @ctxid_pid: Value of the context ID comparator. * @ctxid_mask0:Context ID comparator mask for comparator 0-3. * @ctxid_mask1:Context ID comparator mask for comparator 4-7. * @vmid_idx: VM ID index selector. @@ -352,7 +352,7 @@ struct etmv4_drvdata { u8 addr_type[ETM_MAX_SINGLE_ADDR_CMP]; u8 ctxid_idx; u8 ctxid_size; - u64 ctxid_val[ETMv4_MAX_CTXID_CMP]; + u64 ctxid_pid[ETMv4_MAX_CTXID_CMP]; u32 ctxid_mask0; u32 ctxid_mask1; u8 vmid_idx; -- cgit v1.2.3-59-g8ed1b From f8b66fe52d3ae97df9f2eef6410bd5aef095914c Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 31 Jul 2015 09:37:29 -0600 Subject: Doc: trace: Fix typo in coresight.txt This patch fix spelling typos found in coresight.txt Signed-off-by: Masanari Iida Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/coresight.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt index 77d14d51a670..0a5c3290e732 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -15,7 +15,7 @@ HW assisted tracing is becoming increasingly useful when dealing with systems that have many SoCs and other components like GPU and DMA engines. ARM has developed a HW assisted tracing solution by means of different components, each being added to a design at synthesis time to cater to specific tracing needs. -Compoments are generally categorised as source, link and sinks and are +Components are generally categorised as source, link and sinks and are (usually) discovered using the AMBA bus. "Sources" generate a compressed stream representing the processor instruction @@ -138,7 +138,7 @@ void coresight_unregister(struct coresight_device *csdev); The registering function is taking a "struct coresight_device *csdev" and register the device with the core framework. The unregister function takes -a reference to a "strut coresight_device", obtained at registration time. +a reference to a "struct coresight_device", obtained at registration time. If everything goes well during the registration process the new devices will show up under /sys/bus/coresight/devices, as showns here for a TC2 platform: -- cgit v1.2.3-59-g8ed1b From 2af38ab572b031a4111f01153cc020b1038b427b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:13:58 +0100 Subject: nvmem: Add bindings for simple nvmem framework This patch adds bindings for simple nvmem framework which allows nvmem consumers to talk to nvmem providers to get access to nvmem cell data. Signed-off-by: Maxime Ripard [Maxime Ripard: intial version of eeprom framework] Signed-off-by: Srinivas Kandagatla Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/nvmem.txt | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt new file mode 100644 index 000000000000..b52bc11e9597 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt @@ -0,0 +1,80 @@ += NVMEM(Non Volatile Memory) Data Device Tree Bindings = + +This binding is intended to represent the location of hardware +configuration data stored in NVMEMs like eeprom, efuses and so on. + +On a significant proportion of boards, the manufacturer has stored +some data on NVMEM, for the OS to be able to retrieve these information +and act upon it. Obviously, the OS has to know about where to retrieve +these data from, and where they are stored on the storage device. + +This document is here to document this. + += Data providers = +Contains bindings specific to provider drivers and data cells as children +of this node. + +Optional properties: + read-only: Mark the provider as read only. + += Data cells = +These are the child nodes of the provider which contain data cell +information like offset and size in nvmem provider. + +Required properties: +reg: specifies the offset in byte within the storage device. + +Optional properties: + +bits: Is pair of bit location and number of bits, which specifies offset + in bit and number of bits within the address range specified by reg property. + Offset takes values from 0-7. + +For example: + + /* Provider */ + qfprom: qfprom@00700000 { + ... + + /* Data cells */ + tsens_calibration: calib@404 { + reg = <0x404 0x10>; + }; + + tsens_calibration_bckp: calib_bckp@504 { + reg = <0x504 0x11>; + bits = <6 128> + }; + + pvs_version: pvs-version@6 { + reg = <0x6 0x2> + bits = <7 2> + }; + + speed_bin: speed-bin@c{ + reg = <0xc 0x1>; + bits = <2 3>; + + }; + ... + }; + += Data consumers = +Are device nodes which consume nvmem data cells/providers. + +Required-properties: +nvmem-cells: list of phandle to the nvmem data cells. +nvmem-cell-names: names for the each nvmem-cells specified. Required if + nvmem-cells is used. + +Optional-properties: +nvmem : list of phandles to nvmem providers. +nvmem-names: names for the each nvmem provider. required if nvmem is used. + +For example: + + tsens { + ... + nvmem-cells = <&tsens_calibration>; + nvmem-cell-names = "calibration"; + }; -- cgit v1.2.3-59-g8ed1b From 354ebb541dfa37a83395e5a9b7d68c34f80fffc0 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:14:14 +0100 Subject: Documentation: nvmem: add nvmem api level and how-to doc This patch add basic how-to and api summary documentation for simple NVMEM framework. Signed-off-by: Srinivas Kandagatla Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- Documentation/nvmem/nvmem.txt | 152 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 Documentation/nvmem/nvmem.txt (limited to 'Documentation') diff --git a/Documentation/nvmem/nvmem.txt b/Documentation/nvmem/nvmem.txt new file mode 100644 index 000000000000..dbd40d879239 --- /dev/null +++ b/Documentation/nvmem/nvmem.txt @@ -0,0 +1,152 @@ + NVMEM SUBSYSTEM + Srinivas Kandagatla + +This document explains the NVMEM Framework along with the APIs provided, +and how to use it. + +1. Introduction +=============== +*NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to +retrieve configuration of SOC or Device specific data from non volatile +memories like eeprom, efuses and so on. + +Before this framework existed, NVMEM drivers like eeprom were stored in +drivers/misc, where they all had to duplicate pretty much the same code to +register a sysfs file, allow in-kernel users to access the content of the +devices they were driving, etc. + +This was also a problem as far as other in-kernel users were involved, since +the solutions used were pretty much different from one driver to another, there +was a rather big abstraction leak. + +This framework aims at solve these problems. It also introduces DT +representation for consumer devices to go get the data they require (MAC +Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs. This +framework is based on regmap, so that most of the abstraction available in +regmap can be reused, across multiple types of buses. + +NVMEM Providers ++++++++++++++++ + +NVMEM provider refers to an entity that implements methods to initialize, read +and write the non-volatile memory. + +2. Registering/Unregistering the NVMEM provider +=============================================== + +A NVMEM provider can register with NVMEM core by supplying relevant +nvmem configuration to nvmem_register(), on success core would return a valid +nvmem_device pointer. + +nvmem_unregister(nvmem) is used to unregister a previously registered provider. + +For example, a simple qfprom case: + +static struct nvmem_config econfig = { + .name = "qfprom", + .owner = THIS_MODULE, +}; + +static int qfprom_probe(struct platform_device *pdev) +{ + ... + econfig.dev = &pdev->dev; + nvmem = nvmem_register(&econfig); + ... +} + +It is mandatory that the NVMEM provider has a regmap associated with its +struct device. Failure to do would return error code from nvmem_register(). + +NVMEM Consumers ++++++++++++++++ + +NVMEM consumers are the entities which make use of the NVMEM provider to +read from and to NVMEM. + +3. NVMEM cell based consumer APIs +================================= + +NVMEM cells are the data entries/fields in the NVMEM. +The NVMEM framework provides 3 APIs to read/write NVMEM cells. + +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name); +struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name); + +void nvmem_cell_put(struct nvmem_cell *cell); +void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); + +void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len); +int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len); + +*nvmem_cell_get() apis will get a reference to nvmem cell for a given id, +and nvmem_cell_read/write() can then read or write to the cell. +Once the usage of the cell is finished the consumer should call *nvmem_cell_put() +to free all the allocation memory for the cell. + +4. Direct NVMEM device based consumer APIs +========================================== + +In some instances it is necessary to directly read/write the NVMEM. +To facilitate such consumers NVMEM framework provides below apis. + +struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); +struct nvmem_device *devm_nvmem_device_get(struct device *dev, + const char *name); +void nvmem_device_put(struct nvmem_device *nvmem); +int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset, + size_t bytes, void *buf); +int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset, + size_t bytes, void *buf); +int nvmem_device_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf); +int nvmem_device_cell_write(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf); + +Before the consumers can read/write NVMEM directly, it should get hold +of nvmem_controller from one of the *nvmem_device_get() api. + +The difference between these apis and cell based apis is that these apis always +take nvmem_device as parameter. + +5. Releasing a reference to the NVMEM +===================================== + +When a consumers no longer needs the NVMEM, it has to release the reference +to the NVMEM it has obtained using the APIs mentioned in the above section. +The NVMEM framework provides 2 APIs to release a reference to the NVMEM. + +void nvmem_cell_put(struct nvmem_cell *cell); +void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); +void nvmem_device_put(struct nvmem_device *nvmem); +void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem); + +Both these APIs are used to release a reference to the NVMEM and +devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated +with this NVMEM. + +Userspace ++++++++++ + +6. Userspace binary interface +============================== + +Userspace can read/write the raw NVMEM file located at +/sys/bus/nvmem/devices/*/nvmem + +ex: + +hexdump /sys/bus/nvmem/devices/qfprom0/nvmem + +0000000 0000 0000 0000 0000 0000 0000 0000 0000 +* +00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00 +0000000 0000 0000 0000 0000 0000 0000 0000 0000 +... +* +0001000 + +7. DeviceTree Binding +===================== + +See Documentation/devicetree/bindings/nvmem/nvmem.txt -- cgit v1.2.3-59-g8ed1b From b470d6d7a5dfe41112d55c39eac67ddc5afac80d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:16:59 +0100 Subject: nvmem: qfprom: Add bindings for qfprom This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver is based on simple nvmem framework. Signed-off-by: Srinivas Kandagatla Reviewed-by: Stephen Boyd Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qfprom.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/nvmem/qfprom.txt b/Documentation/devicetree/bindings/nvmem/qfprom.txt new file mode 100644 index 000000000000..4ad68b7f5c18 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/qfprom.txt @@ -0,0 +1,35 @@ += Qualcomm QFPROM device tree bindings = + +This binding is intended to represent QFPROM which is found in most QCOM SOCs. + +Required properties: +- compatible: should be "qcom,qfprom" +- reg: Should contain registers location and length + += Data cells = +Are child nodes of qfprom, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + qfprom: qfprom@00700000 { + compatible = "qcom,qfprom"; + reg = <0x00700000 0x8000>; + ... + /* Data cells */ + tsens_calibration: calib@404 { + reg = <0x4404 0x10>; + }; + }; + + += Data consumers = +Are device nodes which consume nvmem data cells. + +For example: + + tsens { + ... + nvmem-cells = <&tsens_calibration>; + nvmem-cell-names = "calibration"; + }; -- cgit v1.2.3-59-g8ed1b From 3d0b16a66c8a9d10294572c6f79df4f15a27825d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 Jul 2015 12:17:09 +0100 Subject: nvmem: sunxi: Move the SID driver to the nvmem framework Now that we have the nvmem framework, we can consolidate the common driver code. Move the driver to the framework, and hopefully, it will fix the sysfs file creation race. Signed-off-by: Maxime Ripard [srinivas.kandagatla: Moved to regmap based EEPROM framework] Signed-off-by: Srinivas Kandagatla Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 --- .../bindings/misc/allwinner,sunxi-sid.txt | 17 -- .../bindings/nvmem/allwinner,sunxi-sid.txt | 21 +++ drivers/misc/eeprom/Kconfig | 13 -- drivers/misc/eeprom/Makefile | 1 - drivers/misc/eeprom/sunxi_sid.c | 156 ------------------- drivers/nvmem/Kconfig | 11 ++ drivers/nvmem/Makefile | 2 + drivers/nvmem/sunxi_sid.c | 171 +++++++++++++++++++++ 9 files changed, 205 insertions(+), 209 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt delete mode 100644 drivers/misc/eeprom/sunxi_sid.c create mode 100644 drivers/nvmem/sunxi_sid.c (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid deleted file mode 100644 index ffb9536f6ecc..000000000000 --- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid +++ /dev/null @@ -1,22 +0,0 @@ -What: /sys/devices/*//eeprom -Date: August 2013 -Contact: Oliver Schinagl -Description: read-only access to the SID (Security-ID) on current - A-series SoC's from Allwinner. Currently supports A10, A10s, A13 - and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes, - whereas the newer A20 SoC exposes 512 bytes split into sections. - Besides the 16 bytes of SID, there's also an SJTAG area, - HDMI-HDCP key and some custom keys. Below a quick overview, for - details see the user manual: - 0x000 128 bit root-key (sun[457]i) - 0x010 128 bit boot-key (sun7i) - 0x020 64 bit security-jtag-key (sun7i) - 0x028 16 bit key configuration (sun7i) - 0x02b 16 bit custom-vendor-key (sun7i) - 0x02c 320 bit low general key (sun7i) - 0x040 32 bit read-control access (sun7i) - 0x064 224 bit low general key (sun7i) - 0x080 2304 bit HDCP-key (sun7i) - 0x1a0 768 bit high general key (sun7i) -Users: any user space application which wants to read the SID on - Allwinner's A-series of CPU's. diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt deleted file mode 100644 index fabdf64a5737..000000000000 --- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +++ /dev/null @@ -1,17 +0,0 @@ -Allwinner sunxi-sid - -Required properties: -- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid" -- reg: Should contain registers location and length - -Example for sun4i: - sid@01c23800 { - compatible = "allwinner,sun4i-a10-sid"; - reg = <0x01c23800 0x10> - }; - -Example for sun7i: - sid@01c23800 { - compatible = "allwinner,sun7i-a20-sid"; - reg = <0x01c23800 0x200> - }; diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt new file mode 100644 index 000000000000..d543ed3f5363 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt @@ -0,0 +1,21 @@ +Allwinner sunxi-sid + +Required properties: +- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid" +- reg: Should contain registers location and length + += Data cells = +Are child nodes of qfprom, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example for sun4i: + sid@01c23800 { + compatible = "allwinner,sun4i-a10-sid"; + reg = <0x01c23800 0x10> + }; + +Example for sun7i: + sid@01c23800 { + compatible = "allwinner,sun7i-a20-sid"; + reg = <0x01c23800 0x200> + }; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 9536852fd4c6..04f2e1fa9dd1 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG If unsure, say N. -config EEPROM_SUNXI_SID - tristate "Allwinner sunxi security ID support" - depends on ARCH_SUNXI && SYSFS - help - This is a driver for the 'security ID' available on various Allwinner - devices. - - Due to the potential risks involved with changing e-fuses, - this driver is read-only. - - This driver can also be built as a module. If so, the module - will be called sunxi_sid. - endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 9507aec95e94..fc1e81d29267 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o -obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c deleted file mode 100644 index 8385177ff32b..000000000000 --- a/drivers/misc/eeprom/sunxi_sid.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2013 Oliver Schinagl - * http://www.linux-sunxi.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver exposes the Allwinner security ID, efuses exported in byte- - * sized chunks. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "sunxi-sid" - -struct sunxi_sid_data { - void __iomem *reg_base; - unsigned int keysize; -}; - -/* We read the entire key, due to a 32 bit read alignment requirement. Since we - * want to return the requested byte, this results in somewhat slower code and - * uses 4 times more reads as needed but keeps code simpler. Since the SID is - * only very rarely probed, this is not really an issue. - */ -static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data, - const unsigned int offset) -{ - u32 sid_key; - - if (offset >= sid_data->keysize) - return 0; - - sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4)); - sid_key >>= (offset % 4) * 8; - - return sid_key; /* Only return the last byte */ -} - -static ssize_t sid_read(struct file *fd, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t size) -{ - struct platform_device *pdev; - struct sunxi_sid_data *sid_data; - int i; - - pdev = to_platform_device(kobj_to_dev(kobj)); - sid_data = platform_get_drvdata(pdev); - - if (pos < 0 || pos >= sid_data->keysize) - return 0; - if (size > sid_data->keysize - pos) - size = sid_data->keysize - pos; - - for (i = 0; i < size; i++) - buf[i] = sunxi_sid_read_byte(sid_data, pos + i); - - return i; -} - -static struct bin_attribute sid_bin_attr = { - .attr = { .name = "eeprom", .mode = S_IRUGO, }, - .read = sid_read, -}; - -static int sunxi_sid_remove(struct platform_device *pdev) -{ - device_remove_bin_file(&pdev->dev, &sid_bin_attr); - dev_dbg(&pdev->dev, "driver unloaded\n"); - - return 0; -} - -static const struct of_device_id sunxi_sid_of_match[] = { - { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16}, - { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512}, - {/* sentinel */}, -}; -MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); - -static int sunxi_sid_probe(struct platform_device *pdev) -{ - struct sunxi_sid_data *sid_data; - struct resource *res; - const struct of_device_id *of_dev_id; - u8 *entropy; - unsigned int i; - - sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data), - GFP_KERNEL); - if (!sid_data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(sid_data->reg_base)) - return PTR_ERR(sid_data->reg_base); - - of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev); - if (!of_dev_id) - return -ENODEV; - sid_data->keysize = (int)of_dev_id->data; - - platform_set_drvdata(pdev, sid_data); - - sid_bin_attr.size = sid_data->keysize; - if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) - return -ENODEV; - - entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL); - for (i = 0; i < sid_data->keysize; i++) - entropy[i] = sunxi_sid_read_byte(sid_data, i); - add_device_randomness(entropy, sid_data->keysize); - kfree(entropy); - - dev_dbg(&pdev->dev, "loaded\n"); - - return 0; -} - -static struct platform_driver sunxi_sid_driver = { - .probe = sunxi_sid_probe, - .remove = sunxi_sid_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = sunxi_sid_of_match, - }, -}; -module_platform_driver(sunxi_sid_driver); - -MODULE_AUTHOR("Oliver Schinagl "); -MODULE_DESCRIPTION("Allwinner sunxi security id driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index fa85805bbdb7..8db297821f78 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -25,4 +25,15 @@ config QCOM_QFPROM This driver can also be built as a module. If so, the module will be called nvmem_qfprom. +config NVMEM_SUNXI_SID + tristate "Allwinner SoCs SID support" + depends on ARCH_SUNXI + select REGMAP_MMIO + help + This is a driver for the 'security ID' available on various Allwinner + devices. + + This driver can also be built as a module. If so, the module + will be called nvmem_sunxi_sid. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index ff44fe99c7d2..4328b930ad9a 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -8,3 +8,5 @@ nvmem_core-y := core.o # Devices obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o nvmem_qfprom-y := qfprom.o +obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o +nvmem_sunxi_sid-y := sunxi_sid.o diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c new file mode 100644 index 000000000000..14777dd5212d --- /dev/null +++ b/drivers/nvmem/sunxi_sid.c @@ -0,0 +1,171 @@ +/* + * Allwinner sunXi SoCs Security ID support. + * + * Copyright (c) 2013 Oliver Schinagl + * Copyright (C) 2014 Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct nvmem_config econfig = { + .name = "sunxi-sid", + .read_only = true, + .owner = THIS_MODULE, +}; + +struct sunxi_sid { + void __iomem *base; +}; + +/* We read the entire key, due to a 32 bit read alignment requirement. Since we + * want to return the requested byte, this results in somewhat slower code and + * uses 4 times more reads as needed but keeps code simpler. Since the SID is + * only very rarely probed, this is not really an issue. + */ +static u8 sunxi_sid_read_byte(const struct sunxi_sid *sid, + const unsigned int offset) +{ + u32 sid_key; + + sid_key = ioread32be(sid->base + round_down(offset, 4)); + sid_key >>= (offset % 4) * 8; + + return sid_key; /* Only return the last byte */ +} + +static int sunxi_sid_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct sunxi_sid *sid = context; + unsigned int offset = *(u32 *)reg; + u8 *buf = val; + + while (val_size) { + *buf++ = sunxi_sid_read_byte(sid, offset); + val_size--; + offset++; + } + + return 0; +} + +static int sunxi_sid_write(void *context, const void *data, size_t count) +{ + /* Unimplemented, dummy to keep regmap core happy */ + return 0; +} + +static struct regmap_bus sunxi_sid_bus = { + .read = sunxi_sid_read, + .write = sunxi_sid_write, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg) +{ + return false; +} + +static struct regmap_config sunxi_sid_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .reg_stride = 1, + .writeable_reg = sunxi_sid_writeable_reg, +}; + +static int sunxi_sid_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct nvmem_device *nvmem; + struct regmap *regmap; + struct sunxi_sid *sid; + int i, size; + char *randomness; + + sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL); + if (!sid) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sid->base = devm_ioremap_resource(dev, res); + if (IS_ERR(sid->base)) + return PTR_ERR(sid->base); + + size = resource_size(res) - 1; + sunxi_sid_regmap_config.max_register = size; + + regmap = devm_regmap_init(dev, &sunxi_sid_bus, sid, + &sunxi_sid_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(regmap); + } + + econfig.dev = dev; + nvmem = nvmem_register(&econfig); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + randomness = kzalloc(sizeof(u8) * size, GFP_KERNEL); + for (i = 0; i < size; i++) + randomness[i] = sunxi_sid_read_byte(sid, i); + + add_device_randomness(randomness, size); + kfree(randomness); + + platform_set_drvdata(pdev, nvmem); + + return 0; +} + +static int sunxi_sid_remove(struct platform_device *pdev) +{ + struct nvmem_device *nvmem = platform_get_drvdata(pdev); + + return nvmem_unregister(nvmem); +} + +static const struct of_device_id sunxi_sid_of_match[] = { + { .compatible = "allwinner,sun4i-a10-sid" }, + { .compatible = "allwinner,sun7i-a20-sid" }, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); + +static struct platform_driver sunxi_sid_driver = { + .probe = sunxi_sid_probe, + .remove = sunxi_sid_remove, + .driver = { + .name = "eeprom-sunxi-sid", + .of_match_table = sunxi_sid_of_match, + }, +}; +module_platform_driver(sunxi_sid_driver); + +MODULE_AUTHOR("Oliver Schinagl "); +MODULE_DESCRIPTION("Allwinner sunxi security id driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 223e8f01b072152cc4336e7dcb1cf8c21ab34432 Mon Sep 17 00:00:00 2001 From: "Seymour, Shane M" Date: Thu, 25 Jun 2015 02:33:08 +0000 Subject: sysfs.txt: update show method notes about sprintf/snprintf/scnprintf usage Changed the documentation to allow sprintf() when the buffer provided by sysfs cannot be overflowed. Explicitly say snprintf() must never be used in a show function to format data to be returned to user space. Change based on a discussion about the patch st: convert DRIVER_ATTR macros to DRIVER_ATTR_RO Suggested-by: Greg Kroah-Hartman Signed-off-by: Shane Seymour Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/sysfs.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt index b35a64b82f9e..9494afb9476a 100644 --- a/Documentation/filesystems/sysfs.txt +++ b/Documentation/filesystems/sysfs.txt @@ -212,7 +212,10 @@ Other notes: - show() methods should return the number of bytes printed into the buffer. This is the return value of scnprintf(). -- show() should always use scnprintf(). +- show() must not use snprintf() when formatting the value to be + returned to user space. If you can guarantee that an overflow + will never happen you can use sprintf() otherwise you must use + scnprintf(). - store() should return the number of bytes used from the buffer. If the entire buffer has been used, just return the count argument. -- cgit v1.2.3-59-g8ed1b From bf64dd262eaaece2ff560e86fabf94c6725f3b5c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Aug 2015 09:26:41 +0200 Subject: ARM: ux500: add an SMP enablement type and move cpu nodes The "cpus" node cannot be inside the "soc" node, while this works for the CoreSight blocks, the early boot code will look for "cpus" directly under the root node, so this is a hard convention. So move the CPU nodes. Augment the "reg" property to match what is actually in the hardware: 0x300 and 0x301 respectively. Then add an SMP enablement type to be used by the SMP init code, "ste,dbx500-smp". Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson --- Documentation/devicetree/bindings/arm/cpus.txt | 1 + arch/arm/boot/dts/ste-dbx5x0.dtsi | 53 +++++++++++++------------- 2 files changed, 28 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index d6b794cef0b8..91e6e5c478d0 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -199,6 +199,7 @@ nodes to be present and contain the properties described below. "qcom,kpss-acc-v1" "qcom,kpss-acc-v2" "rockchip,rk3066-smp" + "ste,dbx500-smp" - cpu-release-addr Usage: required for systems that have an "enable-method" diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index a75f3289e653..b8f81fb418ce 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -15,6 +15,33 @@ #include "skeleton.dtsi" / { + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "ste,dbx500-smp"; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + }; + }; + CPU0: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0x300>; + }; + CPU1: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0x301>; + }; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -22,32 +49,6 @@ interrupt-parent = <&intc>; ranges; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu-map { - cluster0 { - core0 { - cpu = <&CPU0>; - }; - core1 { - cpu = <&CPU1>; - }; - }; - }; - CPU0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <0>; - }; - CPU1: cpu@1 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <1>; - }; - }; - ptm@801ae000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0x801ae000 0x1000>; -- cgit v1.2.3-59-g8ed1b From 151b49e19119da28dfcd29561147ec56913cbe61 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:25:41 -0500 Subject: Documentation: fsl-quadspi: Add fsl, imx7d-qspi compatible string new compatible string: "fsl,imx7d-qspi" Signed-off-by: Frank Li Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt index 4461dc71cb10..ca72696d70ae 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt @@ -1,7 +1,8 @@ * Freescale Quad Serial Peripheral Interface(QuadSPI) Required properties: - - compatible : Should be "fsl,vf610-qspi" or "fsl,imx6sx-qspi" + - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", + "fsl,imx7d-qspi" - reg : the first contains the register location and length, the second contains the memory mapping address and length - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" -- cgit v1.2.3-59-g8ed1b From cb94d0bb41e43b4fdd219ad930686397814bcd8d Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:25:52 -0500 Subject: Documentation: fsl-quadspi: Add fsl, imx6ul-qspi compatible string new compatible string: "fsl,imx6ul-qspi". Signed-off-by: Frank Li Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt index ca72696d70ae..862aa2f8837a 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt @@ -2,7 +2,7 @@ Required properties: - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", - "fsl,imx7d-qspi" + "fsl,imx7d-qspi", "fsl,imx6ul-qspi" - reg : the first contains the register location and length, the second contains the memory mapping address and length - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" -- cgit v1.2.3-59-g8ed1b From e9c9963b439db734e9705f96909c5a3388dd81bb Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 6 Aug 2015 12:44:23 -0600 Subject: Revert "DocBook: Avoid building man pages repeatedly and inconsistently" This reverts commit b44158b17099ed5c7c8f4bfb7029942adbfbc318. This commit introduced warnings and possibly inconsistent results into the doc build process. The goal is good but it will need to be achieved another way. Reported-by: Masanari Iida Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 10 +--------- Documentation/DocBook/device-drivers.tmpl | 6 ------ Documentation/DocBook/gadget.tmpl | 3 --- Documentation/DocBook/kernel-api.tmpl | 6 ------ 4 files changed, 1 insertion(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 83fcb6c2a00f..11a41456b943 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -56,13 +56,6 @@ htmldocs: $(HTML) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) - @dups=$$(sed -n 's/.*\([^<]*\)<\/refname>.*/\1/p' \ - $(obj)/*.xml.noextra | sort | uniq -d); \ - if [ -n "$$dups" ]; then \ - echo >&2 "The following manual pages are generated more than once:"; \ - printf >&2 '%s\n' "$$dups"; \ - exit 1; \ - fi find $(obj)/man -name '*.9' | xargs gzip -nf installmandocs: mandocs @@ -157,7 +150,7 @@ quiet_cmd_db2html = HTML $@ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi quiet_cmd_db2man = MAN $@ - cmd_db2man = if grep -q refentry $<; then xmlif excludeextra=1 <$< >$<.noextra && xmlto man $(XMLTOFLAGS) -o $(obj)/man $<.noextra ; fi + cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi %.9 : %.xml @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ @@ -224,7 +217,6 @@ clean-files := $(DOCBOOKS) \ $(patsubst %.xml, %.ps, $(DOCBOOKS)) \ $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ $(patsubst %.xml, %.html, $(DOCBOOKS)) \ - $(patsubst %, %.noextra, $(DOCBOOKS)) \ $(patsubst %.xml, %.9, $(DOCBOOKS)) \ $(index) diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 87853ea1f70b..faf09d4a0ea8 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -194,13 +194,8 @@ X!Edrivers/pnp/system.c Sound Devices - - !Iinclude/sound/core.h - !Esound/sound_core.c - - !Iinclude/sound/pcm.h !Esound/core/pcm.c !Esound/core/device.c @@ -216,7 +211,6 @@ X!Edrivers/pnp/system.c !Esound/core/hwdep.c !Esound/core/pcm_native.c !Esound/core/memalloc.c - diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index e1b87bd63f82..641629221176 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -488,10 +488,7 @@ These are the same types and constants used by host side drivers (and usbcore). - - !Iinclude/linux/usb/ch9.h - Core Objects and Methods diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 722249a0dbfe..ecfd0ea40661 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -58,11 +58,8 @@ String Conversions !Elib/vsprintf.c - - !Finclude/linux/kernel.h kstrtol !Finclude/linux/kernel.h kstrtoul - !Elib/kstrtox.c String Manipulation @@ -181,10 +178,7 @@ X!Ekernel/module.c Hardware Interfaces Interrupt Handling - - !Ekernel/irq/manage.c - DMA Channels -- cgit v1.2.3-59-g8ed1b From 64e32895f9d87aaa0842c07d0b17f4895955db20 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Mon, 27 Jul 2015 10:15:18 +0200 Subject: SubmittingPatches: remove stray quote character Signed-off-by: Jakub Wilk Signed-off-by: Jonathan Corbet --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 80b9f54f87ef..fa596d8a3ab0 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -739,7 +739,7 @@ interest on a single line; it should look something like: git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus - to get these changes:" + to get these changes: A pull request should also include an overall message saying what will be included in the request, a "git shortlog" listing of the patches -- cgit v1.2.3-59-g8ed1b From b325e832e9478b920c1b8366623fe456a3527513 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 4 Aug 2015 12:36:43 -0400 Subject: ARM: keystone: add documentation for SoCs and EVMs Currently there is no general documentation on Keystone SoCs in the Linux Documentation folder of the source tree. This patch adds some essential documentation with links to help users of Keystone Linux and also provide links to existing documents where necessary. Signed-off-by: Murali Karicheri Signed-off-by: Jonathan Corbet --- Documentation/arm/keystone/Overview.txt | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Documentation/arm/keystone/Overview.txt (limited to 'Documentation') diff --git a/Documentation/arm/keystone/Overview.txt b/Documentation/arm/keystone/Overview.txt new file mode 100644 index 000000000000..f17bc4c9dff9 --- /dev/null +++ b/Documentation/arm/keystone/Overview.txt @@ -0,0 +1,73 @@ + TI Keystone Linux Overview + -------------------------- + +Introduction +------------ +Keystone range of SoCs are based on ARM Cortex-A15 MPCore Processors +and c66x DSP cores. This document describes essential information required +for users to run Linux on Keystone based EVMs from Texas Instruments. + +Following SoCs & EVMs are currently supported:- + +------------ K2HK SoC and EVM -------------------------------------------------- + +a.k.a Keystone 2 Hawking/Kepler SoC +TCI6636K2H & TCI6636K2K: See documentation at + http://www.ti.com/product/tci6638k2k + http://www.ti.com/product/tci6638k2h + +EVM: +http://www.advantech.com/Support/TI-EVM/EVMK2HX_sd.aspx + +------------ K2E SoC and EVM --------------------------------------------------- + +a.k.a Keystone 2 Edison SoC +K2E - 66AK2E05: See documentation at + http://www.ti.com/product/66AK2E05/technicaldocuments + +EVM: +https://www.einfochips.com/index.php/partnerships/texas-instruments/k2e-evm.html + +------------ K2L SoC and EVM --------------------------------------------------- + +a.k.a Keystone 2 Lamarr SoC +K2L - TCI6630K2L: See documentation at + http://www.ti.com/product/TCI6630K2L/technicaldocuments +EVM: +https://www.einfochips.com/index.php/partnerships/texas-instruments/k2l-evm.html + +Configuration +------------- + +All of the K2 SoCs/EVMs share a common defconfig, keystone_defconfig and same +image is used to boot on individual EVMs. The platform configuration is +specified through DTS. Following are the DTS used:- + K2HK EVM : k2hk-evm.dts + K2E EVM : k2e-evm.dts + K2L EVM : k2l-evm.dts + +The device tree documentation for the keystone machines are located at + Documentation/devicetree/bindings/arm/keystone/keystone.txt + +Known issues & workaround +------------------------- + +Some of the device drivers used on keystone are re-used from that from +DaVinci and other TI SoCs. These device drivers may use clock APIs directly. +Some of the keystone specific drivers such as netcp uses run time power +management API instead to enable clock. As this API has limitations on +keystone, following workaround is needed to boot Linux. + + Add 'clk_ignore_unused' to the bootargs env variable in u-boot. Otherwise + clock frameworks will try to disable clocks that are unused and disable + the hardware. This is because netcp related power domain and clock + domains are enabled in u-boot as run time power management API currently + doesn't enable clocks for netcp due to a limitation. This workaround is + expected to be removed in the future when proper API support becomes + available. Until then, this work around is needed. + + +Document Author +--------------- +Murali Karicheri +Copyright 2015 Texas Instruments -- cgit v1.2.3-59-g8ed1b From cb4ff766c42f0511ead5488b8de77fd392677464 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 5 Aug 2015 16:24:04 +0800 Subject: ACPI / Documentation: Update method tracing documentation. This patch updates method tracing documentation. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/method-tracing.txt | 204 ++++++++++++++++++++++++++++++---- 1 file changed, 185 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/acpi/method-tracing.txt b/Documentation/acpi/method-tracing.txt index f6efb1ea559a..c2505eefc878 100644 --- a/Documentation/acpi/method-tracing.txt +++ b/Documentation/acpi/method-tracing.txt @@ -1,26 +1,192 @@ -/sys/module/acpi/parameters/: +ACPICA Trace Facility -trace_method_name - The AML method name that the user wants to trace +Copyright (C) 2015, Intel Corporation +Author: Lv Zheng -trace_debug_layer - The temporary debug_layer used when tracing the method. - Using 0xffffffff by default if it is 0. -trace_debug_level - The temporary debug_level used when tracing the method. - Using 0x00ffffff by default if it is 0. +Abstract: -trace_state - The status of the tracing feature. +This document describes the functions and the interfaces of the method +tracing facility. + +1. Functionalities and usage examples: + + ACPICA provides method tracing capability. And two functions are + currently implemented using this capability. + + A. Log reducer + ACPICA subsystem provides debugging outputs when CONFIG_ACPI_DEBUG is + enabled. The debugging messages which are deployed via + ACPI_DEBUG_PRINT() macro can be reduced at 2 levels - per-component + level (known as debug layer, configured via + /sys/module/acpi/parameters/debug_layer) and per-type level (known as + debug level, configured via /sys/module/acpi/parameters/debug_level). + + But when the particular layer/level is applied to the control method + evaluations, the quantity of the debugging outputs may still be too + large to be put into the kernel log buffer. The idea thus is worked out + to only enable the particular debug layer/level (normally more detailed) + logs when the control method evaluation is started, and disable the + detailed logging when the control method evaluation is stopped. + + The following command examples illustrate the usage of the "log reducer" + functionality: + a. Filter out the debug layer/level matched logs when control methods + are being evaluated: + # cd /sys/module/acpi/parameters + # echo "0xXXXXXXXX" > trace_debug_layer + # echo "0xYYYYYYYY" > trace_debug_level + # echo "enable" > trace_state + b. Filter out the debug layer/level matched logs when the specified + control method is being evaluated: + # cd /sys/module/acpi/parameters + # echo "0xXXXXXXXX" > trace_debug_layer + # echo "0xYYYYYYYY" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "method" > /sys/module/acpi/parameters/trace_state + c. Filter out the debug layer/level matched logs when the specified + control method is being evaluated for the first time: + # cd /sys/module/acpi/parameters + # echo "0xXXXXXXXX" > trace_debug_layer + # echo "0xYYYYYYYY" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "method-once" > /sys/module/acpi/parameters/trace_state + Where: + 0xXXXXXXXX/0xYYYYYYYY: Refer to Documentation/acpi/debug.txt for + possible debug layer/level masking values. + \PPPP.AAAA.TTTT.HHHH: Full path of a control method that can be found + in the ACPI namespace. It needn't be an entry + of a control method evaluation. + + B. AML tracer + + There are special log entries added by the method tracing facility at + the "trace points" the AML interpreter starts/stops to execute a control + method, or an AML opcode. Note that the format of the log entries are + subject to change: + [ 0.186427] exdebug-0398 ex_trace_point : Method Begin [0xf58394d8:\_SB.PCI0.LPCB.ECOK] execution. + [ 0.186630] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905c88:If] execution. + [ 0.186820] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905cc0:LEqual] execution. + [ 0.187010] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905a20:-NamePath-] execution. + [ 0.187214] exdebug-0398 ex_trace_point : Opcode End [0xf5905a20:-NamePath-] execution. + [ 0.187407] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905f60:One] execution. + [ 0.187594] exdebug-0398 ex_trace_point : Opcode End [0xf5905f60:One] execution. + [ 0.187789] exdebug-0398 ex_trace_point : Opcode End [0xf5905cc0:LEqual] execution. + [ 0.187980] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905cc0:Return] execution. + [ 0.188146] exdebug-0398 ex_trace_point : Opcode Begin [0xf5905f60:One] execution. + [ 0.188334] exdebug-0398 ex_trace_point : Opcode End [0xf5905f60:One] execution. + [ 0.188524] exdebug-0398 ex_trace_point : Opcode End [0xf5905cc0:Return] execution. + [ 0.188712] exdebug-0398 ex_trace_point : Opcode End [0xf5905c88:If] execution. + [ 0.188903] exdebug-0398 ex_trace_point : Method End [0xf58394d8:\_SB.PCI0.LPCB.ECOK] execution. - "enabled" means this feature is enabled - and the AML method is traced every time it's executed. + Developers can utilize these special log entries to track the AML + interpretion, thus can aid issue debugging and performance tuning. Note + that, as the "AML tracer" logs are implemented via ACPI_DEBUG_PRINT() + macro, CONFIG_ACPI_DEBUG is also required to be enabled for enabling + "AML tracer" logs. - "1" means this feature is enabled and the AML method - will only be traced during the next execution. + The following command examples illustrate the usage of the "AML tracer" + functionality: + a. Filter out the method start/stop "AML tracer" logs when control + methods are being evaluated: + # cd /sys/module/acpi/parameters + # echo "0x80" > trace_debug_layer + # echo "0x10" > trace_debug_level + # echo "enable" > trace_state + b. Filter out the method start/stop "AML tracer" when the specified + control method is being evaluated: + # cd /sys/module/acpi/parameters + # echo "0x80" > trace_debug_layer + # echo "0x10" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "method" > trace_state + c. Filter out the method start/stop "AML tracer" logs when the specified + control method is being evaluated for the first time: + # cd /sys/module/acpi/parameters + # echo "0x80" > trace_debug_layer + # echo "0x10" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "method-once" > trace_state + d. Filter out the method/opcode start/stop "AML tracer" when the + specified control method is being evaluated: + # cd /sys/module/acpi/parameters + # echo "0x80" > trace_debug_layer + # echo "0x10" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "opcode" > trace_state + e. Filter out the method/opcode start/stop "AML tracer" when the + specified control method is being evaluated for the first time: + # cd /sys/module/acpi/parameters + # echo "0x80" > trace_debug_layer + # echo "0x10" > trace_debug_level + # echo "\PPPP.AAAA.TTTT.HHHH" > trace_method_name + # echo "opcode-opcode" > trace_state - "disabled" means this feature is disabled. - Users can enable/disable this debug tracing feature by - "echo string > /sys/module/acpi/parameters/trace_state". - "string" should be one of "enable", "disable" and "1". + Note that all above method tracing facility related module parameters can + be used as the boot parameters, for example: + acpi.trace_debug_layer=0x80 acpi.trace_debug_level=0x10 \ + acpi.trace_method_name=\_SB.LID0._LID acpi.trace_state=opcode-once + +2. Interface descriptions: + + All method tracing functions can be configured via ACPI module + parameters that are accessible at /sys/module/acpi/parameters/: + + trace_method_name + The full path of the AML method that the user wants to trace. + Note that the full path shouldn't contain the trailing "_"s in its + name segments but may contain "\" to form an absolute path. + + trace_debug_layer + The temporary debug_layer used when the tracing feature is enabled. + Using ACPI_EXECUTER (0x80) by default, which is the debug_layer + used to match all "AML tracer" logs. + + trace_debug_level + The temporary debug_level used when the tracing feature is enabled. + Using ACPI_LV_TRACE_POINT (0x10) by default, which is the + debug_level used to match all "AML tracer" logs. + + trace_state + The status of the tracing feature. + Users can enable/disable this debug tracing feature by executing + the following command: + # echo string > /sys/module/acpi/parameters/trace_state + Where "string" should be one of the followings: + "disable" + Disable the method tracing feature. + "enable" + Enable the method tracing feature. + ACPICA debugging messages matching + "trace_debug_layer/trace_debug_level" during any method + execution will be logged. + "method" + Enable the method tracing feature. + ACPICA debugging messages matching + "trace_debug_layer/trace_debug_level" during method execution + of "trace_method_name" will be logged. + "method-once" + Enable the method tracing feature. + ACPICA debugging messages matching + "trace_debug_layer/trace_debug_level" during method execution + of "trace_method_name" will be logged only once. + "opcode" + Enable the method tracing feature. + ACPICA debugging messages matching + "trace_debug_layer/trace_debug_level" during method/opcode + execution of "trace_method_name" will be logged. + "opcode-once" + Enable the method tracing feature. + ACPICA debugging messages matching + "trace_debug_layer/trace_debug_level" during method/opcode + execution of "trace_method_name" will be logged only once. + Note that, the difference between the "enable" and other feature + enabling options are: + 1. When "enable" is specified, since + "trace_debug_layer/trace_debug_level" shall apply to all control + method evaluations, after configuring "trace_state" to "enable", + "trace_method_name" will be reset to NULL. + 2. When "method/opcode" is specified, if + "trace_method_name" is NULL when "trace_state" is configured to + these options, the "trace_debug_layer/trace_debug_level" will + apply to all control method evaluations. -- cgit v1.2.3-59-g8ed1b From ba4539ffc19b090841cd32ffe2c57d937e311857 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:22:56 +0530 Subject: PM / OPP: Update bindings to make opp-hz a 64 bit value With a 32 bit value, the maximum frequency that the bindings can support is ~ 4 GHz. And that might fall short of what newer systems may have. Allow opp-hz to be a 64 bit big-endian value. Suggested-by: Stephen Boyd Suggested-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Acked-by: Rob Herring Signed-off-by: Rafael J. Wysocki --- Documentation/devicetree/bindings/power/opp.txt | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt index 0d5e7c978121..0cb44dc21f97 100644 --- a/Documentation/devicetree/bindings/power/opp.txt +++ b/Documentation/devicetree/bindings/power/opp.txt @@ -88,7 +88,7 @@ This defines voltage-current-frequency combinations along with other related properties. Required properties: -- opp-hz: Frequency in Hz +- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. Optional properties: - opp-microvolt: voltage in micro Volts. @@ -158,20 +158,20 @@ Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. opp-shared; opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; opp01 { - opp-hz = <1100000000>; + opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; opp02 { - opp-hz = <1200000000>; + opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; clock-latency-ns = <290000>; turbo-mode; @@ -237,20 +237,20 @@ independently. */ opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; opp01 { - opp-hz = <1100000000>; + opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; opp02 { - opp-hz = <1200000000>; + opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; opp-microamp = <90000; lock-latency-ns = <290000>; @@ -313,20 +313,20 @@ DVFS state together. opp-shared; opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; opp01 { - opp-hz = <1100000000>; + opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; opp02 { - opp-hz = <1200000000>; + opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; opp-microamp = <90000>; clock-latency-ns = <290000>; @@ -339,20 +339,20 @@ DVFS state together. opp-shared; opp10 { - opp-hz = <1300000000>; + opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1045000 1050000 1055000>; opp-microamp = <95000>; clock-latency-ns = <400000>; opp-suspend; }; opp11 { - opp-hz = <1400000000>; + opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1075000>; opp-microamp = <100000>; clock-latency-ns = <400000>; }; opp12 { - opp-hz = <1500000000>; + opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1010000 1100000 1110000>; opp-microamp = <95000>; clock-latency-ns = <400000>; @@ -379,7 +379,7 @@ Example 4: Handling multiple regulators opp-shared; opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000>, /* Supply 0 */ <960000>, /* Supply 1 */ <960000>; /* Supply 2 */ @@ -392,7 +392,7 @@ Example 4: Handling multiple regulators /* OR */ opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>, /* Supply 0 */ <960000 965000 975000>, /* Supply 1 */ <960000 965000 975000>; /* Supply 2 */ @@ -405,7 +405,7 @@ Example 4: Handling multiple regulators /* OR */ opp00 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>, /* Supply 0 */ <960000 965000 975000>, /* Supply 1 */ <960000 965000 975000>; /* Supply 2 */ @@ -437,12 +437,12 @@ Example 5: Multiple OPP tables opp-shared; opp00 { - opp-hz = <600000000>; + opp-hz = /bits/ 64 <600000000>; ... }; opp01 { - opp-hz = <800000000>; + opp-hz = /bits/ 64 <800000000>; ... }; }; @@ -453,12 +453,12 @@ Example 5: Multiple OPP tables opp-shared; opp10 { - opp-hz = <1000000000>; + opp-hz = /bits/ 64 <1000000000>; ... }; opp11 { - opp-hz = <1100000000>; + opp-hz = /bits/ 64 <1100000000>; ... }; }; -- cgit v1.2.3-59-g8ed1b From 3566c5b277a41e912d15cd583c4604c95bb6b3f8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 22:27:19 +0530 Subject: PM / OPP: Create a directory for opp bindings More platform specific extended opp bindings will follow and it would be easy to manage them with a directory for opp. Lets create that and move the existing opp bindings into it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- Documentation/devicetree/bindings/opp/opp.txt | 465 ++++++++++++++++++++++++ Documentation/devicetree/bindings/power/opp.txt | 465 ------------------------ 2 files changed, 465 insertions(+), 465 deletions(-) create mode 100644 Documentation/devicetree/bindings/opp/opp.txt delete mode 100644 Documentation/devicetree/bindings/power/opp.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt new file mode 100644 index 000000000000..0cb44dc21f97 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -0,0 +1,465 @@ +Generic OPP (Operating Performance Points) Bindings +---------------------------------------------------- + +Devices work at voltage-current-frequency combinations and some implementations +have the liberty of choosing these. These combinations are called Operating +Performance Points aka OPPs. This document defines bindings for these OPPs +applicable across wide range of devices. For illustration purpose, this document +uses CPU as a device. + +This document contain multiple versions of OPP binding and only one of them +should be used per device. + +Binding 1: operating-points +============================ + +This binding only supports voltage-frequency pairs. + +Properties: +- operating-points: An array of 2-tuples items, and each item consists + of frequency and voltage like . + freq: clock frequency in kHz + vol: voltage in microvolt + +Examples: + +cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; +}; + + +Binding 2: operating-points-v2 +============================ + +* Property: operating-points-v2 + +Devices supporting OPPs must set their "operating-points-v2" property with +phandle to a OPP table in their DT node. The OPP core will use this phandle to +find the operating points for the device. + +Devices may want to choose OPP tables at runtime and so can provide a list of +phandles here. But only *one* of them should be chosen at runtime. This must be +accompanied by a corresponding "operating-points-names" property, to uniquely +identify the OPP tables. + +If required, this can be extended for SoC vendor specfic bindings. Such bindings +should be documented as Documentation/devicetree/bindings/power/-opp.txt +and should have a compatible description like: "operating-points-v2-". + +Optional properties: +- operating-points-names: Names of OPP tables (required if multiple OPP + tables are present), to uniquely identify them. The same list must be present + for all the CPUs which are sharing clock/voltage rails and hence the OPP + tables. + +* OPP Table Node + +This describes the OPPs belonging to a device. This node can have following +properties: + +Required properties: +- compatible: Allow OPPs to express their compatibility. It should be: + "operating-points-v2". + +- OPP nodes: One or more OPP nodes describing voltage-current-frequency + combinations. Their name isn't significant but their phandle can be used to + reference an OPP. + +Optional properties: +- opp-shared: Indicates that device nodes using this OPP Table Node's phandle + switch their DVFS state together, i.e. they share clock/voltage/current lines. + Missing property means devices have independent clock/voltage/current lines, + but they share OPP tables. + +- status: Marks the OPP table enabled/disabled. + + +* OPP Node + +This defines voltage-current-frequency combinations along with other related +properties. + +Required properties: +- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. + +Optional properties: +- opp-microvolt: voltage in micro Volts. + + A single regulator's voltage is specified with an array of size one or three. + Single entry is for target voltage and three entries are for + voltages. + + Entries for multiple regulators must be present in the same order as + regulators are specified in device's DT node. + +- opp-microamp: The maximum current drawn by the device in microamperes + considering system specific parameters (such as transients, process, aging, + maximum operating temperature range etc.) as necessary. This may be used to + set the most efficient regulator operating mode. + + Should only be set if opp-microvolt is set for the OPP. + + Entries for multiple regulators must be present in the same order as + regulators are specified in device's DT node. If this property isn't required + for few regulators, then this should be marked as zero for them. If it isn't + required for any regulator, then this property need not be present. + +- clock-latency-ns: Specifies the maximum possible transition latency (in + nanoseconds) for switching to this OPP from any other OPP. + +- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is + available on some platforms, where the device can run over its operating + frequency for a short duration of time limited by the device's power, current + and thermal limits. + +- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in + the table should have this. + +- status: Marks the node enabled/disabled. + +Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000 975000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp01 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <980000 1000000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp02 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; +}; + +Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states +independently. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,krait"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@1 { + compatible = "qcom,krait"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@2 { + compatible = "qcom,krait"; + reg = <2>; + next-level-cache = <&L2>; + clocks = <&clk_controller 2>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply2>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@3 { + compatible = "qcom,krait"; + reg = <3>; + next-level-cache = <&L2>; + clocks = <&clk_controller 3>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply3>; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + cpu_opp_table: opp_table { + compatible = "operating-points-v2"; + + /* + * Missing opp-shared property means CPUs switch DVFS states + * independently. + */ + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000 975000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp01 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <980000 1000000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp02 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000; + lock-latency-ns = <290000>; + turbo-mode; + }; + }; +}; + +Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch +DVFS state together. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@1 { + compatible = "arm,cortex-a7"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@100 { + compatible = "arm,cortex-a15"; + reg = <100>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + + cpu@101 { + compatible = "arm,cortex-a15"; + reg = <101>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + }; + + cluster0_opp: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000 975000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp01 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <980000 1000000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp02 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; + + cluster1_opp: opp_table1 { + compatible = "operating-points-v2"; + opp-shared; + + opp10 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1045000 1050000 1055000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + opp-suspend; + }; + opp11 { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1075000>; + opp-microamp = <100000>; + clock-latency-ns = <400000>; + }; + opp12 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1010000 1100000 1110000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + turbo-mode; + }; + }; +}; + +Example 4: Handling multiple regulators + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000>, /* Supply 0 */ + <960000>, /* Supply 1 */ + <960000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000 975000 985000>, /* Supply 0 */ + <960000 965000 975000>, /* Supply 1 */ + <960000 965000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000 975000 985000>, /* Supply 0 */ + <960000 965000 975000>, /* Supply 1 */ + <960000 965000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <0>, /* Supply 1 doesn't need this */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + }; +}; + +Example 5: Multiple OPP tables + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + cpu-supply = <&cpu_supply> + operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>; + operating-points-names = "slow", "fast"; + }; + }; + + cpu0_opp_table_slow: opp_table_slow { + compatible = "operating-points-v2"; + status = "okay"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <600000000>; + ... + }; + + opp01 { + opp-hz = /bits/ 64 <800000000>; + ... + }; + }; + + cpu0_opp_table_fast: opp_table_fast { + compatible = "operating-points-v2"; + status = "okay"; + opp-shared; + + opp10 { + opp-hz = /bits/ 64 <1000000000>; + ... + }; + + opp11 { + opp-hz = /bits/ 64 <1100000000>; + ... + }; + }; +}; diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt deleted file mode 100644 index 0cb44dc21f97..000000000000 --- a/Documentation/devicetree/bindings/power/opp.txt +++ /dev/null @@ -1,465 +0,0 @@ -Generic OPP (Operating Performance Points) Bindings ----------------------------------------------------- - -Devices work at voltage-current-frequency combinations and some implementations -have the liberty of choosing these. These combinations are called Operating -Performance Points aka OPPs. This document defines bindings for these OPPs -applicable across wide range of devices. For illustration purpose, this document -uses CPU as a device. - -This document contain multiple versions of OPP binding and only one of them -should be used per device. - -Binding 1: operating-points -============================ - -This binding only supports voltage-frequency pairs. - -Properties: -- operating-points: An array of 2-tuples items, and each item consists - of frequency and voltage like . - freq: clock frequency in kHz - vol: voltage in microvolt - -Examples: - -cpu@0 { - compatible = "arm,cortex-a9"; - reg = <0>; - next-level-cache = <&L2>; - operating-points = < - /* kHz uV */ - 792000 1100000 - 396000 950000 - 198000 850000 - >; -}; - - -Binding 2: operating-points-v2 -============================ - -* Property: operating-points-v2 - -Devices supporting OPPs must set their "operating-points-v2" property with -phandle to a OPP table in their DT node. The OPP core will use this phandle to -find the operating points for the device. - -Devices may want to choose OPP tables at runtime and so can provide a list of -phandles here. But only *one* of them should be chosen at runtime. This must be -accompanied by a corresponding "operating-points-names" property, to uniquely -identify the OPP tables. - -If required, this can be extended for SoC vendor specfic bindings. Such bindings -should be documented as Documentation/devicetree/bindings/power/-opp.txt -and should have a compatible description like: "operating-points-v2-". - -Optional properties: -- operating-points-names: Names of OPP tables (required if multiple OPP - tables are present), to uniquely identify them. The same list must be present - for all the CPUs which are sharing clock/voltage rails and hence the OPP - tables. - -* OPP Table Node - -This describes the OPPs belonging to a device. This node can have following -properties: - -Required properties: -- compatible: Allow OPPs to express their compatibility. It should be: - "operating-points-v2". - -- OPP nodes: One or more OPP nodes describing voltage-current-frequency - combinations. Their name isn't significant but their phandle can be used to - reference an OPP. - -Optional properties: -- opp-shared: Indicates that device nodes using this OPP Table Node's phandle - switch their DVFS state together, i.e. they share clock/voltage/current lines. - Missing property means devices have independent clock/voltage/current lines, - but they share OPP tables. - -- status: Marks the OPP table enabled/disabled. - - -* OPP Node - -This defines voltage-current-frequency combinations along with other related -properties. - -Required properties: -- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. - -Optional properties: -- opp-microvolt: voltage in micro Volts. - - A single regulator's voltage is specified with an array of size one or three. - Single entry is for target voltage and three entries are for - voltages. - - Entries for multiple regulators must be present in the same order as - regulators are specified in device's DT node. - -- opp-microamp: The maximum current drawn by the device in microamperes - considering system specific parameters (such as transients, process, aging, - maximum operating temperature range etc.) as necessary. This may be used to - set the most efficient regulator operating mode. - - Should only be set if opp-microvolt is set for the OPP. - - Entries for multiple regulators must be present in the same order as - regulators are specified in device's DT node. If this property isn't required - for few regulators, then this should be marked as zero for them. If it isn't - required for any regulator, then this property need not be present. - -- clock-latency-ns: Specifies the maximum possible transition latency (in - nanoseconds) for switching to this OPP from any other OPP. - -- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is - available on some platforms, where the device can run over its operating - frequency for a short duration of time limited by the device's power, current - and thermal limits. - -- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in - the table should have this. - -- status: Marks the node enabled/disabled. - -Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a9"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu0_opp_table>; - }; - - cpu@1 { - compatible = "arm,cortex-a9"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu0_opp_table>; - }; - }; - - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000 975000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp01 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <980000 1000000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp02 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - clock-latency-ns = <290000>; - turbo-mode; - }; - }; -}; - -Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states -independently. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "qcom,krait"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@1 { - compatible = "qcom,krait"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@2 { - compatible = "qcom,krait"; - reg = <2>; - next-level-cache = <&L2>; - clocks = <&clk_controller 2>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply2>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@3 { - compatible = "qcom,krait"; - reg = <3>; - next-level-cache = <&L2>; - clocks = <&clk_controller 3>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply3>; - operating-points-v2 = <&cpu_opp_table>; - }; - }; - - cpu_opp_table: opp_table { - compatible = "operating-points-v2"; - - /* - * Missing opp-shared property means CPUs switch DVFS states - * independently. - */ - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000 975000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp01 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <980000 1000000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp02 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - opp-microamp = <90000; - lock-latency-ns = <290000>; - turbo-mode; - }; - }; -}; - -Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch -DVFS state together. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a7"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cluster0_opp>; - }; - - cpu@1 { - compatible = "arm,cortex-a7"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cluster0_opp>; - }; - - cpu@100 { - compatible = "arm,cortex-a15"; - reg = <100>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cluster1_opp>; - }; - - cpu@101 { - compatible = "arm,cortex-a15"; - reg = <101>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cluster1_opp>; - }; - }; - - cluster0_opp: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000 975000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp01 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <980000 1000000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp02 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - opp-microamp = <90000>; - clock-latency-ns = <290000>; - turbo-mode; - }; - }; - - cluster1_opp: opp_table1 { - compatible = "operating-points-v2"; - opp-shared; - - opp10 { - opp-hz = /bits/ 64 <1300000000>; - opp-microvolt = <1045000 1050000 1055000>; - opp-microamp = <95000>; - clock-latency-ns = <400000>; - opp-suspend; - }; - opp11 { - opp-hz = /bits/ 64 <1400000000>; - opp-microvolt = <1075000>; - opp-microamp = <100000>; - clock-latency-ns = <400000>; - }; - opp12 { - opp-hz = /bits/ 64 <1500000000>; - opp-microvolt = <1010000 1100000 1110000>; - opp-microamp = <95000>; - clock-latency-ns = <400000>; - turbo-mode; - }; - }; -}; - -Example 4: Handling multiple regulators - -/ { - cpus { - cpu@0 { - compatible = "arm,cortex-a7"; - ... - - cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>; - operating-points-v2 = <&cpu0_opp_table>; - }; - }; - - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000>, /* Supply 0 */ - <960000>, /* Supply 1 */ - <960000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <70000>, /* Supply 1 */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - - /* OR */ - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000 975000 985000>, /* Supply 0 */ - <960000 965000 975000>, /* Supply 1 */ - <960000 965000 975000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <70000>, /* Supply 1 */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - - /* OR */ - - opp00 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000 975000 985000>, /* Supply 0 */ - <960000 965000 975000>, /* Supply 1 */ - <960000 965000 975000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <0>, /* Supply 1 doesn't need this */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - }; -}; - -Example 5: Multiple OPP tables - -/ { - cpus { - cpu@0 { - compatible = "arm,cortex-a7"; - ... - - cpu-supply = <&cpu_supply> - operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>; - operating-points-names = "slow", "fast"; - }; - }; - - cpu0_opp_table_slow: opp_table_slow { - compatible = "operating-points-v2"; - status = "okay"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <600000000>; - ... - }; - - opp01 { - opp-hz = /bits/ 64 <800000000>; - ... - }; - }; - - cpu0_opp_table_fast: opp_table_fast { - compatible = "operating-points-v2"; - status = "okay"; - opp-shared; - - opp10 { - opp-hz = /bits/ 64 <1000000000>; - ... - }; - - opp11 { - opp-hz = /bits/ 64 <1100000000>; - ... - }; - }; -}; -- cgit v1.2.3-59-g8ed1b From fe2edd9cbb7763c68350e267f8060113ce9848fe Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 01:02:36 +0200 Subject: Documentation: dt: atmel-at91: add clocks to system timer, rstc and shdwc The system timer (at91rm9200), the reset controller and the shutdown controller need an input clock. This is the slow clock and they will not function without it. Also fix the shutdown controller example. Acked-By: Sebastian Reichel Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8cbfa08..209710cdf3aa 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -50,6 +50,7 @@ System Timer (ST) required properties: - reg: Should contain registers location and length - interrupts: Should contain interrupt for the ST which is the IRQ line shared across all System Controller members. +- clocks: phandle to input clock. Its subnodes can be: - watchdog: compatible should be "atmel,at91rm9200-wdt" @@ -89,12 +90,14 @@ RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". can be "at91sam9260" or "at91sam9g45" - reg: Should contain registers location and length +- clocks: phandle to input clock. Example: rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; }; RAMC SDRAM/DDR Controller required properties: @@ -117,6 +120,7 @@ required properties: - compatible: Should be "atmel,-shdwc". can be "at91sam9260", "at91sam9rl" or "at91sam9x5". - reg: Should contain registers location and length +- clocks: phandle to input clock. optional properties: - atmel,wakeup-mode: String, operation mode of the wakeup mode. @@ -135,9 +139,10 @@ optional at91sam9x5 properties: Example: - rstc@fffffd00 { - compatible = "atmel,at91sam9260-rstc"; - reg = <0xfffffd00 0x10>; + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; }; Special Function Registers (SFR) -- cgit v1.2.3-59-g8ed1b From 04600560a01270ef3a9bdeaeeebcfa23df81a327 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Jul 2015 02:11:14 +0200 Subject: Documentation: dt: atmel-at91: add slow clock to tcb The timer counters need the slow clock. It is required as they will not function without it. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 209710cdf3aa..dc2d0f06d058 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -62,7 +62,7 @@ TC/TCLIB Timer required properties: Note that you can specify several interrupt cells if the TC block has one interrupt per channel. - clock-names: tuple listing input clock names. - Required elements: "t0_clk" + Required elements: "t0_clk", "slow_clk" Optional elements: "t1_clk", "t2_clk" - clocks: phandles to input clocks. -- cgit v1.2.3-59-g8ed1b From d79e327aa58505fe693ef4a5157cc61eb968be02 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 00:43:07 +0200 Subject: Documentation: watchdog: at91sam9_wdt: add clocks property The watchdog has an input clock, the slow clock. It is required as it will not function without it. Reviewed-by: Guenter Roeck Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt index a4d869744f59..86fa6de1019b 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt @@ -6,6 +6,7 @@ Required properties: - compatible: must be "atmel,at91sam9260-wdt". - reg: physical base address of the controller and length of memory mapped region. +- clocks: phandle to input clock. Optional properties: - timeout-sec: contains the watchdog timeout in seconds. @@ -39,6 +40,7 @@ Example: compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; timeout-sec = <15>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; -- cgit v1.2.3-59-g8ed1b From e1162cba4e44bd97d7e690bf664afc71a85b1413 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 00:49:44 +0200 Subject: Documentation: dt: rtc: at91rm9200: add clocks property The RTC needs an input clock, it is the slow clock. It is required as it will not function without it. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt index 34c1505774bf..5d3791e789c6 100644 --- a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt @@ -5,6 +5,7 @@ Required properties: - reg: physical base address of the controller and length of memory mapped region. - interrupts: rtc alarm/event interrupt +- clocks: phandle to input clock. Example: @@ -12,4 +13,5 @@ rtc@fffffe00 { compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffe00 0x100>; interrupts = <1 4 7>; + clocks = <&clk32k>; }; -- cgit v1.2.3-59-g8ed1b From 253508cadddbb676b05f03ada93d0f986df107f5 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Fri, 26 Jun 2015 12:05:39 -0400 Subject: fix typo in Documentation/SubmittingPatches This adds a missing letter in Documentation/SubmittingPatches. Signed-off-by: Nik Nyby Signed-off-by: Jiri Kosina --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 27e7e5edeca8..e2d29a749ff4 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -291,7 +291,7 @@ sending him e-mail. If you have a patch that fixes an exploitable security bug, send that patch to security@kernel.org. For severe bugs, a short embargo may be considered -to allow distrbutors to get the patch out to users; in such cases, +to allow distributors to get the patch out to users; in such cases, obviously, the patch should not be sent to any public lists. Patches that fix a severe bug in a released kernel should be directed -- cgit v1.2.3-59-g8ed1b From 831527b7304d06ea24afd2d01956dad06cd34043 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 6 Jul 2015 10:28:41 -0400 Subject: pcmcia: Fix typo in locking documentation This fixes a typo in the docs: "devie" -> "device". Signed-off-by: Nik Nyby Signed-off-by: Jiri Kosina --- Documentation/pcmcia/locking.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/pcmcia/locking.txt b/Documentation/pcmcia/locking.txt index 68f622bc4064..b2c9b478906b 100644 --- a/Documentation/pcmcia/locking.txt +++ b/Documentation/pcmcia/locking.txt @@ -96,7 +96,7 @@ or single-use fields not mentioned): 3. Per PCMCIA-device Data: -------------------------- -The "main" struct pcmcia_devie is protected as follows (read-only fields +The "main" struct pcmcia_device is protected as follows (read-only fields or single-use fields not mentioned): -- cgit v1.2.3-59-g8ed1b From 6ade97724fb571338a0f82ecaac5bced2f43f042 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Sat, 18 Jul 2015 14:31:40 +0200 Subject: Doc: fix trivial typo in SubmittingPatches This patch changes the tense of a verb in SubmittingPatches to ensure grammatical validity of the containing sentence. Signed-off-by: Benjamin Herr Signed-off-by: Jiri Kosina --- Documentation/SubmittingPatches | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index e2d29a749ff4..d3f56137b498 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -90,7 +90,7 @@ patch. Make sure your patch does not include any extra files which do not belong in a patch submission. Make sure to review your patch -after- -generated it with diff(1), to ensure accuracy. +generating it with diff(1), to ensure accuracy. If your changes produce a lot of deltas, you need to split them into individual patches which modify things in logical stages; see section -- cgit v1.2.3-59-g8ed1b From 0d850e7cdc69962e85abd7f7dcd2359f293f835a Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Fri, 7 Aug 2015 15:19:49 +0800 Subject: spi: Mediatek: Document devicetree bindings for spi bus Signed-off-by: Leilk Liu Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-mt65xx.txt | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-mt65xx.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt new file mode 100644 index 000000000000..dcefc438272f --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt @@ -0,0 +1,51 @@ +Binding for MTK SPI controller + +Required properties: +- compatible: should be one of the following. + - mediatek,mt8173-spi: for mt8173 platforms + - mediatek,mt8135-spi: for mt8135 platforms + - mediatek,mt6589-spi: for mt6589 platforms + +- #address-cells: should be 1. + +- #size-cells: should be 0. + +- reg: Address and length of the register set for the device + +- interrupts: Should contain spi interrupt + +- clocks: phandles to input clocks. + The first should be <&topckgen CLK_TOP_SPI_SEL>. + The second should be one of the following. + - <&clk26m>: specify parent clock 26MHZ. + - <&topckgen CLK_TOP_SYSPLL3_D2>: specify parent clock 109MHZ. + It's the default one. + - <&topckgen CLK_TOP_SYSPLL4_D2>: specify parent clock 78MHZ. + - <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ. + - <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ. + +- clock-names: shall be "spi-clk" for the controller clock, and + "parent-clk" for the parent clock. + +Optional properties: +- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi + controller used, this value should be 0~3, only required for MT8173. + 0: specify GPIO69,70,71,72 for spi pins. + 1: specify GPIO102,103,104,105 for spi pins. + 2: specify GPIO128,129,130,131 for spi pins. + 3: specify GPIO5,6,7,8 for spi pins. + +Example: + +- SoC Specific Portion: +spi: spi@1100a000 { + compatible = "mediatek,mt8173-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x1100a000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_SPI_SEL>, <&topckgen CLK_TOP_SYSPLL3_D2>; + clock-names = "spi-clk", "parent-clk"; + mediatek,pad-select = <0>; + status = "disabled"; +}; -- cgit v1.2.3-59-g8ed1b From 5b55f52d13d3643e7d62ad2f37f55d8e7f5f0c8e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 18:31:14 +0530 Subject: Documentation/fb: add documentation for sm712fb Create the documentation for SM712. Mention all the supported modes and how to use. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- Documentation/fb/sm712fb.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/fb/sm712fb.txt (limited to 'Documentation') diff --git a/Documentation/fb/sm712fb.txt b/Documentation/fb/sm712fb.txt new file mode 100644 index 000000000000..c388442edf51 --- /dev/null +++ b/Documentation/fb/sm712fb.txt @@ -0,0 +1,31 @@ +What is sm712fb? +================= + +This is a graphics framebuffer driver for Silicon Motion SM712 based processors. + +How to use it? +============== + +Switching modes is done using the video=sm712fb:... boot parameter. + +If you want, for example, enable a resolution of 1280x1024x24bpp you should +pass to the kernel this command line: "video=sm712fb:0x31B". + +You should not compile-in vesafb. + +Currently supported video modes are: + +[Graphic modes] + +bpp | 640x480 800x600 1024x768 1280x1024 +----+-------------------------------------------- + 8 | 0x301 0x303 0x305 0x307 + 16 | 0x311 0x314 0x317 0x31A + 24 | 0x312 0x315 0x318 0x31B + +Missing Features +================ +(alias TODO list) + + * 2D acceleratrion + * dual-head support -- cgit v1.2.3-59-g8ed1b From 3fc147e9156f6c176e5543c59d31182252f14933 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 4 Aug 2015 21:37:01 +0200 Subject: PM / AVS: rockchip-io: add io selectors and supplies for rk3368 This adds the necessary data for handling io voltage domains on the rk3368. As interesting tidbit, the rk3368 contains two separate iodomain areas. One in the regular General Register Files (GRF) and one in PMUGRF in the pmu power domain. Signed-off-by: Heiko Stuebner Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- .../bindings/power/rockchip-io-domain.txt | 14 +++++ drivers/power/avs/rockchip-io-domain.c | 59 ++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt index 8b70db103ca7..b8627e763dba 100644 --- a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt +++ b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt @@ -33,6 +33,8 @@ Required properties: - compatible: should be one of: - "rockchip,rk3188-io-voltage-domain" for rk3188 - "rockchip,rk3288-io-voltage-domain" for rk3288 + - "rockchip,rk3368-io-voltage-domain" for rk3368 + - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains - rockchip,grf: phandle to the syscon managing the "general register files" @@ -64,6 +66,18 @@ Possible supplies for rk3288: - sdcard-supply: The supply connected to SDMMC0_VDD. - wifi-supply: The supply connected to APIO3_VDD. Also known as SDIO0. +Possible supplies for rk3368: +- audio-supply: The supply connected to APIO3_VDD. +- dvp-supply: The supply connected to DVPIO_VDD. +- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC +- gpio30-supply: The supply connected to APIO1_VDD. +- gpio1830 The supply connected to APIO4_VDD. +- sdcard-supply: The supply connected to SDMMC0_VDD. +- wifi-supply: The supply connected to APIO2_VDD. Also known as SDIO0. + +Possible supplies for rk3368 pmu-domains: +- pmu-supply: The supply connected to PMUIO_VDD. +- vop-supply: The supply connected to LCDC_VDD. Example: diff --git a/drivers/power/avs/rockchip-io-domain.c b/drivers/power/avs/rockchip-io-domain.c index 3ae35d0590d2..2e300028f0f7 100644 --- a/drivers/power/avs/rockchip-io-domain.c +++ b/drivers/power/avs/rockchip-io-domain.c @@ -43,6 +43,10 @@ #define RK3288_SOC_CON2_FLASH0 BIT(7) #define RK3288_SOC_FLASH_SUPPLY_NUM 2 +#define RK3368_SOC_CON15 0x43c +#define RK3368_SOC_CON15_FLASH0 BIT(14) +#define RK3368_SOC_FLASH_SUPPLY_NUM 2 + struct rockchip_iodomain; /** @@ -158,6 +162,25 @@ static void rk3288_iodomain_init(struct rockchip_iodomain *iod) dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); } +static void rk3368_iodomain_init(struct rockchip_iodomain *iod) +{ + int ret; + u32 val; + + /* if no flash supply we should leave things alone */ + if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg) + return; + + /* + * set flash0 iodomain to also use this framework + * instead of a special gpio. + */ + val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16); + ret = regmap_write(iod->grf, RK3368_SOC_CON15, val); + if (ret < 0) + dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); +} + /* * On the rk3188 the io-domains are handled by a shared register with the * lower 8 bits being still being continuing drive-strength settings. @@ -201,6 +224,34 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { .init = rk3288_iodomain_init, }; +static const struct rockchip_iodomain_soc_data soc_data_rk3368 = { + .grf_offset = 0x900, + .supply_names = { + NULL, /* reserved */ + "dvp", /* DVPIO_VDD */ + "flash0", /* FLASH0_VDD (emmc) */ + "wifi", /* APIO2_VDD (sdio0) */ + NULL, + "audio", /* APIO3_VDD */ + "sdcard", /* SDMMC0_VDD (sdmmc) */ + "gpio30", /* APIO1_VDD */ + "gpio1830", /* APIO4_VDD (gpujtag) */ + }, + .init = rk3368_iodomain_init, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = { + .grf_offset = 0x100, + .supply_names = { + NULL, + NULL, + NULL, + NULL, + "pmu", /*PMU IO domain*/ + "vop", /*LCDC IO domain*/ + }, +}; + static const struct of_device_id rockchip_iodomain_match[] = { { .compatible = "rockchip,rk3188-io-voltage-domain", @@ -210,6 +261,14 @@ static const struct of_device_id rockchip_iodomain_match[] = { .compatible = "rockchip,rk3288-io-voltage-domain", .data = (void *)&soc_data_rk3288 }, + { + .compatible = "rockchip,rk3368-io-voltage-domain", + .data = (void *)&soc_data_rk3368 + }, + { + .compatible = "rockchip,rk3368-pmu-io-voltage-domain", + .data = (void *)&soc_data_rk3368_pmu + }, { /* sentinel */ }, }; -- cgit v1.2.3-59-g8ed1b From 378abcdf3297613f6712343ce3a79b7d6abdf955 Mon Sep 17 00:00:00 2001 From: Alexandru M Stan Date: Wed, 29 Jul 2015 20:57:20 +0200 Subject: ARM: dts: rockchip: add veyron-minnie board Also known as the Asus Chromebook Flip. Signed-off-by: Alexandru M Stan Signed-off-by: Heiko Stuebner Reviewed-by: Douglas Anderson --- Documentation/devicetree/bindings/arm/rockchip.txt | 7 + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/rk3288-veyron-minnie.dts | 226 +++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 arch/arm/boot/dts/rk3288-veyron-minnie.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index c7411cc53533..af58cd74aeff 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -38,6 +38,13 @@ Rockchip platforms device tree bindings "google,veyron-jerry-rev3", "google,veyron-jerry", "google,veyron", "rockchip,rk3288"; +- Google Minnie (Asus Chromebook Flip C100P): + Required root node properties: + - compatible = "google,veyron-minnie-rev4", "google,veyron-minnie-rev3", + "google,veyron-minnie-rev2", "google,veyron-minnie-rev1", + "google,veyron-minnie-rev0", "google,veyron-minnie", + "google,veyron", "rockchip,rk3288"; + - Google Pinky (dev-board): Required root node properties: - compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 7017d8e3f4f5..7805a6541a38 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -491,6 +491,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-firefly.dtb \ rk3288-r89.dtb \ rk3288-veyron-jerry.dtb \ + rk3288-veyron-minnie.dtb \ rk3288-veyron-pinky.dtb \ rk3288-veyron-speedy.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts new file mode 100644 index 000000000000..0e30bd6bf92b --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts @@ -0,0 +1,226 @@ +/* + * Google Veyron Minnie Rev 0+ board device tree source + * + * Copyright 2015 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3288-veyron-chromebook.dtsi" + +/ { + model = "Google Minnie"; + compatible = "google,veyron-minnie-rev4", "google,veyron-minnie-rev3", + "google,veyron-minnie-rev2", "google,veyron-minnie-rev1", + "google,veyron-minnie-rev0", "google,veyron-minnie", + "google,veyron", "rockchip,rk3288"; + + backlight_regulator: backlight-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_pwr_en>; + regulator-name = "backlight_regulator"; + vin-supply = <&vcc33_sys>; + startup-delay-us = <15000>; + }; + + panel_regulator: panel-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_h>; + regulator-name = "panel_regulator"; + vin-supply = <&vcc33_sys>; + }; + + vcc18_lcd: vcc18-lcd { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&avdd_1v8_disp_en>; + regulator-name = "vcc18_lcd"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc18_wl>; + }; +}; + +&gpio_keys { + pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>; + + volum_down { + label = "Volum_down"; + gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <100>; + }; + + volum_up { + label = "Volum_up"; + gpios = <&gpio5 10 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <100>; + }; +}; + +&i2c_tunnel { + battery: bq27500@55 { + compatible = "ti,bq27500"; + reg = <0x55>; + }; +}; + +&i2c3 { + status = "okay"; + + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; +}; + +&rk808 { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>; + + regulators { + vcc33_touch: LDO_REG2 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc33_touch"; + regulator-suspend-mem-disabled; + }; + + vcc5v_touch: SWITCH_REG2 { + regulator-name = "vcc5v_touch"; + regulator-suspend-mem-disabled; + }; + }; +}; + +&sdmmc { + disable-wp; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio + &sdmmc_bus4>; +}; + +&vcc_5v { + enable-active-high; + gpio = <&gpio7 21 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&drv_5v>; +}; + +&vcc50_hdmi { + enable-active-high; + gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc50_hdmi_en>; +}; + +&pinctrl { + backlight { + bl_pwr_en: bl_pwr_en { + rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + buck-5v { + drv_5v: drv-5v { + rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + buttons { + volum_down_l: volum-down-l { + rockchip,pins = <5 11 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + volum_up_l: volum-up-l { + rockchip,pins = <5 10 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + hdmi { + vcc50_hdmi_en: vcc50-hdmi-en { + rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lcd { + lcd_enable_h: lcd-en { + rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + avdd_1v8_disp_en: avdd-1v8-disp-en { + rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + dvs_1: dvs-1 { + rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + dvs_2: dvs-2 { + rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + prochot { + gpio_prochot: gpio-prochot { + rockchip,pins = <2 8 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + touchscreen { + touch_int: touch-int { + rockchip,pins = <2 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + touch_rst: touch-rst { + rockchip,pins = <2 15 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From aab978772a4fbe71d8231cb58d0989737db27a36 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 4 Aug 2015 17:20:08 +0300 Subject: DocBook: Add initial documentation for IIO This is intended to help developers faster find their way inside the Industrial I/O core and reduce time spent on IIO drivers development. Signed-off-by: Daniel Baluta Acked-by: Crt Mori Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/iio.tmpl | 697 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 698 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/iio.tmpl (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b6a6a2e0dd3b..9e086067b4ae 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -15,7 +15,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml drm.xml media_api.xml w1.xml \ - writing_musb_glue_layer.xml crypto-API.xml + writing_musb_glue_layer.xml crypto-API.xml iio.xml include Documentation/DocBook/media/Makefile diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl new file mode 100644 index 000000000000..06bb53de5a47 --- /dev/null +++ b/Documentation/DocBook/iio.tmpl @@ -0,0 +1,697 @@ + + + + + + Industrial I/O driver developer's guide + + + + Daniel + Baluta + +
+ daniel.baluta@intel.com +
+
+
+
+ + + 2015 + Intel Corporation + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2. + + +
+ + + + + Introduction + + The main purpose of the Industrial I/O subsystem (IIO) is to provide + support for devices that in some sense perform either analog-to-digital + conversion (ADC) or digital-to-analog conversion (DAC) or both. The aim + is to fill the gap between the somewhat similar hwmon and input + subsystems. + Hwmon is directed at low sample rate sensors used to monitor and + control the system itself, like fan speed control or temperature + measurement. Input is, as its name suggests, focused on human interaction + input devices (keyboard, mouse, touchscreen). In some cases there is + considerable overlap between these and IIO. + + + Devices that fall into this category include: + + + analog to digital converters (ADCs) + + + accelerometers + + + capacitance to digital converters (CDCs) + + + digital to analog converters (DACs) + + + gyroscopes + + + inertial measurement units (IMUs) + + + color and light sensors + + + magnetometers + + + pressure sensors + + + proximity sensors + + + temperature sensors + + + Usually these sensors are connected via SPI or I2C. A common use case of the + sensors devices is to have combined functionality (e.g. light plus proximity + sensor). + + + + Industrial I/O core + + The Industrial I/O core offers: + + + a unified framework for writing drivers for many different types of + embedded sensors. + + + a standard interface to user space applications manipulating sensors. + + + The implementation can be found under + drivers/iio/industrialio-* + + + Industrial I/O devices + +!Finclude/linux/iio/iio.h iio_dev +!Fdrivers/iio/industrialio-core.c iio_device_alloc +!Fdrivers/iio/industrialio-core.c iio_device_free +!Fdrivers/iio/industrialio-core.c iio_device_register +!Fdrivers/iio/industrialio-core.c iio_device_unregister + + + An IIO device usually corresponds to a single hardware sensor and it + provides all the information needed by a driver handling a device. + Let's first have a look at the functionality embedded in an IIO + device then we will show how a device driver makes use of an IIO + device. + + + There are two ways for a user space application to interact + with an IIO driver. + + + /sys/bus/iio/iio:deviceX/, this + represents a hardware sensor and groups together the data + channels of the same chip. + + + /dev/iio:deviceX, character device node + interface used for buffered data transfer and for events information + retrieval. + + + + A typical IIO driver will register itself as an I2C or SPI driver and will + create two routines, probe and remove + . At probe: + + call iio_device_alloc, which allocates memory + for an IIO device. + + initialize IIO device fields with driver specific information + (e.g. device name, device channels). + + call iio_device_register, this registers the + device with the IIO core. After this call the device is ready to accept + requests from user space applications. + + + At remove, we free the resources allocated in + probe in reverse order: + + iio_device_unregister, unregister the device + from the IIO core. + + iio_device_free, free the memory allocated + for the IIO device. + + + + IIO device sysfs interface + + Attributes are sysfs files used to expose chip info and also allowing + applications to set various configuration parameters. For device + with index X, attributes can be found under + /sys/bus/iio/iio:deviceX/ directory. + Common attributes are: + + name, description of the physical + chip. + + dev, shows the major:minor pair + associated with /dev/iio:deviceX node. + + sampling_frequency_available, + available discrete set of sampling frequency values for + device. + + + Available standard attributes for IIO devices are described in the + Documentation/ABI/testing/sysfs-bus-iio file + in the Linux kernel sources. + + + IIO device channels +!Finclude/linux/iio/iio.h iio_chan_spec structure. + + An IIO device channel is a representation of a data channel. An + IIO device can have one or multiple channels. For example: + + + a thermometer sensor has one channel representing the + temperature measurement. + + + a light sensor with two channels indicating the measurements in + the visible and infrared spectrum. + + + an accelerometer can have up to 3 channels representing + acceleration on X, Y and Z axes. + + + An IIO channel is described by the struct iio_chan_spec + . A thermometer driver for the temperature sensor in the + example above would have to describe its channel as follows: + + static const struct iio_chan_spec temp_channel[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, + }; + + + Channel sysfs attributes exposed to userspace are specified in + the form of bitmasks. Depending on their + shared info, attributes can be set in one of the following masks: + + info_mask_separate, attributes will + be specific to this channel + info_mask_shared_by_type, + attributes are shared by all channels of the same type + info_mask_shared_by_dir, attributes + are shared by all channels of the same direction + info_mask_shared_by_all, + attributes are shared by all channels + + When there are multiple data channels per channel type we have two + ways to distinguish between them: + + set .modified field of + iio_chan_spec to 1. Modifiers are specified using + .channel2 field of the same + iio_chan_spec structure and are used to indicate a + physically unique characteristic of the channel such as its direction + or spectral response. For example, a light sensor can have two channels, + one for infrared light and one for both infrared and visible light. + + set .indexed field of + iio_chan_spec to 1. In this case the channel is + simply another instance with an index specified by the + .channel field. + + + Here is how we can make use of the channel's modifiers: + + static const struct iio_chan_spec light_channels[] = { + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + + } + + This channel's definition will generate two separate sysfs files + for raw data retrieval: + + + /sys/bus/iio/iio:deviceX/in_intensity_ir_raw + + + /sys/bus/iio/iio:deviceX/in_intensity_both_raw + + + one file for processed data: + + + /sys/bus/iio/iio:deviceX/in_illuminance_input + + + + and one shared sysfs file for sampling frequency: + + + /sys/bus/iio/iio:deviceX/sampling_frequency. + + + + + + Here is how we can make use of the channel's indexing: + + static const struct iio_chan_spec light_channels[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + } + + This will generate two separate attributes files for raw data + retrieval: + + + /sys/bus/iio/devices/iio:deviceX/in_voltage0_raw, + representing voltage measurement for channel 0. + + + /sys/bus/iio/devices/iio:deviceX/in_voltage1_raw, + representing voltage measurement for channel 1. + + + + + + + Industrial I/O buffers +!Finclude/linux/iio/buffer.h iio_buffer +!Edrivers/iio/industrialio-buffer.c + + + The Industrial I/O core offers a way for continuous data capture + based on a trigger source. Multiple data channels can be read at once + from /dev/iio:deviceX character device node, + thus reducing the CPU load. + + + + IIO buffer sysfs interface + + An IIO buffer has an associated attributes directory under + /sys/bus/iio/iio:deviceX/buffer/. Here are the existing + attributes: + + + length, the total number of data samples + (capacity) that can be stored by the buffer. + + + enable, activate buffer capture. + + + + + + IIO buffer setup + The meta information associated with a channel reading + placed in a buffer is called a scan element . + The important bits configuring scan elements are exposed to + userspace applications via the + /sys/bus/iio/iio:deviceX/scan_elements/ directory. This + file contains attributes of the following form: + + enable, used for enabling a channel. + If and only if its attribute is non zero, then a triggered capture + will contain data samples for this channel. + + type, description of the scan element + data storage within the buffer and hence the form in which it is + read from user space. Format is + [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] . + + be or le, specifies + big or little endian. + + + s or u, specifies if + signed (2's complement) or unsigned. + + bits, is the number of valid data + bits. + + storagebits, is the number of bits + (after padding) that it occupies in the buffer. + + + shift, if specified, is the shift that needs + to be applied prior to masking out unused bits. + + + repeat, specifies the number of bits/storagebits + repetitions. When the repeat element is 0 or 1, then the repeat + value is omitted. + + + + + For example, a driver for a 3-axis accelerometer with 12 bit + resolution where data is stored in two 8-bits registers as + follows: + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) + +---+---+---+---+---+---+---+---+ + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) + +---+---+---+---+---+---+---+---+ + + + will have the following scan element type for each axis: + + $ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type + le:s12/16>>4 + + A user space application will interpret data samples read from the + buffer as two byte little endian signed data, that needs a 4 bits + right shift before masking out the 12 valid bits of data. + + + For implementing buffer support a driver should initialize the following + fields in iio_chan_spec definition: + + struct iio_chan_spec { + /* other members */ + int scan_index + struct { + char sign; + u8 realbits; + u8 storagebits; + u8 shift; + u8 repeat; + enum iio_endian endianness; + } scan_type; + }; + + The driver implementing the accelerometer described above will + have the following channel definition: + + struct struct iio_chan_spec accel_channels[] = { + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + /* other stuff here */ + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 12, + .storgebits = 16, + .shift = 4, + .endianness = IIO_LE, + }, + } + /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1) + * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis + */ + } + + + + Here scan_index defines the order in which + the enabled channels are placed inside the buffer. Channels with a lower + scan_index will be placed before channels with a higher index. Each + channel needs to have a unique scan_index. + + + Setting scan_index to -1 can be used to indicate that the specific + channel does not support buffered capture. In this case no entries will + be created for the channel in the scan_elements directory. + + + + + Industrial I/O triggers +!Finclude/linux/iio/trigger.h iio_trigger +!Edrivers/iio/industrialio-trigger.c + + In many situations it is useful for a driver to be able to + capture data based on some external event (trigger) as opposed + to periodically polling for data. An IIO trigger can be provided + by a device driver that also has an IIO device based on hardware + generated events (e.g. data ready or threshold exceeded) or + provided by a separate driver from an independent interrupt + source (e.g. GPIO line connected to some external system, timer + interrupt or user space writing a specific file in sysfs). A + trigger may initiate data capture for a number of sensors and + also it may be completely unrelated to the sensor itself. + + + IIO trigger sysfs interface + There are two locations in sysfs related to triggers: + + /sys/bus/iio/devices/triggerY, + this file is created once an IIO trigger is registered with + the IIO core and corresponds to trigger with index Y. Because + triggers can be very different depending on type there are few + standard attributes that we can describe here: + + + name, trigger name that can be later + used for association with a device. + + + sampling_frequency, some timer based + triggers use this attribute to specify the frequency for + trigger calls. + + + + + /sys/bus/iio/devices/iio:deviceX/trigger/, this + directory is created once the device supports a triggered + buffer. We can associate a trigger with our device by writing + the trigger's name in the current_trigger file. + + + + + IIO trigger setup + + + Let's see a simple example of how to setup a trigger to be used + by a driver. + + + struct iio_trigger_ops trigger_ops = { + .set_trigger_state = sample_trigger_state, + .validate_device = sample_validate_device, + } + + struct iio_trigger *trig; + + /* first, allocate memory for our trigger */ + trig = iio_trigger_alloc(dev, "trig-%s-%d", name, idx); + + /* setup trigger operations field */ + trig->ops = &trigger_ops; + + /* now register the trigger with the IIO core */ + iio_trigger_register(trig); + + + + + IIO trigger ops +!Finclude/linux/iio/trigger.h iio_trigger_ops + + Notice that a trigger has a set of operations attached: + + + set_trigger_state, switch the trigger on/off + on demand. + + + validate_device, function to validate the + device when the current trigger gets changed. + + + + + + + Industrial I/O triggered buffers + + Now that we know what buffers and triggers are let's see how they + work together. + + IIO triggered buffer setup +!Edrivers/iio/industrialio-triggered-buffer.c +!Finclude/linux/iio/iio.h iio_buffer_setup_ops + + + + A typical triggered buffer setup looks like this: + + const struct iio_buffer_setup_ops sensor_buffer_setup_ops = { + .preenable = sensor_buffer_preenable, + .postenable = sensor_buffer_postenable, + .postdisable = sensor_buffer_postdisable, + .predisable = sensor_buffer_predisable, + }; + + irqreturn_t sensor_iio_pollfunc(int irq, void *p) + { + pf->timestamp = iio_get_time_ns(); + return IRQ_WAKE_THREAD; + } + + irqreturn_t sensor_trigger_handler(int irq, void *p) + { + u16 buf[8]; + int i = 0; + + /* read data for each active channel */ + for_each_set_bit(bit, active_scan_mask, masklength) + buf[i++] = sensor_get_data(bit) + + iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp); + + iio_trigger_notify_done(trigger); + return IRQ_HANDLED; + } + + /* setup triggered buffer, usually in probe function */ + iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc, + sensor_trigger_handler, + sensor_buffer_setup_ops); + + + The important things to notice here are: + + iio_buffer_setup_ops, the buffer setup + functions to be called at predefined points in the buffer configuration + sequence (e.g. before enable, after disable). If not specified, the + IIO core uses the default iio_triggered_buffer_setup_ops. + + sensor_iio_pollfunc, the function that + will be used as top half of poll function. It should do as little + processing as possible, because it runs in interrupt context. The most + common operation is recording of the current timestamp and for this reason + one can use the IIO core defined iio_pollfunc_store_time + function. + + sensor_trigger_handler, the function that + will be used as bottom half of the poll function. This runs in the + context of a kernel thread and all the processing takes place here. + It usually reads data from the device and stores it in the internal + buffer together with the timestamp recorded in the top half. + + + + + + + Resources + IIO core may change during time so the best documentation to read is the + source code. There are several locations where you should look: + + + drivers/iio/, contains the IIO core plus + and directories for each sensor type (e.g. accel, magnetometer, + etc.) + + + include/linux/iio/, contains the header + files, nice to read for the internal kernel interfaces. + + + include/uapi/linux/iio/, contains files to be + used by user space applications. + + + tools/iio/, contains tools for rapidly + testing buffers, events and device creation. + + + drivers/staging/iio/, contains code for some + drivers or experimental features that are not yet mature enough + to be moved out. + + + + Besides the code, there are some good online documentation sources: + + + Industrial I/O mailing + list + + + + Analog Device IIO wiki page + + + + Using the Linux IIO framework for SDR, Lars-Peter Clausen's + presentation at FOSDEM + + + + +
+ + -- cgit v1.2.3-59-g8ed1b From 655665d67c8465501a46aa8ffde4e6e29201ba99 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Thu, 6 Aug 2015 14:17:53 +0300 Subject: iio: Documentation: Add trigger name attribute ABI documentation This patch adds an entry in ABI Documentation for the name attribute issued when a trigger is created. Signed-off-by: Cristina Opriceana Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs index 5235e6c749ab..bbb039237a25 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs +++ b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs @@ -9,3 +9,12 @@ Description: automated testing or in situations, where other trigger methods are not applicable. For example no RTC or spare GPIOs. X is the IIO index of the trigger. + +What: /sys/bus/iio/devices/triggerX/name +KernelVersion: 2.6.39 +Contact: linux-iio@vger.kernel.org +Description: + The name attribute holds a description string for the current + trigger. In order to associate the trigger with an IIO device + one should write this name string to + /sys/bus/iio/devices/iio:deviceY/trigger/current_trigger. -- cgit v1.2.3-59-g8ed1b From bdb25b0af8bd225ddf82083d767fada56fb2c1ae Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Wed, 29 Jul 2015 15:57:41 +0300 Subject: iio: Fix typos in ABI documentation Fix typos in ABI documentation Signed-off-by: Vladimir Barinov Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 400d23441a61..abe228dc0dac 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -493,7 +493,7 @@ Contact: linux-iio@vger.kernel.org Description: Specifies the output powerdown mode. DAC output stage is disconnected from the amplifier and - 1kohm_to_gnd: connected to ground via an 1kOhm resistor, + 1kohm_to_gnd: connected to ground via an 1kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor, 100kohm_to_gnd: connected to ground via an 100kOhm resistor, @@ -503,9 +503,9 @@ Description: outX_powerdown_mode_available. If Y is not present the mode is shared across all outputs. -What: /sys/.../iio:deviceX/out_votlageY_powerdown_mode_available +What: /sys/.../iio:deviceX/out_voltageY_powerdown_mode_available What: /sys/.../iio:deviceX/out_voltage_powerdown_mode_available -What: /sys/.../iio:deviceX/out_altvotlageY_powerdown_mode_available +What: /sys/.../iio:deviceX/out_altvoltageY_powerdown_mode_available What: /sys/.../iio:deviceX/out_altvoltage_powerdown_mode_available KernelVersion: 2.6.38 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From 68a403823600fc9d8277f930981d3a013353b2fe Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 17 Mar 2015 13:19:51 -0700 Subject: hwmon: (adm1275) Add support for ADM1293 and ADM1294 ADM1293 and ADM1294 are mostly compatible with other chips of the same series, but have more configuration options. There are also some differences in register details. Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1275 | 40 +++++++----- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/adm1275.c | 141 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 158 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index 15b4a20d5062..d697229e3c18 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -14,6 +14,10 @@ Supported chips: Prefix: 'adm1276' Addresses scanned: - Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf + * Analog Devices ADM1293/ADM1294 + Prefix: 'adm1293', 'adm1294' + Addresses scanned: - + Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1293_1294.pdf Author: Guenter Roeck @@ -22,12 +26,12 @@ Description ----------- This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, -and ADM1276 Hot-Swap Controller and Digital Power Monitor. +ADM1276, ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. -ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit -board to be removed from or inserted into a live backplane. They also feature -current and voltage readback via an integrated 12-bit analog-to-digital -converter (ADC), accessed using a PMBus interface. +ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 are hot-swap controllers that +allow a circuit board to be removed from or inserted into a live backplane. +They also feature current and voltage readback via an integrated 12 +bit analog-to-digital converter (ADC), accessed using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -58,16 +62,16 @@ Sysfs entries The following attributes are supported. Limits are read-write, history reset attributes are write-only, all other attributes are read-only. -in1_label "vin1" or "vout1" depending on chip variant and - configuration. On ADM1075, vout1 reports the voltage on - the VAUX pin. -in1_input Measured voltage. -in1_min Minimum Voltage. -in1_max Maximum voltage. -in1_min_alarm Voltage low alarm. -in1_max_alarm Voltage high alarm. -in1_highest Historical maximum voltage. -in1_reset_history Write any value to reset history. +inX_label "vin1" or "vout1" depending on chip variant and + configuration. On ADM1075, ADM1293, and ADM1294, + vout1 reports the voltage on the VAUX pin. +inX_input Measured voltage. +inX_min Minimum Voltage. +inX_max Maximum voltage. +inX_min_alarm Voltage low alarm. +inX_max_alarm Voltage high alarm. +inX_highest Historical maximum voltage. +inX_reset_history Write any value to reset history. curr1_label "iout1" curr1_input Measured current. @@ -86,7 +90,9 @@ curr1_reset_history Write any value to reset history. power1_label "pin1" power1_input Input power. +power1_input_lowest Lowest observed input power. ADM1293 and ADM1294 only. +power1_input_highest Highest observed input power. power1_reset_history Write any value to reset history. - Power attributes are supported on ADM1075 and ADM1276 - only. + Power attributes are supported on ADM1075, ADM1276, + ADM1293, and ADM1294. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 9f7dbd189c97..67901cb08f77 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -30,8 +30,8 @@ config SENSORS_ADM1275 default n help If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital - Power Monitors. + Devices ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap + Controller and Digital Power Monitors. This driver can also be built as a module. If so, the module will be called adm1275. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 1c19a2ee415c..188af4c89f40 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -24,7 +24,11 @@ #include #include "pmbus.h" -enum chips { adm1075, adm1275, adm1276 }; +enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; + +#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) +#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) +#define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6) #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 @@ -37,18 +41,30 @@ enum chips { adm1075, adm1275, adm1276 }; #define ADM1075_IRANGE_25 BIT(3) #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) +#define ADM1293_IRANGE_25 0 +#define ADM1293_IRANGE_50 BIT(6) +#define ADM1293_IRANGE_100 BIT(7) +#define ADM1293_IRANGE_200 (BIT(6) | BIT(7)) +#define ADM1293_IRANGE_MASK (BIT(6) | BIT(7)) + +#define ADM1293_VIN_SEL_012 BIT(2) +#define ADM1293_VIN_SEL_074 BIT(3) +#define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3)) +#define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3)) + +#define ADM1293_VAUX_EN BIT(1) + #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 #define ADM1275_IOUT_WARN2_SELECT BIT(4) #define ADM1276_PEAK_PIN 0xda - -#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) - #define ADM1075_READ_VAUX 0xdd #define ADM1075_VAUX_OV_WARN_LIMIT 0xde #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf +#define ADM1293_IOUT_MIN 0xe3 +#define ADM1293_PIN_MIN 0xe4 #define ADM1075_VAUX_STATUS 0xf6 #define ADM1075_VAUX_OV_WARN BIT(7) @@ -60,6 +76,9 @@ struct adm1275_data { bool have_uc_fault; bool have_vout; bool have_vaux_status; + bool have_mfr_vaux_status; + bool have_iout_min; + bool have_pin_min; bool have_pin_max; struct pmbus_driver_info info; }; @@ -94,6 +113,28 @@ static const struct coefficients adm1276_coefficients[] = { [4] = { 2115, 0, -1 }, /* power, vrange not set */ }; +static const struct coefficients adm1293_coefficients[] = { + [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ + [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ + [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */ + [3] = { 8000, -100, -2 }, /* current, irange25 */ + [4] = { 4000, -100, -2 }, /* current, irange50 */ + [5] = { 20000, -1000, -3 }, /* current, irange100 */ + [6] = { 10000, -1000, -3 }, /* current, irange200 */ + [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */ + [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */ + [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */ + [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */ + [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */ + [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */ + [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */ + [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */ + [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */ + [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */ + [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */ + [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ +}; + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -131,6 +172,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); break; + case PMBUS_VIRT_READ_IOUT_MIN: + if (!data->have_iout_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); break; @@ -140,6 +186,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_READ_VIN_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; + case PMBUS_VIRT_READ_PIN_MIN: + if (!data->have_pin_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN); + break; case PMBUS_VIRT_READ_PIN_MAX: if (!data->have_pin_max) return -ENXIO; @@ -163,6 +214,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct adm1275_data *data = to_adm1275_data(info); int ret; if (page) @@ -176,6 +229,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); + if (!ret && data->have_iout_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_IOUT_MIN, 0); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); @@ -185,6 +241,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_PIN_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); + if (!ret && data->have_pin_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_PIN_MIN, 0); break; default: ret = -ENODATA; @@ -231,6 +290,15 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_VOLTAGE_OV_WARNING; if (mfr_status & ADM1075_VAUX_UV_WARN) ret |= PB_VOLTAGE_UV_WARNING; + } else if (data->have_mfr_vaux_status) { + mfr_status = pmbus_read_byte_data(client, page, + PMBUS_STATUS_MFR_SPECIFIC); + if (mfr_status < 0) + return mfr_status; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; } break; default: @@ -244,6 +312,8 @@ static const struct i2c_device_id adm1275_id[] = { { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, + { "adm1293", adm1293 }, + { "adm1294", adm1294 }, { } }; MODULE_DEVICE_TABLE(i2c, adm1275_id); @@ -258,7 +328,7 @@ static int adm1275_probe(struct i2c_client *client, struct adm1275_data *data; const struct i2c_device_id *mid; const struct coefficients *coefficients; - int vindex = -1, cindex = -1, pindex = -1; + int vindex = -1, voindex = -1, cindex = -1, pindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -390,17 +460,72 @@ static int adm1275_probe(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; + case adm1293: + case adm1294: + data->have_iout_min = true; + data->have_pin_min = true; + data->have_pin_max = true; + data->have_mfr_vaux_status = true; + + coefficients = adm1293_coefficients; + + voindex = 0; + switch (config & ADM1293_VIN_SEL_MASK) { + case ADM1293_VIN_SEL_012: /* 1.2V */ + vindex = 0; + break; + case ADM1293_VIN_SEL_074: /* 7.4V */ + vindex = 1; + break; + case ADM1293_VIN_SEL_210: /* 21V */ + vindex = 2; + break; + default: /* disabled */ + break; + } + + switch (config & ADM1293_IRANGE_MASK) { + case ADM1293_IRANGE_25: + cindex = 3; + break; + case ADM1293_IRANGE_50: + cindex = 4; + break; + case ADM1293_IRANGE_100: + cindex = 5; + break; + case ADM1293_IRANGE_200: + cindex = 6; + break; + } + + if (vindex >= 0) + pindex = 7 + vindex * 4 + (cindex - 3); + + if (config & ADM1293_VAUX_EN) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + info->func[0] |= PMBUS_HAVE_PIN | + PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; + + break; default: dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } + + if (voindex < 0) + voindex = vindex; if (vindex >= 0) { info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; - info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; - info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; - info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; + } + if (voindex >= 0) { + info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m; + info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b; + info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; } if (cindex >= 0) { info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; -- cgit v1.2.3-59-g8ed1b From a1dc86ebd2f2eb6652c8be9311c16acccd1708f8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 19 Jul 2015 00:29:14 +0200 Subject: hwmon: (lm70) add device tree support Allow the lm70 to be probed from a device tree. Signed-off-by: Rabin Vincent Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm70.txt | 21 +++++++++++++++ drivers/hwmon/lm70.c | 34 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hwmon/lm70.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/lm70.txt b/Documentation/devicetree/bindings/hwmon/lm70.txt new file mode 100644 index 000000000000..e7fd921aa4f1 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lm70.txt @@ -0,0 +1,21 @@ +* LM70/TMP121/LM71/LM74 thermometer. + +Required properties: +- compatible: one of + "ti,lm70" + "ti,tmp121" + "ti,lm71" + "ti,lm74" + +See Documentation/devicetree/bindings/spi/spi-bus.txt for more required and +optional properties. + +Example: + +spi_master { + temperature-sensor@0 { + compatible = "ti,lm70"; + reg = <0>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 97204dce162d..9296e9daf774 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -37,6 +37,7 @@ #include #include #include +#include #define DRVNAME "lm70" @@ -130,11 +131,41 @@ ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ +#ifdef CONFIG_OF +static const struct of_device_id lm70_of_ids[] = { + { + .compatible = "ti,lm70", + .data = (void *) LM70_CHIP_LM70, + }, + { + .compatible = "ti,tmp121", + .data = (void *) LM70_CHIP_TMP121, + }, + { + .compatible = "ti,lm71", + .data = (void *) LM70_CHIP_LM71, + }, + { + .compatible = "ti,lm74", + .data = (void *) LM70_CHIP_LM74, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lm70_of_ids); +#endif + static int lm70_probe(struct spi_device *spi) { - int chip = spi_get_device_id(spi)->driver_data; + const struct of_device_id *match; struct device *hwmon_dev; struct lm70 *p_lm70; + int chip; + + match = of_match_device(lm70_of_ids, &spi->dev); + if (match) + chip = (int)(uintptr_t)match->data; + else + chip = spi_get_device_id(spi)->driver_data; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -169,6 +200,7 @@ static struct spi_driver lm70_driver = { .driver = { .name = "lm70", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lm70_of_ids), }, .id_table = lm70_ids, .probe = lm70_probe, -- cgit v1.2.3-59-g8ed1b From 1c6e8f6ba89c59270db223284d47e3c928c6fbfc Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Tue, 28 Jul 2015 01:01:07 +0300 Subject: hwmon: (nct7802) Add auto_point attributes Introduced REG_PWM, pwm[1..3]_auto_point[1..5]_temp, pwm[1..3]_auto_point[1..5]_pwm, nct7802_auto_point_attrs, nct7802_auto_point_group, updated nct7802_regmap_is_volatile Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct7802 | 3 +- drivers/hwmon/nct7802.c | 130 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/nct7802 b/Documentation/hwmon/nct7802 index 2e00f5e344bc..5438deb6be02 100644 --- a/Documentation/hwmon/nct7802 +++ b/Documentation/hwmon/nct7802 @@ -17,8 +17,7 @@ This driver implements support for the Nuvoton NCT7802Y hardware monitoring chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan speed sensors. -The chip also supports intelligent fan speed control. This functionality is -not currently supported by the driver. +Smart Fan™ speed control is available via pwmX_auto_point attributes. Tested Boards and BIOS Versions ------------------------------- diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index f4908bb228b8..3ce33d244cc0 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,7 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_PWM(x) (0x60 + (x)) #define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) #define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) #define REG_VENDOR_ID 0xfd @@ -130,6 +131,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, unsigned int val; int ret; + if (!attr->index) + return sprintf(buf, "255\n"); + ret = regmap_read(data->regmap, attr->index, &val); if (ret < 0) return ret; @@ -826,9 +830,12 @@ static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); /* 7.2.91... Fan Control Output Value */ -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); -static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); -static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(0)); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(1)); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(2)); /* 7.2.95... Temperature to Fan mapping Relationships Register */ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, @@ -893,11 +900,125 @@ static struct attribute_group nct7802_pwm_group = { .attrs = nct7802_pwm_attrs, }; +/* 7.2.115... 0x80-0x83, 0x84 Temperature (X-axis) transition */ +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x80, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x81, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x82, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x83, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x84, 0); + +/* 7.2.120... 0x85-0x88 PWM (Y-axis) transition */ +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x85); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x86); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x87); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x88); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.124 Table 2 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x90, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x91, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x92, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x93, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x94, 0); + +/* 7.2.129 Table 2 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x95); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x96); +static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x97); +static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x98); +static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.133 Table 3 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA0, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA1, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA3, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA4, 0); + +/* 7.2.138 Table 3 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA5); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA6); +static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA7); +static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA8); +static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +static struct attribute *nct7802_auto_point_attrs[] = { + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, + + NULL +}; + +static struct attribute_group nct7802_auto_point_group = { + .attrs = nct7802_auto_point_attrs, +}; + static const struct attribute_group *nct7802_groups[] = { &nct7802_temp_group, &nct7802_in_group, &nct7802_fan_group, &nct7802_pwm_group, + &nct7802_auto_point_group, NULL }; @@ -945,7 +1066,8 @@ static int nct7802_detect(struct i2c_client *client, static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg) { - return reg != REG_BANK && reg <= 0x20; + return (reg != REG_BANK && reg <= 0x20) || + (reg >= REG_PWM(0) && reg <= REG_PWM(2)); } static const struct regmap_config nct7802_regmap_config = { -- cgit v1.2.3-59-g8ed1b From ead8080351c988b9c4bb5ec261d7b4c97ebb2773 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Wed, 5 Aug 2015 12:53:08 -0700 Subject: hwmon: (it87) Add support for IT8732F Add support for the IT8732F. This chip is pretty similar to IT8721F, with the main difference being that the ADC LSB is 10.9 mV instead of 12 mV. Signed-off-by: Justin Maggard Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 35 ++++++++++++++++++++++------------- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 43 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index e87294878334..733296d65449 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -38,6 +38,10 @@ Supported chips: Prefix: 'it8728' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8732F + Prefix: 'it8732' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8771E Prefix: 'it8771' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -111,9 +115,9 @@ Description ----------- This driver implements support for the IT8603E, IT8620E, IT8623E, IT8705F, -IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, -IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and SiS950 -chips. +IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, +IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and +SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -137,10 +141,10 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions have support for 2 additional fans. The additional fans are supported by the driver. -The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8781F, IT8782F, IT8783E/F, -and late IT8712F and IT8705F also have optional 16-bit tachometer counters -for fans 1 to 3. This is better (no more fan clock divider mess) but not -compatible with the older chips and revisions. The 16-bit tachometer mode +The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, +IT8783E/F, and late IT8712F and IT8705F also have optional 16-bit tachometer +counters for fans 1 to 3. This is better (no more fan clock divider mess) but +not compatible with the older chips and revisions. The 16-bit tachometer mode is enabled by the driver when one of the above chips is detected. The IT8726F is just bit enhanced IT8716F with additional hardware @@ -159,6 +163,9 @@ IT8728F. It only supports 16-bit fan mode. The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. +The IT8732F supports a closed-loop mode for fan control, but this is not +currently implemented by the driver. + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -173,12 +180,14 @@ is done. Voltage sensors (also known as IN sensors) report their values in volts. An alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution of -0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The -battery voltage in8 does not have limit registers. - -On the IT8603E, IT8721F/IT8758E, IT8781F, IT8782F, and IT8783E/F, some +zero'; this is important for negative voltage measurements. On most chips, all +voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. IT8603E, IT8721F/IT8758E and IT8728F can measure between 0 and +3.06 volts, with a resolution of 0.012 volt. IT8732F can measure between 0 and +2.8 volts with a resolution of 0.0109 volt. The battery voltage in8 does not +have limit registers. + +On the IT8603E, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, and IT8783E/F, some voltage inputs are internal and scaled inside the chip: * in3 (optional) * in7 (optional for IT8781F, IT8782F, and IT8783E/F) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7c65b7334738..500b262b89bb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -609,8 +609,8 @@ config SENSORS_IT87 depends on !PPC select HWMON_VID help - If you say yes here you get support for ITE IT8705F, IT8712F, - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, + If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, + IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d0ee556e8ce0..1896e26df634 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -21,6 +21,7 @@ * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface * IT8728F Super I/O chip w/LPC interface + * IT8732F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface * IT8771E Super I/O chip w/LPC interface * IT8772E Super I/O chip w/LPC interface @@ -69,8 +70,9 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8786, it8790, it8603, it8620 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, + it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603, + it8620 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -148,6 +150,7 @@ static inline void superio_exit(void) #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 +#define IT8732F_DEVID 0x8732 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 #define IT8781F_DEVID 0x8781 @@ -265,6 +268,7 @@ struct it87_devices { #define FEAT_VID (1 << 9) /* Set if chip supports VID */ #define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */ #define FEAT_SIX_FANS (1 << 11) /* Supports six fans */ +#define FEAT_10_9MV_ADC (1 << 12) static const struct it87_devices it87_devices[] = { [it87] = { @@ -315,6 +319,15 @@ static const struct it87_devices it87_devices[] = { | FEAT_IN7_INTERNAL, .peci_mask = 0x07, }, + [it8732] = { + .name = "it8732", + .suffix = "F", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, [it8771] = { .name = "it8771", .suffix = "E", @@ -391,6 +404,7 @@ static const struct it87_devices it87_devices[] = { #define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) #define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) +#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC) #define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) #define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) #define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) @@ -475,7 +489,14 @@ struct it87_data { static int adc_lsb(const struct it87_data *data, int nr) { - int lsb = has_12mv_adc(data) ? 12 : 16; + int lsb; + + if (has_12mv_adc(data)) + lsb = 120; + else if (has_10_9mv_adc(data)) + lsb = 109; + else + lsb = 160; if (data->in_scaled & (1 << nr)) lsb <<= 1; return lsb; @@ -483,13 +504,13 @@ static int adc_lsb(const struct it87_data *data, int nr) static u8 in_to_reg(const struct it87_data *data, int nr, long val) { - val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); + val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr)); return clamp_val(val, 0, 255); } static int in_from_reg(const struct it87_data *data, int nr, int val) { - return val * adc_lsb(data, nr); + return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10); } static inline u8 FAN_TO_REG(long rpm, int div) @@ -1515,9 +1536,14 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, }; struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; + const char *label; - return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] - : labels[nr]); + if (has_12mv_adc(data) || has_10_9mv_adc(data)) + label = labels_it8721[nr]; + else + label = labels[nr]; + + return sprintf(buf, "%s\n", label); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1853,6 +1879,9 @@ static int __init it87_find(unsigned short *address, case IT8728F_DEVID: sio_data->type = it8728; break; + case IT8732F_DEVID: + sio_data->type = it8732; + break; case IT8771E_DEVID: sio_data->type = it8771; break; -- cgit v1.2.3-59-g8ed1b From 1f61cab8a729e00af77b51b44c3a8dc8ef3b3eb9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 11:15:23 -0700 Subject: hwmon: (pmbus) Add support for MAX20751 MAX20751 is a multiphase power controller with internal buck converter. It uses VR12.0 to report the output voltage. This requires an explicit driver, since the VR version can not be auto-detected. The chip supports a manufacturer specific command to fine-tune the output voltage. This command is not currently supported. Signed-off-by: Guenter Roeck --- Documentation/hwmon/max20751 | 77 ++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 7 ++++ drivers/hwmon/pmbus/Kconfig | 10 ++++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/max20751.c | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 Documentation/hwmon/max20751 create mode 100644 drivers/hwmon/pmbus/max20751.c (limited to 'Documentation') diff --git a/Documentation/hwmon/max20751 b/Documentation/hwmon/max20751 new file mode 100644 index 000000000000..f9fa25ebb521 --- /dev/null +++ b/Documentation/hwmon/max20751 @@ -0,0 +1,77 @@ +Kernel driver max20751 +====================== + +Supported chips: + * maxim MAX20751 + Prefix: 'max20751' + Addresses scanned: - + Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX20751.pdf + Application note: http://pdfserv.maximintegrated.com/en/an/AN5941.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports MAX20751 Multiphase Master with PMBus Interface +and Internal Buck Converter. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. + +in1_label "vin1" +in1_input Measured voltage. +in1_min Minimum input voltage. +in1_max Maximum input voltage. +in1_lcrit Critical minimum input voltage. +in1_crit Critical maximum input voltage. +in1_min_alarm Input voltage low alarm. +in1_lcrit_alarm Input voltage critical low alarm. +in1_min_alarm Input voltage low alarm. +in1_max_alarm Input voltage high alarm. + +in2_label "vout1" +in2_input Measured voltage. +in2_min Minimum output voltage. +in2_max Maximum output voltage. +in2_lcrit Critical minimum output voltage. +in2_crit Critical maximum output voltage. +in2_min_alarm Output voltage low alarm. +in2_lcrit_alarm Output voltage critical low alarm. +in2_min_alarm Output voltage low alarm. +in2_max_alarm Output voltage high alarm. + +curr1_input Measured output current. +curr1_label "iout1" +curr1_max Maximum output current. +curr1_alarm Current high alarm. + +temp1_input Measured temperature. +temp1_max Maximum temperature. +temp1_crit Critical high temperature. +temp1_max_alarm Chip temperature high alarm. +temp1_crit_alarm Chip temperature critical high alarm. + +power1_input Output power. +power1_label "pout1" diff --git a/MAINTAINERS b/MAINTAINERS index a9ae6c105520..6a406b607eeb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6539,6 +6539,13 @@ S: Maintained F: Documentation/hwmon/max16065 F: drivers/hwmon/max16065.c +MAX20751 HARDWARE MONITOR DRIVER +M: Guenter Roeck +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/max20751 +F: drivers/hwmon/max20751.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: "Hans J. Koch" L: lm-sensors@lm-sensors.org diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 67901cb08f77..6e1e6fe434f7 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -73,6 +73,16 @@ config SENSORS_MAX16064 This driver can also be built as a module. If so, the module will be called max16064. +config SENSORS_MAX20751 + tristate "Maxim MAX20751" + default n + help + If you say yes here you get hardware monitoring support for Maxim + MAX20751. + + This driver can also be built as a module. If so, the module will + be called max20751. + config SENSORS_MAX34440 tristate "Maxim MAX34440 and compatibles" default n diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 1454293e985c..bce046d37f02 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o +obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c new file mode 100644 index 000000000000..ab74aeae8cf2 --- /dev/null +++ b/drivers/hwmon/pmbus/max20751.c @@ -0,0 +1,64 @@ +/* + * Hardware monitoring driver for Maxim MAX20751 + * + * Copyright (c) 2015 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "pmbus.h" + +static struct pmbus_driver_info max20751_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .vrm_version = vr12, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, +}; + +static int max20751_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &max20751_info); +} + +static const struct i2c_device_id max20751_id[] = { + {"max20751", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, max20751_id); + +static struct i2c_driver max20751_driver = { + .driver = { + .name = "max20751", + }, + .probe = max20751_probe, + .remove = pmbus_do_remove, + .id_table = max20751_id, +}; + +module_i2c_driver(max20751_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 1a94acf858000836d28b13942eebf5cbffc9ac34 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Fri, 24 Jul 2015 14:05:06 -0500 Subject: ARM: socfpga: dts: add "altr,modrst-offset" property The "altr,modrst-offset" property represents the offset into the reset manager that is the first register to be used by the driver to bring peripherals out of reset. Signed-off-by: Dinh Nguyen --- Documentation/devicetree/bindings/reset/socfpga-reset.txt | 2 ++ arch/arm/boot/dts/socfpga.dtsi | 1 + arch/arm/boot/dts/socfpga_arria10.dtsi | 1 + 3 files changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/socfpga-reset.txt b/Documentation/devicetree/bindings/reset/socfpga-reset.txt index 32c1c8bfd5dc..98c9f560e5c5 100644 --- a/Documentation/devicetree/bindings/reset/socfpga-reset.txt +++ b/Documentation/devicetree/bindings/reset/socfpga-reset.txt @@ -3,6 +3,7 @@ Altera SOCFPGA Reset Manager Required properties: - compatible : "altr,rst-mgr" - reg : Should contain 1 register ranges(address and length) +- altr,modrst-offset : Should contain the offset of the first modrst register. - #reset-cells: 1 Example: @@ -10,4 +11,5 @@ Example: #reset-cells = <1>; compatible = "altr,rst-mgr"; reg = <0xffd05000 0x1000>; + altr,modrst-offset = <0x10>; }; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 80f924deed37..ed185b92bcbe 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -752,6 +752,7 @@ #reset-cells = <1>; compatible = "altr,rst-mgr"; reg = <0xffd05000 0x1000>; + altr,modrst-offset = <0x10>; }; usbphy0: usbphy@0 { diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index 4779b07310df..1d341dc3e598 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi @@ -588,6 +588,7 @@ #reset-cells = <1>; compatible = "altr,rst-mgr"; reg = <0xffd05000 0x100>; + altr,modrst-offset = <0x20>; }; scu: snoop-control-unit@ffffc000 { -- cgit v1.2.3-59-g8ed1b From 92b7cb5dc885b38b21093eefed8028b615952965 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 3 Aug 2015 17:40:51 +0300 Subject: extcon: palmas: Support GPIO based USB ID detection Some palmas based chip variants do not have OTG based ID logic. For these variants we rely on GPIO based USB ID detection. These chips do have VBUS comparator for VBUS detection so we continue to use the old way of detecting VBUS. Signed-off-by: Roger Quadros Acked-by: Chanwoo Choi Acked-by: Lee Jones Signed-off-by: Chanwoo Choi --- .../devicetree/bindings/extcon/extcon-palmas.txt | 5 +- drivers/extcon/extcon-palmas.c | 129 ++++++++++++++++++--- drivers/extcon/extcon-usb-gpio.c | 1 + include/linux/mfd/palmas.h | 7 ++ 4 files changed, 126 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt index 45414bbcd945..f61d5af44a27 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt @@ -10,8 +10,11 @@ Required Properties: Optional Properties: - ti,wakeup : To enable the wakeup comparator in probe - - ti,enable-id-detection: Perform ID detection. + - ti,enable-id-detection: Perform ID detection. If id-gpio is specified + it performs id-detection using GPIO else using OTG core. - ti,enable-vbus-detection: Perform VBUS detection. + - id-gpio: gpio for GPIO ID detection. See gpio binding. + - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds. palmas-usb { compatible = "ti,twl6035-usb", "ti,palmas-usb"; diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 8933e7e0d9da..662e91778cb0 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -28,6 +28,10 @@ #include #include #include +#include +#include + +#define USB_GPIO_DEBOUNCE_MS 20 /* ms */ static const unsigned int palmas_extcon_cable[] = { EXTCON_USB, @@ -118,19 +122,54 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) return IRQ_HANDLED; } +static void palmas_gpio_id_detect(struct work_struct *work) +{ + int id; + struct palmas_usb *palmas_usb = container_of(to_delayed_work(work), + struct palmas_usb, + wq_detectid); + struct extcon_dev *edev = palmas_usb->edev; + + if (!palmas_usb->id_gpiod) + return; + + id = gpiod_get_value_cansleep(palmas_usb->id_gpiod); + + if (id) { + extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); + dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); + } else { + extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); + dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); + } +} + +static irqreturn_t palmas_gpio_id_irq_handler(int irq, void *_palmas_usb) +{ + struct palmas_usb *palmas_usb = _palmas_usb; + + queue_delayed_work(system_power_efficient_wq, &palmas_usb->wq_detectid, + palmas_usb->sw_debounce_jiffies); + + return IRQ_HANDLED; +} + static void palmas_enable_irq(struct palmas_usb *palmas_usb) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_VBUS_CTRL_SET, PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP); - palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, - PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); + if (palmas_usb->enable_id_detection) { + palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, + PALMAS_USB_ID_CTRL_SET, + PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); - palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, - PALMAS_USB_ID_INT_EN_HI_SET, - PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | - PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); + palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, + PALMAS_USB_ID_INT_EN_HI_SET, + PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | + PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); + } if (palmas_usb->enable_vbus_detection) palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb); @@ -169,20 +208,36 @@ static int palmas_usb_probe(struct platform_device *pdev) palmas_usb->wakeup = pdata->wakeup; } + palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id"); + if (IS_ERR(palmas_usb->id_gpiod)) { + dev_err(&pdev->dev, "failed to get id gpio\n"); + return PTR_ERR(palmas_usb->id_gpiod); + } + + if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) { + palmas_usb->enable_id_detection = false; + palmas_usb->enable_gpio_id_detection = true; + } + + if (palmas_usb->enable_gpio_id_detection) { + u32 debounce; + + if (of_property_read_u32(node, "debounce-delay-ms", &debounce)) + debounce = USB_GPIO_DEBOUNCE_MS; + + status = gpiod_set_debounce(palmas_usb->id_gpiod, + debounce * 1000); + if (status < 0) + palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); + } + + INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); + palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; - palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_ID_OTG_IRQ); - palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_ID_IRQ); - palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_VBUS_OTG_IRQ); - palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_VBUS_IRQ); - palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); @@ -201,6 +256,10 @@ static int palmas_usb_probe(struct platform_device *pdev) } if (palmas_usb->enable_id_detection) { + palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_ID_OTG_IRQ); + palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_ID_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, @@ -212,9 +271,33 @@ static int palmas_usb_probe(struct platform_device *pdev) palmas_usb->id_irq, status); return status; } + } else if (palmas_usb->enable_gpio_id_detection) { + palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod); + if (palmas_usb->gpio_id_irq < 0) { + dev_err(&pdev->dev, "failed to get id irq\n"); + return palmas_usb->gpio_id_irq; + } + status = devm_request_threaded_irq(&pdev->dev, + palmas_usb->gpio_id_irq, + NULL, + palmas_gpio_id_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "palmas_usb_id", + palmas_usb); + if (status < 0) { + dev_err(&pdev->dev, + "failed to request handler for id irq\n"); + return status; + } } if (palmas_usb->enable_vbus_detection) { + palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_VBUS_OTG_IRQ); + palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_VBUS_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, @@ -229,10 +312,21 @@ static int palmas_usb_probe(struct platform_device *pdev) } palmas_enable_irq(palmas_usb); + /* perform initial detection */ + palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); device_set_wakeup_capable(&pdev->dev, true); return 0; } +static int palmas_usb_remove(struct platform_device *pdev) +{ + struct palmas_usb *palmas_usb = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&palmas_usb->wq_detectid); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int palmas_usb_suspend(struct device *dev) { @@ -243,6 +337,8 @@ static int palmas_usb_suspend(struct device *dev) enable_irq_wake(palmas_usb->vbus_irq); if (palmas_usb->enable_id_detection) enable_irq_wake(palmas_usb->id_irq); + if (palmas_usb->enable_gpio_id_detection) + enable_irq_wake(palmas_usb->gpio_id_irq); } return 0; } @@ -256,6 +352,8 @@ static int palmas_usb_resume(struct device *dev) disable_irq_wake(palmas_usb->vbus_irq); if (palmas_usb->enable_id_detection) disable_irq_wake(palmas_usb->id_irq); + if (palmas_usb->enable_gpio_id_detection) + disable_irq_wake(palmas_usb->gpio_id_irq); } return 0; }; @@ -273,6 +371,7 @@ static const struct of_device_id of_palmas_match_tbl[] = { static struct platform_driver palmas_usb_driver = { .probe = palmas_usb_probe, + .remove = palmas_usb_remove, .driver = { .name = "palmas-usb", .of_match_table = of_palmas_match_tbl, diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index a2a44536a608..2b2fecffb1ad 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index bb270bd03eed..13e1d96935ed 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #define PALMAS_NUM_CLIENTS 3 @@ -551,10 +552,16 @@ struct palmas_usb { int vbus_otg_irq; int vbus_irq; + int gpio_id_irq; + struct gpio_desc *id_gpiod; + unsigned long sw_debounce_jiffies; + struct delayed_work wq_detectid; + enum palmas_usb_state linkstat; int wakeup; bool enable_vbus_detection; bool enable_id_detection; + bool enable_gpio_id_detection; }; #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator) -- cgit v1.2.3-59-g8ed1b From ff1a15d9e79886e253dd4a0fe5c03d130879f58e Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:42 -0700 Subject: crypto: caam - Added clocks and clock-names properties to SEC4.0 device tree binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clocks and clock-names properties describe input clocks that may be required for enablement of CAAM. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index e4022776ac6e..100307304766 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -106,6 +106,18 @@ PROPERTIES to the interrupt parent to which the child domain is being mapped. + - clocks + Usage: required if SEC 4.0 requires explicit enablement of clocks + Value type: + Definition: A list of phandle and clock specifier pairs describing + the clocks required for enabling and disabling SEC 4.0. + + - clock-names + Usage: required if SEC 4.0 requires explicit enablement of clocks + Value type: + Definition: A list of clock name strings in the same order as the + clocks property. + Note: All other standard properties (see the ePAPR) are allowed but are optional. @@ -120,6 +132,11 @@ EXAMPLE ranges = <0 0x300000 0x10000>; interrupt-parent = <&mpic>; interrupts = <92 2>; + clocks = <&clks IMX6QDL_CLK_CAAM_MEM>, + <&clks IMX6QDL_CLK_CAAM_ACLK>, + <&clks IMX6QDL_CLK_CAAM_IPG>, + <&clks IMX6QDL_CLK_EIM_SLOW>; + clock-names = "mem", "aclk", "ipg", "emi_slow"; }; ===================================================================== -- cgit v1.2.3-59-g8ed1b From 0e91657e331d55d4fd4d298cf9e9eecf23a3dd45 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 6 Aug 2015 14:49:00 -0700 Subject: crypto: doc - make URL into hyperlink The HTML output works a little nicer that way. Signed-off-by: Brian Norris Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 8e17a41df4c3..07df23ea06e4 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -1101,7 +1101,7 @@ kernel crypto API | Caller - [1] http://www.chronox.de/libkcapi.html + [1] http://www.chronox.de/libkcapi.html
@@ -1661,7 +1661,7 @@ read(opfd, out, outlen); - [1] http://www.chronox.de/libkcapi.html + [1] http://www.chronox.de/libkcapi.html
-- cgit v1.2.3-59-g8ed1b From cfca3789e0678c57e09dfb1a09fdfce427b7c92e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Aug 2015 20:55:59 -0700 Subject: hwmon: (pmbus) Add device IDs for TPS544{B,C}2{0,5} Add device IDs and references for Texas Instruments TPS544B20, TPS544B25, TPS544C20, and TPS544C25 to the generic PMBus driver. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus | 8 ++++++-- drivers/hwmon/pmbus/Kconfig | 3 ++- drivers/hwmon/pmbus/pmbus.c | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index a3557da8f5b4..b397675e876d 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -23,11 +23,15 @@ Supported chips: http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf - * Texas Instruments TPS40400 - Prefixes: 'tps40400' + * Texas Instruments TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25 + Prefixes: 'tps40400', 'tps544b20', 'tps544b25', 'tps544c20', 'tps544c25' Addresses scanned: - Datasheets: http://www.ti.com/lit/gpn/tps40400 + http://www.ti.com/lit/gpn/tps544b20 + http://www.ti.com/lit/gpn/tps544b25 + http://www.ti.com/lit/gpn/tps544c20 + http://www.ti.com/lit/gpn/tps544c25 * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 6e1e6fe434f7..2b3242cc7779 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -20,7 +20,8 @@ config SENSORS_PMBUS help If you say yes here you get hardware monitoring support for generic PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, and TPS40400. + MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, TPS544B20, + TPS544B25, TPS544C20, TPS544C25, and UDT020. This driver can also be built as a module. If so, the module will be called pmbus. diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index bbfa35d82e42..0a74991a60f0 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -194,6 +194,10 @@ static const struct i2c_device_id pmbus_id[] = { {"pdt012", 1}, {"pmbus", 0}, {"tps40400", 1}, + {"tps544b20", 1}, + {"tps544b25", 1}, + {"tps544c20", 1}, + {"tps544c25", 1}, {"udt020", 1}, {} }; -- cgit v1.2.3-59-g8ed1b From f3ff96e90733c24dc2f7e510822eb177d22683ed Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 10 Jul 2015 02:09:43 +0800 Subject: Document: dt: binding: imx: update document for imx6ul support This part just add necessary change to boot imx6ul. Update clock and pinctrl for imx6ul Signed-off-by: Frank Li Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx6ul-clock.txt | 13 ++++++++ .../bindings/pinctrl/fsl,imx6ul-pinctrl.txt | 36 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx6ul-clock.txt create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/imx6ul-clock.txt b/Documentation/devicetree/bindings/clock/imx6ul-clock.txt new file mode 100644 index 000000000000..571d5039f663 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx6ul-clock.txt @@ -0,0 +1,13 @@ +* Clock bindings for Freescale i.MX6 UltraLite + +Required properties: +- compatible: Should be "fsl,imx6ul-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 entries "ckil", "osc", "ipp_di0" and "ipp_di1" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6ul-clock.h +for the full list of i.MX6 UltraLite clock IDs. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt new file mode 100644 index 000000000000..a81bbf37ed66 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt @@ -0,0 +1,36 @@ +* Freescale i.MX6 UltraLite IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6ul-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx6ul-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX6 UltraLite + Reference Manual for detailed CONFIG settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (0 << 6) +PAD_CTL_SPEED_MED (1 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_260ohm (1 << 3) +PAD_CTL_DSE_130ohm (2 << 3) +PAD_CTL_DSE_87ohm (3 << 3) +PAD_CTL_DSE_65ohm (4 << 3) +PAD_CTL_DSE_52ohm (5 << 3) +PAD_CTL_DSE_43ohm (6 << 3) +PAD_CTL_DSE_37ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) -- cgit v1.2.3-59-g8ed1b From fd26f8830979de48eb3f1c253eb9d2ee2e468eb6 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 4 Jun 2015 13:11:45 -0700 Subject: dt/bindings: Add binding for the Raspberry Pi firmware driver This driver will provide support for calls into the firmware that will be used by other drivers like cpufreq and vc4. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Signed-off-by: Lee Jones --- .../bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt new file mode 100644 index 000000000000..6824b3180ffb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt @@ -0,0 +1,14 @@ +Raspberry Pi VideoCore firmware driver + +Required properties: + +- compatible: Should be "raspberrypi,bcm2835-firmware" +- mboxes: Phandle to the firmware device's Mailbox. + (See: ../mailbox/mailbox.txt for more information) + +Example: + +firmware { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; +}; -- cgit v1.2.3-59-g8ed1b From 78bdcad05ea17fa1fe4644324b877162b1df4e16 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 28 Jul 2015 19:09:09 +0530 Subject: PCI: dra7xx: Add support to make GPIO drive PERST# line The PERST# line in am57x-evm is connected to a GPIO line and PERST# should be driven high to indicate the clocks are stable (As per Figure 2-10: Power Up of the PCIe CEM spec 3.0). Add support to make GPIO drive PERST# line. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas --- Documentation/devicetree/bindings/pci/ti-pci.txt | 3 +++ drivers/pci/host/pci-dra7xx.c | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt index 3d217911b313..60e25161f351 100644 --- a/Documentation/devicetree/bindings/pci/ti-pci.txt +++ b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -23,6 +23,9 @@ PCIe Designware Controller interrupt-map-mask, interrupt-map : as specified in ../designware-pcie.txt +Optional Property: + - gpios : Should be added if a gpio line is required to drive PERST# line + Example: axi { compatible = "simple-bus"; diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 3772aff7df4f..abb85a157ce0 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -336,6 +337,9 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; char name[10]; + int gpio_sel; + enum of_gpio_flags flags; + unsigned long gpio_flags; dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); if (!dra7xx) @@ -398,6 +402,22 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) goto err_get_sync; } + gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags); + if (gpio_is_valid(gpio_sel)) { + gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH; + ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags, + "pcie_reset"); + if (ret) { + dev_err(&pdev->dev, "gpio%d request failed, ret %d\n", + gpio_sel, ret); + goto err_gpio; + } + } else if (gpio_sel == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_gpio; + } + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); reg &= ~LTSSM_EN; dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); @@ -406,11 +426,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) ret = dra7xx_add_pcie_port(dra7xx, pdev); if (ret < 0) - goto err_add_port; + goto err_gpio; return 0; -err_add_port: +err_gpio: pm_runtime_put(dev); err_get_sync: -- cgit v1.2.3-59-g8ed1b From 8bc964aa25e56b7445ffebffccd455f959370a16 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 14:28:03 +0200 Subject: clk: shmobile: r8a7778: Add CPG/MSTP Clock Domain support Add Clock Domain support to the R-Car M1A Clock Pulse Generator (CPG) driver using the generic PM Domain. This allows to power-manage the module clocks of SoC devices that are part of the CPG/MSTP Clock Domain using Runtime PM, or for system suspend/resume. SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed through an MSTP clock should be tagged in DT with a proper "power-domains" property. Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Reviewed-by: Ulf Hansson Signed-off-by: Simon Horman --- .../bindings/clock/renesas,r8a7778-cpg-clocks.txt | 29 +++++++++++++++++++--- arch/arm/mach-shmobile/Kconfig | 1 + drivers/clk/shmobile/clk-r8a7778.c | 2 ++ 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt index 2f3747fdcf1c..e4cdaf1cb333 100644 --- a/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt @@ -1,7 +1,9 @@ * Renesas R8A7778 Clock Pulse Generator (CPG) The CPG generates core clocks for the R8A7778. It includes two PLLs and -several fixed ratio dividers +several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. Required Properties: @@ -10,10 +12,18 @@ Required Properties: - #clock-cells: Must be 1 - clock-output-names: The names of the clocks. Supported clocks are "plla", "pllb", "b", "out", "p", "s", and "s1". + - #power-domain-cells: Must be 0 +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock 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.txt. -Example -------- + +Examples +-------- + + - CPG device node: cpg_clocks: cpg_clocks@ffc80000 { compatible = "renesas,r8a7778-cpg-clocks"; @@ -22,4 +32,17 @@ Example clocks = <&extal_clk>; clock-output-names = "plla", "pllb", "b", "out", "p", "s", "s1"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + sdhi0: sd@ffe4c000 { + compatible = "renesas,sdhi-r8a7778"; + reg = <0xffe4c000 0x100>; + interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7778_CLK_SDHI0>; + power-domains = <&cpg_clocks>; + status = "disabled"; }; diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 45006479d461..e14fa5e87475 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -4,6 +4,7 @@ config ARCH_SHMOBILE config PM_RCAR bool + select PM_GENERIC_DOMAINS if PM config PM_RMOBILE bool diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c index cb33b57274bf..fa45684e220c 100644 --- a/drivers/clk/shmobile/clk-r8a7778.c +++ b/drivers/clk/shmobile/clk-r8a7778.c @@ -124,6 +124,8 @@ static void __init r8a7778_cpg_clocks_init(struct device_node *np) } of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); + + cpg_mstp_add_clk_domain(np); } CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks", -- cgit v1.2.3-59-g8ed1b From b31fc90c14d9e584ac19983686cecab3e0764289 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 14:28:04 +0200 Subject: clk: shmobile: r8a7779: Add CPG/MSTP Clock Domain support Add Clock Domain support to the R-Car H1 Clock Pulse Generator (CPG) driver using the generic PM Domain. This allows to power-manage the module clocks of SoC devices that are part of the CPG/MSTP Clock Domain using Runtime PM, or for system suspend/resume. SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed through an MSTP clock should be tagged in DT with a proper "power-domains" property. Also update the reg property in the DT binding doc example to match the actual dtsi, which uses #address-cells and #size-cells == 1, not 2. Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Reviewed-by: Ulf Hansson Signed-off-by: Simon Horman --- .../bindings/clock/renesas,r8a7779-cpg-clocks.txt | 30 +++++++++++++++++++--- drivers/clk/shmobile/clk-r8a7779.c | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt index ed3c8cb12f4e..8c81547c29f5 100644 --- a/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt @@ -1,7 +1,9 @@ * Renesas R8A7779 Clock Pulse Generator (CPG) The CPG generates core clocks for the R8A7779. It includes one PLL and -several fixed ratio dividers +several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. Required Properties: @@ -12,16 +14,36 @@ Required Properties: - #clock-cells: Must be 1 - clock-output-names: The names of the clocks. Supported clocks are "plla", "z", "zs", "s", "s1", "p", "b", "out". + - #power-domain-cells: Must be 0 +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock 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.txt. -Example -------- + +Examples +-------- + + - CPG device node: cpg_clocks: cpg_clocks@ffc80000 { compatible = "renesas,r8a7779-cpg-clocks"; - reg = <0 0xffc80000 0 0x30>; + reg = <0xffc80000 0x30>; clocks = <&extal_clk>; #clock-cells = <1>; clock-output-names = "plla", "z", "zs", "s", "s1", "p", "b", "out"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + sata: sata@fc600000 { + compatible = "renesas,sata-r8a7779", "renesas,rcar-sata"; + reg = <0xfc600000 0x2000>; + interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7779_CLK_SATA>; + power-domains = <&cpg_clocks>; }; diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c index 652ecacb6daf..e42a63a2ad25 100644 --- a/drivers/clk/shmobile/clk-r8a7779.c +++ b/drivers/clk/shmobile/clk-r8a7779.c @@ -168,6 +168,8 @@ static void __init r8a7779_cpg_clocks_init(struct device_node *np) } of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); + + cpg_mstp_add_clk_domain(np); } CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks", r8a7779_cpg_clocks_init); -- cgit v1.2.3-59-g8ed1b From 63e05d9365dc25ae71bdde436b27c49daedf1977 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 14:28:05 +0200 Subject: clk: shmobile: rcar-gen2: Add CPG/MSTP Clock Domain support Add Clock Domain support to the R-Car Gen2 Clock Pulse Generator (CPG) driver using the generic PM Domain. This allows to power-manage the module clocks of SoC devices that are part of the CPG/MSTP Clock Domain using Runtime PM, or for system suspend/resume. SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed through an MSTP clock should be tagged in DT with a proper "power-domains" property. Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Reviewed-by: Ulf Hansson Signed-off-by: Simon Horman --- .../clock/renesas,rcar-gen2-cpg-clocks.txt | 26 ++++++++++++++++++++-- drivers/clk/shmobile/clk-rcar-gen2.c | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt index 56f111bd3e45..2a9a8edc8f35 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt @@ -2,6 +2,8 @@ The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs and several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. Required Properties: @@ -20,10 +22,18 @@ Required Properties: - clock-output-names: The names of the clocks. Supported clocks are "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", and "adsp" + - #power-domain-cells: Must be 0 +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock 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.txt. -Example -------- + +Examples +-------- + + - CPG device node: cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7790-cpg-clocks", @@ -34,4 +44,16 @@ Example clock-output-names = "main", "pll0, "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", "adsp"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + thermal@e61f0000 { + compatible = "renesas,thermal-r8a7790", "renesas,rcar-thermal"; + reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>; + interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks R8A7790_CLK_THERMAL>; + power-domains = <&cpg_clocks>; }; diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index acfb6d7dbd6b..f2c457f494eb 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -415,6 +415,8 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) } of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); + + cpg_mstp_add_clk_domain(np); } CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks", rcar_gen2_cpg_clocks_init); -- cgit v1.2.3-59-g8ed1b From f04b486d34ac6bab2aaa3988ee098b2bad3950de Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 14:28:06 +0200 Subject: clk: shmobile: rz: Add CPG/MSTP Clock Domain support Add Clock Domain support to the RZ Clock Pulse Generator (CPG) driver using the generic PM Domain. This allows to power-manage the module clocks of SoC devices that are part of the CPG/MSTP Clock Domain using Runtime PM, or for system suspend/resume. SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed through an MSTP clock should be tagged in DT with a proper "power-domains" property. Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Reviewed-by: Ulf Hansson Signed-off-by: Simon Horman --- .../bindings/clock/renesas,rz-cpg-clocks.txt | 29 ++++++++++++++++++++-- arch/arm/mach-shmobile/Kconfig | 1 + drivers/clk/shmobile/clk-rz.c | 3 +++ 3 files changed, 31 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt index b0f7ddb8cdb1..bb51a33a1fbf 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt @@ -2,6 +2,8 @@ The CPG generates core clocks for the RZ SoCs. It includes the PLL, variable CPU and GPU clocks, and several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. Required Properties: @@ -14,10 +16,18 @@ Required Properties: - #clock-cells: Must be 1 - clock-output-names: The names of the clocks. Supported clocks are "pll", "i", and "g" + - #power-domain-cells: Must be 0 +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock 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.txt. -Example -------- + +Examples +-------- + + - CPG device node: cpg_clocks: cpg_clocks@fcfe0000 { #clock-cells = <1>; @@ -26,4 +36,19 @@ Example reg = <0xfcfe0000 0x18>; clocks = <&extal_clk>, <&usb_x1_clk>; clock-output-names = "pll", "i", "g"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + mtu2: timer@fcff0000 { + compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; + reg = <0xfcff0000 0x400>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tgi0a"; + clocks = <&mstp3_clks R7S72100_CLK_MTU2>; + clock-names = "fck"; + power-domains = <&cpg_clocks>; + status = "disabled"; }; diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index e14fa5e87475..34eac88a9889 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -51,6 +51,7 @@ config ARCH_EMEV2 config ARCH_R7S72100 bool "RZ/A1H (R7S72100)" + select PM_GENERIC_DOMAINS if PM select SYS_SUPPORTS_SH_MTU2 config ARCH_R8A73A4 diff --git a/drivers/clk/shmobile/clk-rz.c b/drivers/clk/shmobile/clk-rz.c index 7e68e8630962..9766e3cb595f 100644 --- a/drivers/clk/shmobile/clk-rz.c +++ b/drivers/clk/shmobile/clk-rz.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -99,5 +100,7 @@ static void __init rz_cpg_clocks_init(struct device_node *np) } of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); + + cpg_mstp_add_clk_domain(np); } CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init); -- cgit v1.2.3-59-g8ed1b From 05743b3a09e905b4b09681639fa386feb6a96b5a Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 7 Aug 2015 10:37:19 +0530 Subject: ARM: dts: AM4372: Add the am4372-rtc compatible string am4372-rtc string was already part of dts, introduced to identify the rtc specific to am4372 family of SoCs. It was removed in one of the previous patches. Adding back the same with appropriate documentation. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 1 + arch/arm/boot/dts/am4372.dtsi | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index 4ba4dbd34289..43a83668673a 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -8,6 +8,7 @@ Required properties: Wakeup generation for event Alarm. It can also be used to control an external PMIC via the pmic_power_en pin. + - "ti,am4372-rtc" - for RTC IP used similar to that on AM437X SoC family. - reg: Address range of rtc register set - interrupts: rtc timer, alarm interrupts in order - interrupt-parent: phandle for the interrupt controller diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 15fbc56596cc..6bc8b49bfaaf 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -330,7 +330,8 @@ }; rtc: rtc@44e3e000 { - compatible = "ti,am3352-rtc", "ti,da830-rtc"; + compatible = "ti,am4372-rtc", "ti,am3352-rtc", + "ti,da830-rtc"; reg = <0x44e3e000 0x1000>; interrupts = ; -- cgit v1.2.3-59-g8ed1b From bf89386f166b18c21b2b7a2c5b6e496726c4f25f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 10:29:45 -0700 Subject: hwmon: (ltc2978) Add support for LTC3882 LTC3882 is mostly compatible with LTC3880. Major differences are that it does not measure the input current, and it no longer supports LTC's legacy mechanism to identify the chip. Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 +- Documentation/hwmon/ltc2978 | 26 ++++++----- drivers/hwmon/pmbus/ltc2978.c | 50 +++++++++++++++++++--- 3 files changed, 62 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index ed2f09dc2483..230389f6c984 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -6,6 +6,7 @@ Required properties: * "lltc,ltc2977" * "lltc,ltc2978" * "lltc,ltc3880" + * "lltc,ltc3882" * "lltc,ltc3883" * "lltc,ltm4676" - reg: I2C slave address @@ -20,7 +21,7 @@ Valid names of regulators depend on number of supplies supported per device: * ltc2974 : vout0 - vout3 * ltc2977 : vout0 - vout7 * ltc2978 : vout0 - vout7 - * ltc3880 : vout0 - vout1 + * ltc3880, ltc3882 : vout0 - vout1 * ltc3883 : vout0 * ltm4676 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 686c078bb0e0..521ee8a1135c 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -19,6 +19,10 @@ Supported chips: Prefix: 'ltc3880' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3880 + * Linear Technology LTC3882 + Prefix: 'ltc3882' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3882 * Linear Technology LTC3883 Prefix: 'ltc3883' Addresses scanned: - @@ -34,11 +38,12 @@ Author: Guenter Roeck Description ----------- -LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply -monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual -output poly-phase step-down DC/DC controller. LTC3883 is a single phase -step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule -regulator. +LTC2974 is a quad digital power supply managers. +LTC2978 is an octal power supply monitor. +LTC2977 is a pin compatible replacement for LTC2978. +LTC3880 and LTC3882 are dual output poly-phase step-down DC/DC controllers. +LTC3883 is a single phase step-down DC/DC controller. +LTM4676 is a dual 13A or single 26A uModule regulator. Usage Notes @@ -80,7 +85,7 @@ in[N]_label "vout[1-8]". LTC2974: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 - LTC3880, LTM4676: N=2-3 + LTC3880, LTC3882, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -100,8 +105,9 @@ temp[N]_input Measured temperature. and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. - On LTC3880 and LTM4676, temp1 and temp2 report external - temperatures, and temp3 reports the chip temperature. + On LTC3880, LTC3882, and LTM4676, temp1 and temp2 + report external temperatures, and temp3 reports + the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. temp[N]_min Mimimum temperature. LTC2974, LCT2977, and LTC2978 only. @@ -128,7 +134,7 @@ power[N]_label "pout[1-4]". LTC2974: N=1-4 LTC2977: Not supported LTC2978: Not supported - LTC3880, LTM4676: N=1-2 + LTC3880, LTC3882, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. @@ -143,7 +149,7 @@ curr[N]_label "iout[1-4]". LTC2974: N=1-4 LTC2977: not supported LTC2978: not supported - LTC3880, LTM4676: N=2-3 + LTC3880, LTC3882, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7e10fbf8e133..28e1e735b5c2 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -25,13 +25,13 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd #define LTC2978_MFR_VIN_PEAK 0xde #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf -#define LTC2978_MFR_SPECIAL_ID 0xe7 +#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ /* LTC2974, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb @@ -42,7 +42,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3883, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -313,7 +313,7 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3883 || id == ltm4676) + if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); @@ -369,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, + {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, {"ltm4676", ltm4676}, {} @@ -393,8 +394,30 @@ static int ltc2978_get_id(struct i2c_client *client) int chip_id; chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); - if (chip_id < 0) - return chip_id; + if (chip_id < 0) { + const struct i2c_device_id *id; + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (ret < 0) + return ret; + if (ret < 3 || strncmp(buf, "LTC", 3)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (ret < 0) + return ret; + for (id = <c2978_id[0]; strlen(id->name); id++) { + if (!strncasecmp(id->name, buf, strlen(id->name))) + return (int)id->driver_data; + } + return -ENODEV; + } if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) return ltc2974; @@ -498,6 +521,20 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; + case ltc3882: + info->read_word_data = ltc3880_read_word_data; + info->pages = LTC3880_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; case ltc3883: info->read_word_data = ltc3883_read_word_data; info->pages = LTC3883_NUM_PAGES; @@ -530,6 +567,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, { .compatible = "lltc,ltc3880" }, + { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, { .compatible = "lltc,ltm4676" }, { } -- cgit v1.2.3-59-g8ed1b From 15398566f0ea95c66d202b8705dba4f59b9ba01c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Aug 2015 09:06:37 -0700 Subject: hwmon: (ltc2978) Add support for LTC3887 LTC3887 is an enhanced version of LTC3880 and supports the same commands. Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ltc2978.txt | 1 + Documentation/hwmon/ltc2978 | 19 ++++++++++++------- drivers/hwmon/pmbus/Kconfig | 3 ++- drivers/hwmon/pmbus/ltc2978.c | 19 ++++++++++++++----- 4 files changed, 29 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index 230389f6c984..c1d23c14ddd9 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -8,6 +8,7 @@ Required properties: * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" + * "lltc,ltc3887" * "lltc,ltm4676" - reg: I2C slave address diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 521ee8a1135c..ff130997f22e 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -27,6 +27,10 @@ Supported chips: Prefix: 'ltc3883' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3883 + * Linear Technology LTC3887 + Prefix: 'ltc3887' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3887 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -41,7 +45,8 @@ Description LTC2974 is a quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. -LTC3880 and LTC3882 are dual output poly-phase step-down DC/DC controllers. +LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC +controllers. LTC3883 is a single phase step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule regulator. @@ -85,7 +90,7 @@ in[N]_label "vout[1-8]". LTC2974: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -105,8 +110,8 @@ temp[N]_input Measured temperature. and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. - On LTC3880, LTC3882, and LTM4676, temp1 and temp2 - report external temperatures, and temp3 reports + On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and + temp2 report external temperatures, and temp3 reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. @@ -134,11 +139,11 @@ power[N]_label "pout[1-4]". LTC2974: N=1-4 LTC2977: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, and LTM4676 only. +curr1_label "iin". LTC3880, LTC3883, LTC3887, and LTM4676 only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. @@ -149,7 +154,7 @@ curr[N]_label "iout[1-4]". LTC2974: N=1-4 LTC2977: not supported LTC2978: not supported - LTC3880, LTC3882, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 2b3242cc7779..43b6de900ce5 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,7 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676. + Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTC3887, + and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index acbfe3ec2ffd..0756d8ae9dad 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,6 +1,6 @@ /* * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, - * LTC3883, and LTM4676 + * LTC3883, LTC3887. and LTM4676 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013, 2014 Guenter Roeck @@ -25,7 +25,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, + ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -42,7 +43,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -60,9 +61,11 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; #define LTC3880_ID_MASK 0xff00 #define LTC3883_ID 0x4300 #define LTC3883_ID_MASK 0xff00 +#define LTC3887_ID 0x4700 +#define LTC3887_ID_MASK 0xff00 #define LTM4676_ID 0x4400 #define LTM4676_ID_2 0x4480 -#define LTM4676A_ID 0x47E0 +#define LTM4676A_ID 0x47e0 #define LTM4676_ID_MASK 0xfff0 #define LTC2974_NUM_PAGES 4 @@ -315,7 +318,8 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltm4676) + if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltc3887 || + id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); @@ -373,6 +377,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, + {"ltc3887", ltc3887}, {"ltm4676", ltm4676}, {} }; @@ -432,6 +437,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3880; else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) return ltc3883; + else if ((chip_id & LTC3887_ID_MASK) == LTC3887_ID) + return ltc3887; else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID || (chip_id & LTM4676_ID_MASK) == LTM4676_ID_2 || (chip_id & LTM4676_ID_MASK) == LTM4676A_ID) @@ -511,6 +518,7 @@ static int ltc2978_probe(struct i2c_client *client, } break; case ltc3880: + case ltc3887: case ltm4676: info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; @@ -573,6 +581,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, + { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.2.3-59-g8ed1b From ca6bc691b1b7cf45862410952806f73c1aa62fe6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 11 Aug 2015 13:32:55 +0800 Subject: crypto: sunxi-ss - Document optional reset control bindings Later Allwinner SoCs split out the reset controls for individual modules out of the clock gate controls. The "Security System" crypto engine is no different. Signed-off-by: Chen-Yu Tsai Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/sun4i-ss.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/sun4i-ss.txt b/Documentation/devicetree/bindings/crypto/sun4i-ss.txt index 1e02d177fea6..5d38e9b7033f 100644 --- a/Documentation/devicetree/bindings/crypto/sun4i-ss.txt +++ b/Documentation/devicetree/bindings/crypto/sun4i-ss.txt @@ -9,6 +9,10 @@ Required properties: * "ahb" : AHB gating clock * "mod" : SS controller clock +Optional properties: + - resets : phandle + reset specifier pair + - reset-names : must contain "ahb" + Example: crypto: crypto-engine@01c15000 { compatible = "allwinner,sun4i-a10-crypto"; -- cgit v1.2.3-59-g8ed1b From 2ec3182f9c20a9eef0dacc0512cf2ca2df7be5ad Mon Sep 17 00:00:00 2001 From: Dongsu Park Date: Fri, 19 Dec 2014 14:53:03 +0100 Subject: Documentation: update notes in biovecs about arbitrarily sized bios Update block/biovecs.txt so that it includes a note on what kind of effects arbitrarily sized bios would bring to the block layer. Also fix a trivial typo, bio_iter_iovec. Cc: Christoph Hellwig Cc: Kent Overstreet Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Dongsu Park Signed-off-by: Ming Lin Signed-off-by: Jens Axboe --- Documentation/block/biovecs.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt index 74a32ad52f53..25689584e6e0 100644 --- a/Documentation/block/biovecs.txt +++ b/Documentation/block/biovecs.txt @@ -24,7 +24,7 @@ particular, presenting the illusion of partially completed biovecs so that normal code doesn't have to deal with bi_bvec_done. * Driver code should no longer refer to biovecs directly; we now have - bio_iovec() and bio_iovec_iter() macros that return literal struct biovecs, + bio_iovec() and bio_iter_iovec() macros that return literal struct biovecs, constructed from the raw biovecs but taking into account bi_bvec_done and bi_size. @@ -109,3 +109,11 @@ Other implications: over all the biovecs in the new bio - which is silly as it's not needed. So, don't use bi_vcnt anymore. + + * The current interface allows the block layer to split bios as needed, so we + could eliminate a lot of complexity particularly in stacked drivers. Code + that creates bios can then create whatever size bios are convenient, and + more importantly stacked drivers don't have to deal with both their own bio + size limitations and the limitations of the underlying devices. Thus + there's no need to define ->merge_bvec_fn() callbacks for individual block + drivers. -- cgit v1.2.3-59-g8ed1b From 81db32a3c4627605a0e950d27a403ea02447ab60 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Mon, 10 Aug 2015 15:16:16 -0700 Subject: doc: Add more workqueue functions to the documentation There are some workqueue functions declared in workqueue.h, so include that in the workqueue section of the DocBook docs. Signed-off-by: Tim Bird Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet --- Documentation/DocBook/device-drivers.tmpl | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index faf09d4a0ea8..bbc1d7ee9c76 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -66,6 +66,7 @@ !Ekernel/time/hrtimer.c
Workqueues and Kevents +!Iinclude/linux/workqueue.h !Ekernel/workqueue.c Internal Functions -- cgit v1.2.3-59-g8ed1b From 4983953dbd038fd720e7e16eb9bad5d8ea059ccf Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Mon, 10 Aug 2015 09:00:44 +0100 Subject: Documentation: describe how to add a system call Add a document describing the process of adding a new system call, including the need for a flags argument for future compatibility, and covering 32-bit/64-bit concerns (albeit in an x86-centric way). Signed-off-by: David Drysdale Reviewed-by: Michael Kerrisk Reviewed-by: Eric B Munson Reviewed-by: Kees Cook Reviewed-by: Randy Dunlap Reviewed-by: Josh Triplett Signed-off-by: Jonathan Corbet --- Documentation/adding-syscalls.txt | 527 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 Documentation/adding-syscalls.txt (limited to 'Documentation') diff --git a/Documentation/adding-syscalls.txt b/Documentation/adding-syscalls.txt new file mode 100644 index 000000000000..cc2d4ac4f404 --- /dev/null +++ b/Documentation/adding-syscalls.txt @@ -0,0 +1,527 @@ +Adding a New System Call +======================== + +This document describes what's involved in adding a new system call to the +Linux kernel, over and above the normal submission advice in +Documentation/SubmittingPatches. + + +System Call Alternatives +------------------------ + +The first thing to consider when adding a new system call is whether one of +the alternatives might be suitable instead. Although system calls are the +most traditional and most obvious interaction points between userspace and the +kernel, there are other possibilities -- choose what fits best for your +interface. + + - If the operations involved can be made to look like a filesystem-like + object, it may make more sense to create a new filesystem or device. This + also makes it easier to encapsulate the new functionality in a kernel module + rather than requiring it to be built into the main kernel. + - If the new functionality involves operations where the kernel notifies + userspace that something has happened, then returning a new file + descriptor for the relevant object allows userspace to use + poll/select/epoll to receive that notification. + - However, operations that don't map to read(2)/write(2)-like operations + have to be implemented as ioctl(2) requests, which can lead to a + somewhat opaque API. + - If you're just exposing runtime system information, a new node in sysfs + (see Documentation/filesystems/sysfs.txt) or the /proc filesystem may be + more appropriate. However, access to these mechanisms requires that the + relevant filesystem is mounted, which might not always be the case (e.g. + in a namespaced/sandboxed/chrooted environment). Avoid adding any API to + debugfs, as this is not considered a 'production' interface to userspace. + - If the operation is specific to a particular file or file descriptor, then + an additional fcntl(2) command option may be more appropriate. However, + fcntl(2) is a multiplexing system call that hides a lot of complexity, so + this option is best for when the new function is closely analogous to + existing fcntl(2) functionality, or the new functionality is very simple + (for example, getting/setting a simple flag related to a file descriptor). + - If the operation is specific to a particular task or process, then an + additional prctl(2) command option may be more appropriate. As with + fcntl(2), this system call is a complicated multiplexor so is best reserved + for near-analogs of existing prctl() commands or getting/setting a simple + flag related to a process. + + +Designing the API: Planning for Extension +----------------------------------------- + +A new system call forms part of the API of the kernel, and has to be supported +indefinitely. As such, it's a very good idea to explicitly discuss the +interface on the kernel mailing list, and it's important to plan for future +extensions of the interface. + +(The syscall table is littered with historical examples where this wasn't done, +together with the corresponding follow-up system calls -- eventfd/eventfd2, +dup2/dup3, inotify_init/inotify_init1, pipe/pipe2, renameat/renameat2 -- so +learn from the history of the kernel and plan for extensions from the start.) + +For simpler system calls that only take a couple of arguments, the preferred +way to allow for future extensibility is to include a flags argument to the +system call. To make sure that userspace programs can safely use flags +between kernel versions, check whether the flags value holds any unknown +flags, and reject the system call (with EINVAL) if it does: + + if (flags & ~(THING_FLAG1 | THING_FLAG2 | THING_FLAG3)) + return -EINVAL; + +(If no flags values are used yet, check that the flags argument is zero.) + +For more sophisticated system calls that involve a larger number of arguments, +it's preferred to encapsulate the majority of the arguments into a structure +that is passed in by pointer. Such a structure can cope with future extension +by including a size argument in the structure: + + struct xyzzy_params { + u32 size; /* userspace sets p->size = sizeof(struct xyzzy_params) */ + u32 param_1; + u64 param_2; + u64 param_3; + }; + +As long as any subsequently added field, say param_4, is designed so that a +zero value gives the previous behaviour, then this allows both directions of +version mismatch: + + - To cope with a later userspace program calling an older kernel, the kernel + code should check that any memory beyond the size of the structure that it + expects is zero (effectively checking that param_4 == 0). + - To cope with an older userspace program calling a newer kernel, the kernel + code can zero-extend a smaller instance of the structure (effectively + setting param_4 = 0). + +See perf_event_open(2) and the perf_copy_attr() function (in +kernel/events/core.c) for an example of this approach. + + +Designing the API: Other Considerations +--------------------------------------- + +If your new system call allows userspace to refer to a kernel object, it +should use a file descriptor as the handle for that object -- don't invent a +new type of userspace object handle when the kernel already has mechanisms and +well-defined semantics for using file descriptors. + +If your new xyzzy(2) system call does return a new file descriptor, then the +flags argument should include a value that is equivalent to setting O_CLOEXEC +on the new FD. This makes it possible for userspace to close the timing +window between xyzzy() and calling fcntl(fd, F_SETFD, FD_CLOEXEC), where an +unexpected fork() and execve() in another thread could leak a descriptor to +the exec'ed program. (However, resist the temptation to re-use the actual value +of the O_CLOEXEC constant, as it is architecture-specific and is part of a +numbering space of O_* flags that is fairly full.) + +If your system call returns a new file descriptor, you should also consider +what it means to use the poll(2) family of system calls on that file +descriptor. Making a file descriptor ready for reading or writing is the +normal way for the kernel to indicate to userspace that an event has +occurred on the corresponding kernel object. + +If your new xyzzy(2) system call involves a filename argument: + + int sys_xyzzy(const char __user *path, ..., unsigned int flags); + +you should also consider whether an xyzzyat(2) version is more appropriate: + + int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags); + +This allows more flexibility for how userspace specifies the file in question; +in particular it allows userspace to request the functionality for an +already-opened file descriptor using the AT_EMPTY_PATH flag, effectively giving +an fxyzzy(3) operation for free: + + - xyzzyat(AT_FDCWD, path, ..., 0) is equivalent to xyzzy(path,...) + - xyzzyat(fd, "", ..., AT_EMPTY_PATH) is equivalent to fxyzzy(fd, ...) + +(For more details on the rationale of the *at() calls, see the openat(2) man +page; for an example of AT_EMPTY_PATH, see the statat(2) man page.) + +If your new xyzzy(2) system call involves a parameter describing an offset +within a file, make its type loff_t so that 64-bit offsets can be supported +even on 32-bit architectures. + +If your new xyzzy(2) system call involves privileged functionality, it needs +to be governed by the appropriate Linux capability bit (checked with a call to +capable()), as described in the capabilities(7) man page. Choose an existing +capability bit that governs related functionality, but try to avoid combining +lots of only vaguely related functions together under the same bit, as this +goes against capabilities' purpose of splitting the power of root. In +particular, avoid adding new uses of the already overly-general CAP_SYS_ADMIN +capability. + +If your new xyzzy(2) system call manipulates a process other than the calling +process, it should be restricted (using a call to ptrace_may_access()) so that +only a calling process with the same permissions as the target process, or +with the necessary capabilities, can manipulate the target process. + +Finally, be aware that some non-x86 architectures have an easier time if +system call parameters that are explicitly 64-bit fall on odd-numbered +arguments (i.e. parameter 1, 3, 5), to allow use of contiguous pairs of 32-bit +registers. (This concern does not apply if the arguments are part of a +structure that's passed in by pointer.) + + +Proposing the API +----------------- + +To make new system calls easy to review, it's best to divide up the patchset +into separate chunks. These should include at least the following items as +distinct commits (each of which is described further below): + + - The core implementation of the system call, together with prototypes, + generic numbering, Kconfig changes and fallback stub implementation. + - Wiring up of the new system call for one particular architecture, usually + x86 (including all of x86_64, x86_32 and x32). + - A demonstration of the use of the new system call in userspace via a + selftest in tools/testing/selftests/. + - A draft man-page for the new system call, either as plain text in the + cover letter, or as a patch to the (separate) man-pages repository. + +New system call proposals, like any change to the kernel's API, should always +be cc'ed to linux-api@vger.kernel.org. + + +Generic System Call Implementation +---------------------------------- + +The main entry point for your new xyzzy(2) system call will be called +sys_xyzzy(), but you add this entry point with the appropriate +SYSCALL_DEFINEn() macro rather than explicitly. The 'n' indicates the number +of arguments to the system call, and the macro takes the system call name +followed by the (type, name) pairs for the parameters as arguments. Using +this macro allows metadata about the new system call to be made available for +other tools. + +The new entry point also needs a corresponding function prototype, in +include/linux/syscalls.h, marked as asmlinkage to match the way that system +calls are invoked: + + asmlinkage long sys_xyzzy(...); + +Some architectures (e.g. x86) have their own architecture-specific syscall +tables, but several other architectures share a generic syscall table. Add your +new system call to the generic list by adding an entry to the list in +include/uapi/asm-generic/unistd.h: + + #define __NR_xyzzy 292 + __SYSCALL(__NR_xyzzy, sys_xyzzy) + +Also update the __NR_syscalls count to reflect the additional system call, and +note that if multiple new system calls are added in the same merge window, +your new syscall number may get adjusted to resolve conflicts. + +The file kernel/sys_ni.c provides a fallback stub implementation of each system +call, returning -ENOSYS. Add your new system call here too: + + cond_syscall(sys_xyzzy); + +Your new kernel functionality, and the system call that controls it, should +normally be optional, so add a CONFIG option (typically to init/Kconfig) for +it. As usual for new CONFIG options: + + - Include a description of the new functionality and system call controlled + by the option. + - Make the option depend on EXPERT if it should be hidden from normal users. + - Make any new source files implementing the function dependent on the CONFIG + option in the Makefile (e.g. "obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.c"). + - Double check that the kernel still builds with the new CONFIG option turned + off. + +To summarize, you need a commit that includes: + + - CONFIG option for the new function, normally in init/Kconfig + - SYSCALL_DEFINEn(xyzzy, ...) for the entry point + - corresponding prototype in include/linux/syscalls.h + - generic table entry in include/uapi/asm-generic/unistd.h + - fallback stub in kernel/sys_ni.c + + +x86 System Call Implementation +------------------------------ + +To wire up your new system call for x86 platforms, you need to update the +master syscall tables. Assuming your new system call isn't special in some +way (see below), this involves a "common" entry (for x86_64 and x32) in +arch/x86/entry/syscalls/syscall_64.tbl: + + 333 common xyzzy sys_xyzzy + +and an "i386" entry in arch/x86/entry/syscalls/syscall_32.tbl: + + 380 i386 xyzzy sys_xyzzy + +Again, these numbers are liable to be changed if there are conflicts in the +relevant merge window. + + +Compatibility System Calls (Generic) +------------------------------------ + +For most system calls the same 64-bit implementation can be invoked even when +the userspace program is itself 32-bit; even if the system call's parameters +include an explicit pointer, this is handled transparently. + +However, there are a couple of situations where a compatibility layer is +needed to cope with size differences between 32-bit and 64-bit. + +The first is if the 64-bit kernel also supports 32-bit userspace programs, and +so needs to parse areas of (__user) memory that could hold either 32-bit or +64-bit values. In particular, this is needed whenever a system call argument +is: + + - a pointer to a pointer + - a pointer to a struct containing a pointer (e.g. struct iovec __user *) + - a pointer to a varying sized integral type (time_t, off_t, long, ...) + - a pointer to a struct containing a varying sized integral type. + +The second situation that requires a compatibility layer is if one of the +system call's arguments has a type that is explicitly 64-bit even on a 32-bit +architecture, for example loff_t or __u64. In this case, a value that arrives +at a 64-bit kernel from a 32-bit application will be split into two 32-bit +values, which then need to be re-assembled in the compatibility layer. + +(Note that a system call argument that's a pointer to an explicit 64-bit type +does *not* need a compatibility layer; for example, splice(2)'s arguments of +type loff_t __user * do not trigger the need for a compat_ system call.) + +The compatibility version of the system call is called compat_sys_xyzzy(), and +is added with the COMPAT_SYSCALL_DEFINEn() macro, analogously to +SYSCALL_DEFINEn. This version of the implementation runs as part of a 64-bit +kernel, but expects to receive 32-bit parameter values and does whatever is +needed to deal with them. (Typically, the compat_sys_ version converts the +values to 64-bit versions and either calls on to the sys_ version, or both of +them call a common inner implementation function.) + +The compat entry point also needs a corresponding function prototype, in +include/linux/compat.h, marked as asmlinkage to match the way that system +calls are invoked: + + asmlinkage long compat_sys_xyzzy(...); + +If the system call involves a structure that is laid out differently on 32-bit +and 64-bit systems, say struct xyzzy_args, then the include/linux/compat.h +header file should also include a compat version of the structure (struct +compat_xyzzy_args) where each variable-size field has the appropriate compat_ +type that corresponds to the type in struct xyzzy_args. The +compat_sys_xyzzy() routine can then use this compat_ structure to parse the +arguments from a 32-bit invocation. + +For example, if there are fields: + + struct xyzzy_args { + const char __user *ptr; + __kernel_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +in struct xyzzy_args, then struct compat_xyzzy_args would have: + + struct compat_xyzzy_args { + compat_uptr_t ptr; + compat_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +The generic system call list also needs adjusting to allow for the compat +version; the entry in include/uapi/asm-generic/unistd.h should use +__SC_COMP rather than __SYSCALL: + + #define __NR_xyzzy 292 + __SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy) + +To summarize, you need: + + - a COMPAT_SYSCALL_DEFINEn(xyzzy, ...) for the compat entry point + - corresponding prototype in include/linux/compat.h + - (if needed) 32-bit mapping struct in include/linux/compat.h + - instance of __SC_COMP not __SYSCALL in include/uapi/asm-generic/unistd.h + + +Compatibility System Calls (x86) +-------------------------------- + +To wire up the x86 architecture of a system call with a compatibility version, +the entries in the syscall tables need to be adjusted. + +First, the entry in arch/x86/entry/syscalls/syscall_32.tbl gets an extra +column to indicate that a 32-bit userspace program running on a 64-bit kernel +should hit the compat entry point: + + 380 i386 xyzzy sys_xyzzy compat_sys_xyzzy + +Second, you need to figure out what should happen for the x32 ABI version of +the new system call. There's a choice here: the layout of the arguments +should either match the 64-bit version or the 32-bit version. + +If there's a pointer-to-a-pointer involved, the decision is easy: x32 is +ILP32, so the layout should match the 32-bit version, and the entry in +arch/x86/entry/syscalls/syscall_64.tbl is split so that x32 programs hit the +compatibility wrapper: + + 333 64 xyzzy sys_xyzzy + ... + 555 x32 xyzzy compat_sys_xyzzy + +If no pointers are involved, then it is preferable to re-use the 64-bit system +call for the x32 ABI (and consequently the entry in +arch/x86/entry/syscalls/syscall_64.tbl is unchanged). + +In either case, you should check that the types involved in your argument +layout do indeed map exactly from x32 (-mx32) to either the 32-bit (-m32) or +64-bit (-m64) equivalents. + + +System Calls Returning Elsewhere +-------------------------------- + +For most system calls, once the system call is complete the user program +continues exactly where it left off -- at the next instruction, with the +stack the same and most of the registers the same as before the system call, +and with the same virtual memory space. + +However, a few system calls do things differently. They might return to a +different location (rt_sigreturn) or change the memory space (fork/vfork/clone) +or even architecture (execve/execveat) of the program. + +To allow for this, the kernel implementation of the system call may need to +save and restore additional registers to the kernel stack, allowing complete +control of where and how execution continues after the system call. + +This is arch-specific, but typically involves defining assembly entry points +that save/restore additional registers and invoke the real system call entry +point. + +For x86_64, this is implemented as a stub_xyzzy entry point in +arch/x86/entry/entry_64.S, and the entry in the syscall table +(arch/x86/entry/syscalls/syscall_64.tbl) is adjusted to match: + + 333 common xyzzy stub_xyzzy + +The equivalent for 32-bit programs running on a 64-bit kernel is normally +called stub32_xyzzy and implemented in arch/x86/entry/entry_64_compat.S, +with the corresponding syscall table adjustment in +arch/x86/entry/syscalls/syscall_32.tbl: + + 380 i386 xyzzy sys_xyzzy stub32_xyzzy + +If the system call needs a compatibility layer (as in the previous section) +then the stub32_ version needs to call on to the compat_sys_ version of the +system call rather than the native 64-bit version. Also, if the x32 ABI +implementation is not common with the x86_64 version, then its syscall +table will also need to invoke a stub that calls on to the compat_sys_ +version. + +For completeness, it's also nice to set up a mapping so that user-mode Linux +still works -- its syscall table will reference stub_xyzzy, but the UML build +doesn't include arch/x86/entry/entry_64.S implementation (because UML +simulates registers etc). Fixing this is as simple as adding a #define to +arch/x86/um/sys_call_table_64.c: + + #define stub_xyzzy sys_xyzzy + + +Other Details +------------- + +Most of the kernel treats system calls in a generic way, but there is the +occasional exception that may need updating for your particular system call. + +The audit subsystem is one such special case; it includes (arch-specific) +functions that classify some special types of system call -- specifically +file open (open/openat), program execution (execve/exeveat) or socket +multiplexor (socketcall) operations. If your new system call is analogous to +one of these, then the audit system should be updated. + +More generally, if there is an existing system call that is analogous to your +new system call, it's worth doing a kernel-wide grep for the existing system +call to check there are no other special cases. + + +Testing +------- + +A new system call should obviously be tested; it is also useful to provide +reviewers with a demonstration of how user space programs will use the system +call. A good way to combine these aims is to include a simple self-test +program in a new directory under tools/testing/selftests/. + +For a new system call, there will obviously be no libc wrapper function and so +the test will need to invoke it using syscall(); also, if the system call +involves a new userspace-visible structure, the corresponding header will need +to be installed to compile the test. + +Make sure the selftest runs successfully on all supported architectures. For +example, check that it works when compiled as an x86_64 (-m64), x86_32 (-m32) +and x32 (-mx32) ABI program. + +For more extensive and thorough testing of new functionality, you should also +consider adding tests to the Linux Test Project, or to the xfstests project +for filesystem-related changes. + - https://linux-test-project.github.io/ + - git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git + + +Man Page +-------- + +All new system calls should come with a complete man page, ideally using groff +markup, but plain text will do. If groff is used, it's helpful to include a +pre-rendered ASCII version of the man page in the cover email for the +patchset, for the convenience of reviewers. + +The man page should be cc'ed to linux-man@vger.kernel.org +For more details, see https://www.kernel.org/doc/man-pages/patches.html + +References and Sources +---------------------- + + - LWN article from Michael Kerrisk on use of flags argument in system calls: + https://lwn.net/Articles/585415/ + - LWN article from Michael Kerrisk on how to handle unknown flags in a system + call: https://lwn.net/Articles/588444/ + - LWN article from Jake Edge describing constraints on 64-bit system call + arguments: https://lwn.net/Articles/311630/ + - Pair of LWN articles from David Drysdale that describe the system call + implementation paths in detail for v3.14: + - https://lwn.net/Articles/604287/ + - https://lwn.net/Articles/604515/ + - Architecture-specific requirements for system calls are discussed in the + syscall(2) man-page: + http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES + - Collated emails from Linus Torvalds discussing the problems with ioctl(): + http://yarchive.net/comp/linux/ioctl.html + - "How to not invent kernel interfaces", Arnd Bergmann, + http://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf + - LWN article from Michael Kerrisk on avoiding new uses of CAP_SYS_ADMIN: + https://lwn.net/Articles/486306/ + - Recommendation from Andrew Morton that all related information for a new + system call should come in the same email thread: + https://lkml.org/lkml/2014/7/24/641 + - Recommendation from Michael Kerrisk that a new system call should come with + a man page: https://lkml.org/lkml/2014/6/13/309 + - Suggestion from Thomas Gleixner that x86 wire-up should be in a separate + commit: https://lkml.org/lkml/2014/11/19/254 + - Suggestion from Greg Kroah-Hartman that it's good for new system calls to + come with a man-page & selftest: https://lkml.org/lkml/2014/3/19/710 + - Discussion from Michael Kerrisk of new system call vs. prctl(2) extension: + https://lkml.org/lkml/2014/6/3/411 + - Suggestion from Ingo Molnar that system calls that involve multiple + arguments should encapsulate those arguments in a struct, which includes a + size field for future extensibility: https://lkml.org/lkml/2015/7/30/117 + - Numbering oddities arising from (re-)use of O_* numbering space flags: + - commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness + check") + - commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc + conflict") + - commit bb458c644a59 ("Safer ABI for O_TMPFILE") + - Discussion from Matthew Wilcox about restrictions on 64-bit arguments: + https://lkml.org/lkml/2008/12/12/187 + - Recommendation from Greg Kroah-Hartman that unknown flags should be + policed: https://lkml.org/lkml/2014/7/17/577 + - Recommendation from Linus Torvalds that x32 system calls should prefer + compatibility with 64-bit versions rather than 32-bit versions: + https://lkml.org/lkml/2011/8/31/244 -- cgit v1.2.3-59-g8ed1b From 7bbac697e4a6e64cc4bae26d57310c916aa0da7a Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 3 Aug 2015 09:30:25 +0800 Subject: Documentation: minor typo fix in mailbox.txt Fix minor typo so that can pass correct pointer variable for container_of(). Signed-off-by: Leo Yan [jc: tweaked formatting] Signed-off-by: Jonathan Corbet --- Documentation/mailbox.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/mailbox.txt b/Documentation/mailbox.txt index 1092ad9578da..7ed371c85204 100644 --- a/Documentation/mailbox.txt +++ b/Documentation/mailbox.txt @@ -51,8 +51,7 @@ struct demo_client { */ static void message_from_remote(struct mbox_client *cl, void *mssg) { - struct demo_client *dc = container_of(mbox_client, - struct demo_client, cl); + struct demo_client *dc = container_of(cl, struct demo_client, cl); if (dc->async) { if (is_an_ack(mssg)) { /* An ACK to our last sample sent */ @@ -68,8 +67,7 @@ static void message_from_remote(struct mbox_client *cl, void *mssg) static void sample_sent(struct mbox_client *cl, void *mssg, int r) { - struct demo_client *dc = container_of(mbox_client, - struct demo_client, cl); + struct demo_client *dc = container_of(cl, struct demo_client, cl); complete(&dc->c); } -- cgit v1.2.3-59-g8ed1b From 1bd57127d4aaff518cf93f4809ec2f11b2baf865 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 15 Jul 2015 13:53:05 +0800 Subject: Doc: usb: ci-hdrc-usb2: add itc-setting at binding doc It is used to configure the ITC (in register USBCMD) value for kinds of applications. Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 553e2fae3a76..4159c8cf78e3 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -30,6 +30,8 @@ Optional properties: argument that indicate usb controller index - disable-over-current: (FSL only) disable over current detect - external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus +- itc-setting: interrupt threshold control register control, the setting + should be aligned with ITC bits at register USBCMD. Example: @@ -41,4 +43,5 @@ Example: phys = <&usb_phy0>; phy-names = "usb-phy"; vbus-supply = <®_usb0_vbus>; + gadget-itc-setting = <0x4>; /* 4 micro-frames */ }; -- cgit v1.2.3-59-g8ed1b From c6fba7b750efe64a69dd83e0ff7249abd0e783aa Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 28 Jul 2015 13:33:15 +0800 Subject: Doc: usb: ci-hdrc-usb2: add ahb-burst-config for binding doc It is used to change ahb burst configuration for platforms, it is vendor specific. Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 4159c8cf78e3..d52a747fb859 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -32,6 +32,11 @@ Optional properties: - external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus - itc-setting: interrupt threshold control register control, the setting should be aligned with ITC bits at register USBCMD. +- ahb-burst-config: it is vendor dependent, the required value should be + aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This + property is used to change AHB burst configuration, check the chipidea + spec for meaning of each value. If this property is not existed, it + will use the reset value. Example: @@ -44,4 +49,6 @@ Example: phy-names = "usb-phy"; vbus-supply = <®_usb0_vbus>; gadget-itc-setting = <0x4>; /* 4 micro-frames */ + /* Incremental burst of unspecified length */ + ahb-burst-config = <0x0>; }; -- cgit v1.2.3-59-g8ed1b From bd6e9d115df7fc6f11f3021c6fc05e3eaeb04a32 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 7 Aug 2015 15:08:02 +0800 Subject: Doc: usb: ci-hdrc-usb2: add tx(rx)-burst-config-dword for binding doc It is used to override the default setting for burst size, changing burst size takes effect only when the SBUSCFG.AHBBRST = 0. Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index d52a747fb859..d71ef07bca5d 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -37,6 +37,14 @@ Optional properties: property is used to change AHB burst configuration, check the chipidea spec for meaning of each value. If this property is not existed, it will use the reset value. +- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from system memory to the USB + bus, changing this value takes effect only the SBUSCFG.AHBBRST is 0. +- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from the USB bus to system memory, + changing this value takes effect only the SBUSCFG.AHBBRST is 0. Example: @@ -51,4 +59,6 @@ Example: gadget-itc-setting = <0x4>; /* 4 micro-frames */ /* Incremental burst of unspecified length */ ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; /* 64 bytes */ + rx-burst-size-dword = <0x10>; }; -- cgit v1.2.3-59-g8ed1b From 9ed71e7ad95eb9885420e8d33f33bd4d49e1b775 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 6 Aug 2015 23:36:52 +0100 Subject: DocBook: Fix non-determinstic installation of duplicate man pages Some kernel-doc sections are included in multiple DocBook files. This means the mandocs target will generate the same manual page multiple times with different metadata (author name/address and manual title, taken from the including DocBook file). If it's invoked in a parallel build, the output is non-determinstic. Build the manual pages in a separate subdirectory per DocBook file, then sort and de-duplicate when installing them (which is serialised). Signed-off-by: Ben Hutchings [jc: fixed conflicts with the docs tree] Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b7d2110298de..5e9702194dfe 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -60,7 +60,9 @@ mandocs: $(MAN) installmandocs: mandocs mkdir -p /usr/local/man/man9/ - install -m 644 $(obj)/man/*.9.gz /usr/local/man/man9/ + find $(obj)/man -name '*.9.gz' -printf '%h %f\n' | \ + sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \ + xargs install -m 644 -t /usr/local/man/man9/ ### #External programs used @@ -150,12 +152,12 @@ quiet_cmd_db2html = HTML $@ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi quiet_cmd_db2man = MAN $@ - cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi + cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man/$(*F) $< ; fi %.9 : %.xml @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ exit 1) - $(Q)mkdir -p $(obj)/man + $(Q)mkdir -p $(obj)/man/$(*F) $(call cmd,db2man) @touch $@ -- cgit v1.2.3-59-g8ed1b From 89f271c4d052063a72af2622f285f70caac91845 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 9 Jul 2015 22:19:07 +0200 Subject: doc: dt: add documentation for nxp,lpc1773-spifi Add device tree binding documentation for the SPI Flash Interface (SPIFI) found on NXP LPC18xx and LPC43xx devies. Signed-off-by: Joachim Eastwood Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/nxp-spifi.txt | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/nxp-spifi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/nxp-spifi.txt b/Documentation/devicetree/bindings/mtd/nxp-spifi.txt new file mode 100644 index 000000000000..f8b6b250654e --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/nxp-spifi.txt @@ -0,0 +1,58 @@ +* NXP SPI Flash Interface (SPIFI) + +NXP SPIFI is a specialized SPI interface for serial Flash devices. +It supports one Flash device with 1-, 2- and 4-bits width in SPI +mode 0 or 3. The controller operates in either command or memory +mode. In memory mode the Flash is accessible from the CPU as +normal memory. + +Required properties: + - compatible : Should be "nxp,lpc1773-spifi" + - reg : the first contains the register location and length, + the second contains the memory mapping address and length + - reg-names: Should contain the reg names "spifi" and "flash" + - interrupts : Should contain the interrupt for the device + - clocks : The clocks needed by the SPIFI controller + - clock-names : Should contain the clock names "spifi" and "reg" + +Optional properties: + - resets : phandle + reset specifier + +The SPI Flash must be a child of the SPIFI node and must have a +compatible property as specified in bindings/mtd/jedec,spi-nor.txt + +Optionally it can also contain the following properties. + - spi-cpol : Controller only supports mode 0 and 3 so either + both spi-cpol and spi-cpha should be present or + none of them + - spi-cpha : See above + - spi-rx-bus-width : Used to select how many pins that are used + for input on the controller + +See bindings/spi/spi-bus.txt for more information. + +Example: +spifi: spifi@40003000 { + compatible = "nxp,lpc1773-spifi"; + reg = <0x40003000 0x1000>, <0x14000000 0x4000000>; + reg-names = "spifi", "flash"; + interrupts = <30>; + clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>; + clock-names = "spifi", "reg"; + resets = <&rgu 53>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-cpol; + spi-cpha; + spi-rx-bus-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "data"; + reg = <0 0x200000>; + }; + }; +}; + -- cgit v1.2.3-59-g8ed1b From 6ef2bf71764708f7c58ee9300acd8df05dbaa06f Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:55 +0200 Subject: usb: interface authorization: Documentation part This part adds the documentation for the interface authorization. Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 22 +++++++++++++++++++++ Documentation/usb/authorization.txt | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 864637f25bee..5c6c26446f2a 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -1,3 +1,25 @@ +What: /sys/bus/usb/devices/INTERFACE/authorized +Date: June 2015 +KernelVersion: 4.2 +Description: + This allows to authorize (1) or deauthorize (0) + individual interfaces instead a whole device + in contrast to the device authorization. + If a deauthorized interface will be authorized + so the driver probing must be triggered manually + by writing INTERFACE to /sys/bus/usb/drivers_probe + This allows to avoid side-effects with drivers + that need multiple interfaces. + A deauthorized interface cannot be probed or claimed. + +What: /sys/bus/usb/devices/usbX/interface_authorized_default +Date: June 2015 +KernelVersion: 4.2 +Description: + This is used as default value that determines + if interfaces would authorized per default. + The value can be 1 or 0. It is per default 1. + What: /sys/bus/usb/device/.../authorized Date: July 2008 KernelVersion: 2.6.26 diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt index c069b6884c77..020cec5585ce 100644 --- a/Documentation/usb/authorization.txt +++ b/Documentation/usb/authorization.txt @@ -3,6 +3,9 @@ Authorizing (or not) your USB devices to connect to the system (C) 2007 Inaky Perez-Gonzalez Intel Corporation +Interface authorization part: + (C) 2015 Stefan Koch SUSE LLC + This feature allows you to control if a USB device can be used (or not) in a system. This feature will allow you to implement a lock-down of USB devices, fully controlled by user space. @@ -90,3 +93,34 @@ etc, but you get the idea. Anybody with access to a device gadget kit can fake descriptors and device info. Don't trust that. You are welcome. + +Interface authorization +----------------------- +There is a similar approach to allow or deny specific USB interfaces. +That allows to block only a subset of an USB device. + +Authorize an interface: +$ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized + +Deauthorize an interface: +$ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized + +The default value for new interfaces +on a particular USB bus can be changed, too. + +Allow interfaces per default: +$ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default + +Deny interfaces per default: +$ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default + +Per default the interface_authorized_default bit is 1. +So all interfaces would authorized per default. + +Note: +If a deauthorized interface will be authorized so the driver probing must +be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe + +For drivers that need multiple interfaces all needed interfaces should be +authroized first. After that the drivers should be probed. +This avoids side effects. -- cgit v1.2.3-59-g8ed1b From 5699f871d2d51ce40012501378670613d4d49214 Mon Sep 17 00:00:00 2001 From: Danilo Cesar Lemes de Paula Date: Tue, 28 Jul 2015 16:45:15 -0300 Subject: scripts/kernel-doc: Adding cross-reference links to html documentation. Functions, Structs and Parameters definitions on kernel documentation are pure cosmetic, it only highlights the element. To ease the navigation in the documentation we should use inside those tags so readers can easily jump between methods directly. This was discussed in 2014[1] and is implemented by getting a list of from the DocBook XML to generate a database. Then it looks for , and tags that matches the ones in the database. As it only links existent references, no broken links are added. [1] - lists.freedesktop.org/archives/dri-devel/2014-August/065404.html Signed-off-by: Danilo Cesar Lemes de Paula Cc: Randy Dunlap Cc: Daniel Vetter Cc: Laurent Pinchart Cc: Herbert Xu Cc: Stephan Mueller Cc: Michal Marek Cc: intel-gfx Cc: dri-devel Signed-off-by: Jonathan Corbet --- Documentation/DocBook/Makefile | 43 ++++++--- scripts/kernel-doc-xml-ref | 198 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+), 13 deletions(-) create mode 100755 scripts/kernel-doc-xml-ref (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 5e9702194dfe..b1d6c951ea29 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -66,8 +66,9 @@ installmandocs: mandocs ### #External programs used -KERNELDOC = $(srctree)/scripts/kernel-doc -DOCPROC = $(objtree)/scripts/docproc +KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref +KERNELDOC = $(srctree)/scripts/kernel-doc +DOCPROC = $(objtree)/scripts/docproc XMLTOFLAGS = -m $(srctree)/$(src)/stylesheet.xsl XMLTOFLAGS += --skip-validation @@ -91,7 +92,7 @@ define rule_docproc ) > $(dir $@).$(notdir $@).cmd endef -%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) FORCE +%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) $(KERNELDOCXMLREF) FORCE $(call if_changed_rule,docproc) # Tell kbuild to always build the programs @@ -142,7 +143,20 @@ quiet_cmd_db2html = HTML $@ echo '
\ $(patsubst %.html,%,$(notdir $@))

' > $@ -%.html: %.xml +### +# Rules to create an aux XML and .db, and use them to re-process the DocBook XML +# to fill internal hyperlinks + gen_aux_xml = : + quiet_gen_aux_xml = echo ' XMLREF $@' +silent_gen_aux_xml = : +%.aux.xml: %.xml + @$($(quiet)gen_aux_xml) + @rm -rf $@ + @(cat $< | egrep "^ $<.db) + @$(KERNELDOCXMLREF) -db $<.db $< > $@ +.PRECIOUS: %.aux.xml + +%.html: %.aux.xml @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ exit 1) @@ -211,15 +225,18 @@ dochelp: ### # Temporary files left by various tools clean-files := $(DOCBOOKS) \ - $(patsubst %.xml, %.dvi, $(DOCBOOKS)) \ - $(patsubst %.xml, %.aux, $(DOCBOOKS)) \ - $(patsubst %.xml, %.tex, $(DOCBOOKS)) \ - $(patsubst %.xml, %.log, $(DOCBOOKS)) \ - $(patsubst %.xml, %.out, $(DOCBOOKS)) \ - $(patsubst %.xml, %.ps, $(DOCBOOKS)) \ - $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ - $(patsubst %.xml, %.html, $(DOCBOOKS)) \ - $(patsubst %.xml, %.9, $(DOCBOOKS)) \ + $(patsubst %.xml, %.dvi, $(DOCBOOKS)) \ + $(patsubst %.xml, %.aux, $(DOCBOOKS)) \ + $(patsubst %.xml, %.tex, $(DOCBOOKS)) \ + $(patsubst %.xml, %.log, $(DOCBOOKS)) \ + $(patsubst %.xml, %.out, $(DOCBOOKS)) \ + $(patsubst %.xml, %.ps, $(DOCBOOKS)) \ + $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ + $(patsubst %.xml, %.html, $(DOCBOOKS)) \ + $(patsubst %.xml, %.9, $(DOCBOOKS)) \ + $(patsubst %.xml, %.aux.xml, $(DOCBOOKS)) \ + $(patsubst %.xml, %.xml.db, $(DOCBOOKS)) \ + $(patsubst %.xml, %.xml, $(DOCBOOKS)) \ $(index) clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man diff --git a/scripts/kernel-doc-xml-ref b/scripts/kernel-doc-xml-ref new file mode 100755 index 000000000000..104a5a5ba2c8 --- /dev/null +++ b/scripts/kernel-doc-xml-ref @@ -0,0 +1,198 @@ +#!/usr/bin/perl -w + +use strict; + +## Copyright (C) 2015 Intel Corporation ## +# ## +## This software falls under the GNU General Public License. ## +## Please read the COPYING file for more information ## +# +# +# This software reads a XML file and a list of valid interal +# references to replace Docbook tags with links. +# +# The list of "valid internal references" must be one-per-line in the following format: +# API-struct-foo +# API-enum-bar +# API-my-function +# +# The software walks over the XML file looking for xml tags representing possible references +# to the Document. Each reference will be cross checked against the "Valid Internal Reference" list. If +# the referece is found it replaces its content by a tag. +# +# usage: +# kernel-doc-xml-ref -db filename +# xml filename > outputfile + +# read arguments +if ($#ARGV != 2) { + usage(); +} + +#Holds the database filename +my $databasefile; +my @database; + +#holds the inputfile +my $inputfile; +my $errors = 0; + +my %highlights = ( + "(.*?)", + "\"\" . convert_function(\$1, \$line) . \"\"", + "(.*?)", + "\"\" . convert_struct(\$1) . \"\"", + "(.*?)(.*?)", + "\"\" . convert_param(\$1) . \"\$2\"", + "(.*?)(.*?)", + "\"\" . convert_param(\$1) . \"\$2\""); + +while($ARGV[0] =~ m/^-(.*)/) { + my $cmd = shift @ARGV; + if ($cmd eq "-db") { + $databasefile = shift @ARGV + } else { + usage(); + } +} +$inputfile = shift @ARGV; + +sub open_database { + open (my $handle, '<', $databasefile) or die "Cannot open $databasefile"; + chomp(my @lines = <$handle>); + close $handle; + + @database = @lines; +} + +sub process_file { + open_database(); + + my $dohighlight; + foreach my $pattern (keys %highlights) { + $dohighlight .= "\$line =~ s:$pattern:$highlights{$pattern}:eg;\n"; + } + + open(FILE, $inputfile) or die("Could not open $inputfile") or die ("Cannot open $inputfile"); + foreach my $line () { + eval $dohighlight; + print $line; + } +} + +sub trim($_) +{ + my $str = $_[0]; + $str =~ s/^\s+|\s+$//g; + return $str +} + +sub has_key_defined($_) +{ + if ( grep( /^$_[0]$/, @database)) { + return 1; + } + return 0; +} + +# Gets a content and add it a hyperlink if possible. +sub convert_function($_) +{ + my $arg = $_[0]; + my $key = $_[0]; + + my $line = $_[1]; + + $key = trim($key); + + $key =~ s/[^A-Za-z0-9]/-/g; + $key = "API-" . $key; + + # We shouldn't add links to prototype + if (!has_key_defined($key) || $line =~ m/\s+$head$tail"; +} + +# Converting a struct text to link +sub convert_struct($_) +{ + my $arg = $_[0]; + my $key = $_[0]; + $key =~ s/(struct )?(\w)/$2/g; + $key =~ s/[^A-Za-z0-9]/-/g; + $key = "API-struct-" . $key; + + if (!has_key_defined($key)) { + return $arg; + } + + my ($head, $tail) = split_pointer($arg); + return "$head$tail"; +} + +# Identify "object *" elements +sub split_pointer($_) +{ + my $arg = $_[0]; + if ($arg =~ /(.*?)( ?\* ?)/) { + return ($1, $2); + } + return ($arg, ""); +} + +sub convert_param($_) +{ + my $type = $_[0]; + my $keyname = convert_key_name($type); + + if (!has_key_defined($keyname)) { + return $type; + } + + my ($head, $tail) = split_pointer($type); + return "$head$tail"; + +} + +# DocBook links are in the API-- format +# This method gets an element and returns a valid DocBook reference for it. +sub convert_key_name($_) +{ + #Pattern $2 is optional and might be uninitialized + no warnings 'uninitialized'; + + my $str = $_[0]; + $str =~ s/(const|static)? ?(struct)? ?([a-zA-Z0-9_]+) ?(\*|&)?/$2 $3/g ; + + # trim + $str =~ s/^\s+|\s+$//g; + + # spaces and _ to - + $str =~ s/[^A-Za-z0-9]/-/g; + + return "API-" . $str; +} + +sub usage { + print "Usage: $0 -db database filename\n"; + print " xml source file(s) > outputfile\n"; + exit 1; +} + +# starting point +process_file(); + +if ($errors) { + print STDERR "$errors errors\n"; +} + +exit($errors); -- cgit v1.2.3-59-g8ed1b From 649ca820dab3d76e12408b74af3e8e97abb07ae0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 09:56:20 -0700 Subject: hwmon: (ltc2978) Add support for LTC2975 LTC2975 is mostly compatible to LTC2974, but supports input current and power measurement. Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 +- Documentation/hwmon/ltc2978 | 47 ++++++---- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/ltc2978.c | 104 +++++++++++++++++++-- 4 files changed, 125 insertions(+), 33 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index c1d23c14ddd9..e434d5fba2ae 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -3,6 +3,7 @@ ltc2978 Required properties: - compatible: should contain one of: * "lltc,ltc2974" + * "lltc,ltc2975" * "lltc,ltc2977" * "lltc,ltc2978" * "lltc,ltc3880" @@ -19,7 +20,7 @@ Optional properties: standard binding for regulators; see regulator.txt. Valid names of regulators depend on number of supplies supported per device: - * ltc2974 : vout0 - vout3 + * ltc2974, ltc2975 : vout0 - vout3 * ltc2977 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index ff130997f22e..7e982884e359 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -6,6 +6,10 @@ Supported chips: Prefix: 'ltc2974' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc2974 + * Linear Technology LTC2975 + Prefix: 'ltc2975' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc2975 * Linear Technology LTC2977 Prefix: 'ltc2977' Addresses scanned: - @@ -42,7 +46,7 @@ Author: Guenter Roeck Description ----------- -LTC2974 is a quad digital power supply managers. +LTC2974 and LTC2975 are quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC @@ -71,23 +75,23 @@ in1_label "vin" in1_input Measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_lcrit Critical minimum input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_crit Critical maximum input voltage. in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_lcrit_alarm Input voltage critical low alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_crit_alarm Input voltage critical high alarm. in1_lowest Lowest input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_highest Highest input voltage. in1_reset_history Reset input voltage history. in[N]_label "vout[1-8]". - LTC2974: N=2-5 + LTC2974, LTC2975: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 @@ -101,13 +105,14 @@ in[N]_min_alarm Output voltage low alarm. in[N]_max_alarm Output voltage high alarm. in[N]_lcrit_alarm Output voltage critical low alarm. in[N]_crit_alarm Output voltage critical high alarm. -in[N]_lowest Lowest output voltage. LTC2974 and LTC2978 only. +in[N]_lowest Lowest output voltage. LTC2974, LTC2975, + and LTC2978 only. in[N]_highest Highest output voltage. in[N]_reset_history Reset output voltage history. temp[N]_input Measured temperature. - On LTC2974, temp[1-4] report external temperatures, - and temp5 reports the chip temperature. + On LTC2974 and LTC2975, temp[1-4] report external + temperatures, and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and @@ -120,23 +125,24 @@ temp[N]_max Maximum temperature. temp[N]_lcrit Critical low temperature. temp[N]_crit Critical high temperature. temp[N]_min_alarm Temperature low alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. temp[N]_max_alarm Temperature high alarm. temp[N]_lcrit_alarm Temperature critical low alarm. temp[N]_crit_alarm Temperature critical high alarm. temp[N]_lowest Lowest measured temperature. - LTC2974, LTC2977, and LTC2978 only. - Not supported for chip temperature sensor on LTC2974. + LTC2974, LTC2975, LTC2977, and LTC2978 only. + Not supported for chip temperature sensor on LTC2974 and + LTC2975. temp[N]_highest Highest measured temperature. Not supported for chip - temperature sensor on LTC2974. + temperature sensor on LTC2974 and LTC2975. temp[N]_reset_history Reset temperature history. Not supported for chip - temperature sensor on LTC2974. + temperature sensor on LTC2974 and LTC2975. power1_label "pin". LTC3883 only. power1_input Measured input power. power[N]_label "pout[1-4]". - LTC2974: N=1-4 + LTC2974, LTC2975: N=1-4 LTC2977: Not supported LTC2978: Not supported LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 @@ -151,7 +157,7 @@ curr1_highest Highest input current. LTC3883 only. curr1_reset_history Reset input current history. LTC3883 only. curr[N]_label "iout[1-4]". - LTC2974: N=1-4 + LTC2974, LTC2975: N=1-4 LTC2977: not supported LTC2978: not supported LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 @@ -159,10 +165,11 @@ curr[N]_label "iout[1-4]". curr[N]_input Measured output current. curr[N]_max Maximum output current. curr[N]_crit Critical high output current. -curr[N]_lcrit Critical low output current. LTC2974 only. +curr[N]_lcrit Critical low output current. LTC2974 and LTC2975 only. curr[N]_max_alarm Output current high alarm. curr[N]_crit_alarm Output current critical high alarm. -curr[N]_lcrit_alarm Output current critical low alarm. LTC2974 only. -curr[N]_lowest Lowest output current. LTC2974 only. +curr[N]_lcrit_alarm Output current critical low alarm. + LTC2974 and LTC2975 only. +curr[N]_lowest Lowest output current. LTC2974 and LTC2975 only. curr[N]_highest Highest output current. curr[N]_reset_history Reset output current history. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 43b6de900ce5..8279727987cb 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,8 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTC3887, - and LTM4676. + Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC3880, LTC3883, + LTC3887, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 0756d8ae9dad..e153ffd59ab0 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,9 +1,8 @@ /* - * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, - * LTC3883, LTC3887. and LTM4676 + * Hardware monitoring driver for LTC2978 and compatible chips. * * Copyright (c) 2011 Ericsson AB. - * Copyright (c) 2013, 2014 Guenter Roeck + * Copyright (c) 2013, 2014, 2015 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +24,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, - ltm4676 }; +enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, + ltc3887, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -34,12 +33,12 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ -/* LTC2974, LCT2977, and LTC2978 */ +/* LTC2974, LTC2975, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VIN_MIN 0xfc #define LTC2978_MFR_TEMPERATURE_MIN 0xfd -/* LTC2974 only */ +/* LTC2974, LTC2975 */ #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 @@ -51,8 +50,15 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, /* LTC3883 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 +/* LTC2975 only */ +#define LTC2975_MFR_IIN_PEAK 0xc4 +#define LTC2975_MFR_IIN_MIN 0xc5 +#define LTC2975_MFR_PIN_PEAK 0xc6 +#define LTC2975_MFR_PIN_MIN 0xc7 + #define LTC2974_ID_REV1 0x0212 #define LTC2974_ID_REV2 0x0213 +#define LTC2975_ID 0x0223 #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0121 #define LTC2978_ID_REV2 0x0122 @@ -87,7 +93,8 @@ struct ltc2978_data { u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES]; u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES]; - u16 iin_max; + u16 iin_min, iin_max; + u16 pin_min, pin_max; u16 temp2_max; struct pmbus_driver_info info; }; @@ -246,6 +253,60 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) return ret; } +static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct ltc2978_data *data = to_ltc2978_data(info); + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_IIN_MAX: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_PEAK); + if (ret >= 0) { + if (lin11_to_val(ret) + > lin11_to_val(data->iin_max)) + data->iin_max = ret; + ret = data->iin_max; + } + break; + case PMBUS_VIRT_READ_IIN_MIN: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_MIN); + if (ret >= 0) { + if (lin11_to_val(ret) + < lin11_to_val(data->iin_min)) + data->iin_min = ret; + ret = data->iin_min; + } + break; + case PMBUS_VIRT_READ_PIN_MAX: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_PEAK); + if (ret >= 0) { + if (lin11_to_val(ret) + > lin11_to_val(data->pin_max)) + data->pin_max = ret; + ret = data->pin_max; + } + break; + case PMBUS_VIRT_READ_PIN_MIN: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_MIN); + if (ret >= 0) { + if (lin11_to_val(ret) + < lin11_to_val(data->pin_min)) + data->pin_min = ret; + ret = data->pin_min; + } + break; + case PMBUS_VIRT_RESET_IIN_HISTORY: + case PMBUS_VIRT_RESET_PIN_HISTORY: + ret = 0; + break; + default: + ret = ltc2978_read_word_data(client, page, reg); + break; + } + return ret; +} + static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -337,7 +398,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, switch (reg) { case PMBUS_VIRT_RESET_IIN_HISTORY: data->iin_max = 0x7c00; - ret = ltc2978_clear_peaks(client, page, data->id); + data->iin_min = 0x7bff; + ret = ltc2978_clear_peaks(client, 0, data->id); + break; + case PMBUS_VIRT_RESET_PIN_HISTORY: + data->pin_max = 0x7c00; + data->pin_min = 0x7bff; + ret = ltc2978_clear_peaks(client, 0, data->id); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: data->iout_max[page] = 0x7c00; @@ -372,6 +439,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, static const struct i2c_device_id ltc2978_id[] = { {"ltc2974", ltc2974}, + {"ltc2975", ltc2975}, {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, @@ -428,6 +496,8 @@ static int ltc2978_get_id(struct i2c_client *client) if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) return ltc2974; + else if (chip_id == LTC2975_ID) + return ltc2975; else if (chip_id == LTC2977_ID) return ltc2977; else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || @@ -505,6 +575,19 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; } break; + case ltc2975: + info->read_word_data = ltc2975_read_word_data; + info->pages = LTC2974_NUM_PAGES; + info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP2; + for (i = 0; i < info->pages; i++) { + info->func[i] |= PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; + } + break; case ltc2977: case ltc2978: info->read_word_data = ltc2978_read_word_data; @@ -576,6 +659,7 @@ static int ltc2978_probe(struct i2c_client *client, #ifdef CONFIG_OF static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2974" }, + { .compatible = "lltc,ltc2975" }, { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, { .compatible = "lltc,ltc3880" }, @@ -601,5 +685,5 @@ static struct i2c_driver ltc2978_driver = { module_i2c_driver(ltc2978_driver); MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676"); +MODULE_DESCRIPTION("PMBus driver for LTC2978 and comppatible chips"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 52aae6af71e0e78e25c64e13266917bb323984d5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 06:38:01 -0700 Subject: hwmon: (ltc2978) Add support for LTC2980 and LTM2987 LTC2980 and LTM2987 are command compatible to LTC2977. They consist of two LTC2977 on a single die, and are instantiated as two separate chips, each supporting eight channels. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 4 +- Documentation/hwmon/ltc2978 | 49 ++++++++++++++++------ drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/ltc2978.c | 20 +++++++-- 4 files changed, 58 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index e434d5fba2ae..5dc2691ccf08 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -6,10 +6,12 @@ Required properties: * "lltc,ltc2975" * "lltc,ltc2977" * "lltc,ltc2978" + * "lltc,ltc2980" * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" * "lltc,ltc3887" + * "lltc,ltm2987" * "lltc,ltm4676" - reg: I2C slave address @@ -21,7 +23,7 @@ Optional properties: Valid names of regulators depend on number of supplies supported per device: * ltc2974, ltc2975 : vout0 - vout3 - * ltc2977 : vout0 - vout7 + * ltc2977, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882 : vout0 - vout1 * ltc3883 : vout0 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 7e982884e359..158355398798 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -19,6 +19,10 @@ Supported chips: Addresses scanned: - Datasheet: http://www.linear.com/product/ltc2978 http://www.linear.com/product/ltc2978a + * Linear Technology LTC2980 + Prefix: 'ltc2980' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc2980 * Linear Technology LTC3880 Prefix: 'ltc3880' Addresses scanned: - @@ -35,6 +39,10 @@ Supported chips: Prefix: 'ltc3887' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3887 + * Linear Technology LTM2987 + Prefix: 'ltm2987' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltm2987 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -49,9 +57,15 @@ Description LTC2974 and LTC2975 are quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. +LTC2980 is a 16-channel Power System Manager, consisting of two LTC2977 +in a single die. The chip is instantiated and reported as two separate chips +on two different I2C bus addresses. LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC controllers. LTC3883 is a single phase step-down DC/DC controller. +LTM2987 is a 16-channel Power System Manager with two LTC2977 plus +additional components on a single die. The chip is instantiated and reported +as two separate chips on two different I2C bus addresses. LTM4676 is a dual 13A or single 26A uModule regulator. @@ -75,24 +89,29 @@ in1_label "vin" in1_input Measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_lcrit Critical minimum input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_crit Critical maximum input voltage. in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_lcrit_alarm Input voltage critical low alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_crit_alarm Input voltage critical high alarm. in1_lowest Lowest input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_highest Highest input voltage. in1_reset_history Reset input voltage history. in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 - LTC2977: N=2-9 + LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 @@ -113,24 +132,28 @@ in[N]_reset_history Reset output voltage history. temp[N]_input Measured temperature. On LTC2974 and LTC2975, temp[1-4] report external temperatures, and temp5 reports the chip temperature. - On LTC2977 and LTC2978, only one temperature measurement - is supported and reports the chip temperature. + On LTC2977, LTC2980, LTC2978, and LTM2987, only one + temperature measurement is supported and reports + the chip temperature. On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and temp2 report external temperatures, and temp3 reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. -temp[N]_min Mimimum temperature. LTC2974, LCT2977, and LTC2978 only. +temp[N]_min Mimimum temperature. LTC2974, LCT2977, LTM2980, LTC2978, + and LTM2987 only. temp[N]_max Maximum temperature. temp[N]_lcrit Critical low temperature. temp[N]_crit Critical high temperature. temp[N]_min_alarm Temperature low alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and + LTM2987 only. temp[N]_max_alarm Temperature high alarm. temp[N]_lcrit_alarm Temperature critical low alarm. temp[N]_crit_alarm Temperature critical high alarm. temp[N]_lowest Lowest measured temperature. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and + LTM2987 only. Not supported for chip temperature sensor on LTC2974 and LTC2975. temp[N]_highest Highest measured temperature. Not supported for chip @@ -143,7 +166,7 @@ power1_input Measured input power. power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 - LTC2977: Not supported + LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 LTC3883: N=2 @@ -158,7 +181,7 @@ curr1_reset_history Reset input current history. LTC3883 only. curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 - LTC2977: not supported + LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 8279727987cb..af778aed4033 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,8 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC3880, LTC3883, - LTC3887, and LTM4676. + Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, + LTC3883, LTC3887, LTCM2987, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index e9d3f828fe46..48dcde0bc740 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -24,8 +24,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, - ltc3887, ltm4676 }; +enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, + ltc3883, ltc3887, ltm2987, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -33,7 +33,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */ -/* LTC2974, LTC2975, LCT2977, and LTC2978 */ +/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */ #define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VIN_MIN 0xfc #define LTC2978_MFR_TEMPERATURE_MIN 0xfd @@ -63,11 +63,15 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0110 /* Early revision */ #define LTC2978_ID_REV2 0x0120 +#define LTC2980_ID_A 0x8030 /* A/B for two die IDs */ +#define LTC2980_ID_B 0x8040 #define LTC3880_ID 0x4020 #define LTC3882_ID 0x4200 #define LTC3882_ID_D1 0x4240 /* Dash 1 */ #define LTC3883_ID 0x4300 #define LTC3887_ID 0x4700 +#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ +#define LTM2987_ID_B 0x8020 #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 @@ -409,10 +413,12 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc2975", ltc2975}, {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, + {"ltc2980", ltc2980}, {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, {"ltc3887", ltc3887}, + {"ltm2987", ltm2987}, {"ltm4676", ltm4676}, {} }; @@ -471,6 +477,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc2977; else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) return ltc2978; + else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B) + return ltc2980; else if (chip_id == LTC3880_ID) return ltc3880; else if (chip_id == LTC3882_ID || chip_id == LTC3882_ID_D1) @@ -479,6 +487,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3883; else if (chip_id == LTC3887_ID) return ltc3887; + else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) + return ltm2987; else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || chip_id == LTM4676A_ID) return ltm4676; @@ -559,6 +569,8 @@ static int ltc2978_probe(struct i2c_client *client, break; case ltc2977: case ltc2978: + case ltc2980: + case ltm2987: info->read_word_data = ltc2978_read_word_data; info->pages = LTC2978_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT @@ -634,10 +646,12 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2975" }, { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, + { .compatible = "lltc,ltc2980" }, { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, { .compatible = "lltc,ltc3887" }, + { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.2.3-59-g8ed1b From 228b687d9e20f367e4d5ea8723e3abbf0892db61 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 07:21:43 -0700 Subject: hwmon: (ltc2978) Add support for LTC3886 LTC3886 is a is a dual PolyPhase DC/DC synchronous step-down switching regulator controller. It is mostly command compatible to LTC3883, but supports two phases instead of one. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 ++- Documentation/hwmon/ltc2978 | 23 +++++++++++++-------- drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/ltc2978.c | 24 ++++++++++++++++++++-- 4 files changed, 39 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index 5dc2691ccf08..a7afbf60bb9c 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -10,6 +10,7 @@ Required properties: * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" + * "lltc,ltc3886" * "lltc,ltc3887" * "lltc,ltm2987" * "lltc,ltm4676" @@ -25,7 +26,7 @@ Valid names of regulators depend on number of supplies supported per device: * ltc2974, ltc2975 : vout0 - vout3 * ltc2977, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 - * ltc3880, ltc3882 : vout0 - vout1 + * ltc3880, ltc3882, ltc3886 : vout0 - vout1 * ltc3883 : vout0 * ltm4676 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 158355398798..f997aa53eb95 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -35,6 +35,10 @@ Supported chips: Prefix: 'ltc3883' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3883 + * Linear Technology LTC3886 + Prefix: 'ltc3886' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3886 * Linear Technology LTC3887 Prefix: 'ltc3887' Addresses scanned: - @@ -60,8 +64,8 @@ LTC2977 is a pin compatible replacement for LTC2978. LTC2980 is a 16-channel Power System Manager, consisting of two LTC2977 in a single die. The chip is instantiated and reported as two separate chips on two different I2C bus addresses. -LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC -controllers. +LTC3880, LTC3882, LTC3886, and LTC3887 are dual output poly-phase step-down +DC/DC controllers. LTC3883 is a single phase step-down DC/DC controller. LTM2987 is a 16-channel Power System Manager with two LTC2977 plus additional components on a single die. The chip is instantiated and reported @@ -113,7 +117,7 @@ in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC23886 LTC3887, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -161,29 +165,30 @@ temp[N]_highest Highest measured temperature. Not supported for chip temp[N]_reset_history Reset temperature history. Not supported for chip temperature sensor on LTC2974 and LTC2975. -power1_label "pin". LTC3883 only. +power1_label "pin". LTC3883 and LTC3886 only. power1_input Measured input power. power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, LTC3887, and LTM4676 only. +curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, and LTM4676 + only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. -curr1_highest Highest input current. LTC3883 only. -curr1_reset_history Reset input current history. LTC3883 only. +curr1_highest Highest input current. LTC3883 and LTC3886 only. +curr1_reset_history Reset input current history. LTC3883 and LTC3886 only. curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported - LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index af778aed4033..5ebc36255c88 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -53,7 +53,7 @@ config SENSORS_LTC2978 help If you say yes here you get hardware monitoring support for Linear Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3887, LTCM2987, and LTM4676. + LTC3883, LTC3886, LTC3887, LTCM2987, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 48dcde0bc740..60fe8f9839d3 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -25,7 +25,7 @@ #include "pmbus.h" enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3887, ltm2987, ltm4676 }; + ltc3883, ltc3886, ltc3887, ltm2987, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -47,7 +47,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883 only */ +/* LTC3883 and LTC3886 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 /* LTC2975 only */ @@ -69,6 +69,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3882_ID 0x4200 #define LTC3882_ID_D1 0x4240 /* Dash 1 */ #define LTC3883_ID 0x4300 +#define LTC3886_ID 0x4600 #define LTC3887_ID 0x4700 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 @@ -417,6 +418,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, + {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltm2987", ltm2987}, {"ltm4676", ltm4676}, @@ -485,6 +487,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3882; else if (chip_id == LTC3883_ID) return ltc3883; + else if (chip_id == LTC3886_ID) + return ltc3886; else if (chip_id == LTC3887_ID) return ltc3887; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -624,6 +628,21 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; break; + case ltc3886: + data->features |= FEAT_CLEAR_PEAKS; + info->read_word_data = ltc3883_read_word_data; + info->pages = LTC3880_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; default: return -ENODEV; } @@ -650,6 +669,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, + { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4676" }, -- cgit v1.2.3-59-g8ed1b From dba3398381dd1175c74721c97d1daf8fc5939276 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:57:15 -0700 Subject: Revert "usb: interface authorization: Documentation part" This reverts commit 6ef2bf71764708f7c58ee9300acd8df05dbaa06f as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 22 --------------------- Documentation/usb/authorization.txt | 34 --------------------------------- 2 files changed, 56 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 5c6c26446f2a..864637f25bee 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -1,25 +1,3 @@ -What: /sys/bus/usb/devices/INTERFACE/authorized -Date: June 2015 -KernelVersion: 4.2 -Description: - This allows to authorize (1) or deauthorize (0) - individual interfaces instead a whole device - in contrast to the device authorization. - If a deauthorized interface will be authorized - so the driver probing must be triggered manually - by writing INTERFACE to /sys/bus/usb/drivers_probe - This allows to avoid side-effects with drivers - that need multiple interfaces. - A deauthorized interface cannot be probed or claimed. - -What: /sys/bus/usb/devices/usbX/interface_authorized_default -Date: June 2015 -KernelVersion: 4.2 -Description: - This is used as default value that determines - if interfaces would authorized per default. - The value can be 1 or 0. It is per default 1. - What: /sys/bus/usb/device/.../authorized Date: July 2008 KernelVersion: 2.6.26 diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt index 020cec5585ce..c069b6884c77 100644 --- a/Documentation/usb/authorization.txt +++ b/Documentation/usb/authorization.txt @@ -3,9 +3,6 @@ Authorizing (or not) your USB devices to connect to the system (C) 2007 Inaky Perez-Gonzalez Intel Corporation -Interface authorization part: - (C) 2015 Stefan Koch SUSE LLC - This feature allows you to control if a USB device can be used (or not) in a system. This feature will allow you to implement a lock-down of USB devices, fully controlled by user space. @@ -93,34 +90,3 @@ etc, but you get the idea. Anybody with access to a device gadget kit can fake descriptors and device info. Don't trust that. You are welcome. - -Interface authorization ------------------------ -There is a similar approach to allow or deny specific USB interfaces. -That allows to block only a subset of an USB device. - -Authorize an interface: -$ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized - -Deauthorize an interface: -$ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized - -The default value for new interfaces -on a particular USB bus can be changed, too. - -Allow interfaces per default: -$ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default - -Deny interfaces per default: -$ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default - -Per default the interface_authorized_default bit is 1. -So all interfaces would authorized per default. - -Note: -If a deauthorized interface will be authorized so the driver probing must -be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe - -For drivers that need multiple interfaces all needed interfaces should be -authroized first. After that the drivers should be probed. -This avoids side effects. -- cgit v1.2.3-59-g8ed1b From ccf2dc51bc4a715670641aa5af0d4636acd8e0cd Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 20:08:09 -0700 Subject: hwmon: (ltc2978) Add support for LTM4675 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LTM2975 is a dual 9A or single 18A μModule regulator. It is register compatible with LTM4676. Signed-off-by: Guenter Roeck --- Documentation/hwmon/ltc2978 | 24 ++++++++++++++++-------- drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/ltc2978.c | 10 ++++++++-- 3 files changed, 25 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index f997aa53eb95..9a49d3c90cd1 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -47,6 +47,10 @@ Supported chips: Prefix: 'ltm2987' Addresses scanned: - Datasheet: http://www.linear.com/product/ltm2987 + * Linear Technology LTM4675 + Prefix: 'ltm4675' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltm4675 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -70,6 +74,7 @@ LTC3883 is a single phase step-down DC/DC controller. LTM2987 is a 16-channel Power System Manager with two LTC2977 plus additional components on a single die. The chip is instantiated and reported as two separate chips on two different I2C bus addresses. +LTM4675 is a dual 9A or single 18A μModule regulator LTM4676 is a dual 13A or single 26A uModule regulator. @@ -117,7 +122,8 @@ in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTC23886 LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC23886 LTC3887, LTM4675, LTM4676: + N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -139,9 +145,9 @@ temp[N]_input Measured temperature. On LTC2977, LTC2980, LTC2978, and LTM2987, only one temperature measurement is supported and reports the chip temperature. - On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and - temp2 report external temperatures, and temp3 reports - the chip temperature. + On LTC3880, LTC3882, LTC3887, LTM4675, and LTM4676, + temp1 and temp2 report external temperatures, and temp3 + reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. temp[N]_min Mimimum temperature. LTC2974, LCT2977, LTM2980, LTC2978, @@ -172,12 +178,13 @@ power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676: + N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, and LTM4676 - only. +curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, LTM4675, + and LTM4676 only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. @@ -188,7 +195,8 @@ curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported - LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676: + N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 5ebc36255c88..df6ebb2b8f0f 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -53,7 +53,7 @@ config SENSORS_LTC2978 help If you say yes here you get hardware monitoring support for Linear Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3886, LTC3887, LTCM2987, and LTM4676. + LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index f1c69c9de849..58b789c28b48 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -28,7 +28,7 @@ #include "pmbus.h" enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3886, ltc3887, ltm2987, ltm4676 }; + ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -46,7 +46,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, LTC3887, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -77,6 +77,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3887_ID 0x4700 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 +#define LTM4675_ID 0x47a0 #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 @@ -509,6 +510,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltm2987", ltm2987}, + {"ltm4675", ltm4675}, {"ltm4676", ltm4676}, {} }; @@ -581,6 +583,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3887; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) return ltm2987; + else if (chip_id == LTM4675_ID) + return ltm4675; else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || chip_id == LTM4676A_ID) return ltm4676; @@ -678,6 +682,7 @@ static int ltc2978_probe(struct i2c_client *client, break; case ltc3880: case ltc3887: + case ltm4675: case ltm4676: data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; @@ -763,6 +768,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm2987" }, + { .compatible = "lltc,ltm4675" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.2.3-59-g8ed1b From a493f339a88ddd20693460c1dcf8230aa3732b8b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:31 -0700 Subject: irqchip/bcm2835: Add support for being used as a second level controller The BCM2836 (Raspberry Pi 2) uses two levels of interrupt handling with the CPU-local interrupts being the root, so we need to register ours as chained off of the CPU's local interrupt. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-3-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner --- .../brcm,bcm2835-armctrl-ic.txt | 25 ++++++++++++- drivers/irqchip/irq-bcm2835.c | 43 ++++++++++++++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt index 7da578d72123..2d6c8bb4d827 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt @@ -5,9 +5,14 @@ The BCM2835 contains a custom top-level interrupt controller, which supports controller, or the HW block containing it, is referred to occasionally as "armctrl" in the SoC documentation, hence naming of this binding. +The BCM2836 contains the same interrupt controller with the same +interrupts, but the per-CPU interrupt controller is the root, and an +interrupt there indicates that the ARMCTRL has an interrupt to handle. + Required properties: -- compatible : should be "brcm,bcm2835-armctrl-ic" +- compatible : should be "brcm,bcm2835-armctrl-ic" or + "brcm,bcm2836-armctrl-ic" - reg : Specifies base physical address and size of the registers. - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an @@ -20,6 +25,12 @@ Required properties: The 2nd cell contains the interrupt number within the bank. Valid values are 0..7 for bank 0, and 0..31 for bank 1. +Additional required properties for brcm,bcm2836-armctrl-ic: +- interrupt-parent : Specifies the parent interrupt controller when this + controller is the second level. +- interrupts : Specifies the interrupt on the parent for this interrupt + controller to handle. + The interrupt sources are as follows: Bank 0: @@ -102,9 +113,21 @@ Bank 2: Example: +/* BCM2835, first level */ intc: interrupt-controller { compatible = "brcm,bcm2835-armctrl-ic"; reg = <0x7e00b200 0x200>; interrupt-controller; #interrupt-cells = <2>; }; + +/* BCM2836, second level */ +intc: interrupt-controller { + compatible = "brcm,bcm2836-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&local_intc>; + interrupts = <8>; +}; diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index a40d97268b8a..ed4ca9deca70 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -96,6 +96,7 @@ struct armctrl_ic { static struct armctrl_ic intc __read_mostly; static void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs); +static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc); static void armctrl_mask_irq(struct irq_data *d) { @@ -139,7 +140,8 @@ static const struct irq_domain_ops armctrl_ops = { }; static int __init armctrl_of_init(struct device_node *node, - struct device_node *parent) + struct device_node *parent, + bool is_2836) { void __iomem *base; int irq, b, i; @@ -168,10 +170,34 @@ static int __init armctrl_of_init(struct device_node *node, } } - set_handle_irq(bcm2835_handle_irq); + if (is_2836) { + int parent_irq = irq_of_parse_and_map(node, 0); + + if (!parent_irq) { + panic("%s: unable to get parent interrupt.\n", + node->full_name); + } + irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq); + } else { + set_handle_irq(bcm2835_handle_irq); + } + return 0; } +static int __init bcm2835_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, false); +} + +static int __init bcm2836_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, true); +} + + /* * Handle each interrupt across the entire interrupt controller. This reads the * status register before handling each interrupt, which is necessary given that @@ -219,4 +245,15 @@ static void __exception_irq_entry bcm2835_handle_irq( handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); } -IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); +static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc) +{ + u32 hwirq; + + while ((hwirq = get_next_armctrl_hwirq()) != ~0) + generic_handle_irq(irq_linear_revmap(intc.domain, hwirq)); +} + +IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", + bcm2835_armctrl_of_init); +IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic", + bcm2836_armctrl_of_init); -- cgit v1.2.3-59-g8ed1b From 815e7a31c3f7929f371da9c7e9ee91cfd52ef453 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:32 -0700 Subject: irqchip: Add documentation for the bcm2836 interrupt controller This is a new per-cpu root interrupt controller on the Raspberry Pi 2, which will chain to the bcm2835 interrupt controller for peripheral interrupts. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-4-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner --- .../interrupt-controller/brcm,bcm2836-l1-intc.txt | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt new file mode 100644 index 000000000000..f320dcd6e69b --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt @@ -0,0 +1,37 @@ +BCM2836 per-CPU interrupt controller + +The BCM2836 has a per-cpu interrupt controller for the timer, PMU +events, and SMP IPIs. One of the CPUs may receive interrupts for the +peripheral (GPU) events, which chain to the BCM2835-style interrupt +controller. + +Required properties: + +- compatible: Should be "brcm,bcm2836-l1-intc" +- reg: Specifies base physical address and size of the + registers +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 1 + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +The interrupt sources are as follows: + +0: CNTPSIRQ +1: CNTPNSIRQ +2: CNTHPIRQ +3: CNTVIRQ +8: GPU_FAST +9: PMU_FAST + +Example: + +local_intc: local_intc { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&local_intc>; +}; -- cgit v1.2.3-59-g8ed1b From 4b226fbde68b8bfb66452067523a677b8e6492fa Mon Sep 17 00:00:00 2001 From: Michael van der Westhuizen Date: Tue, 18 Aug 2015 22:21:52 +0200 Subject: dt: snps,dw-apb-ssi: Document new I/O data register width property This change documents a new property for the snps,dw-apb-ssi device, allowing an implementer to specify either four byte or two bytes access to the SPI controller data register. This supports a change that unbreaks this driver on picoXcell platforms. Signed-off-by: Michael van der Westhuizen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt index bd99193e87b9..204b311e0400 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt @@ -10,6 +10,8 @@ Required properties: Optional properties: - cs-gpios : Specifies the gpio pis to be used for chipselects. - num-cs : The number of chipselects. If omitted, this will default to 4. +- reg-io-width : The I/O register width (in bytes) implemented by this + device. Supported values are 2 or 4 (the default). Child nodes as per the generic SPI binding. -- cgit v1.2.3-59-g8ed1b From cebb053bd144d88a4c24b14dd8ac775d8e5972d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 1 Aug 2014 15:50:44 +0200 Subject: of: Add vendor prefix for Sharp Corporation Use "sharp" as the vendor prefix for Sharp Corporation in device tree compatible strings. Signed-off-by: Thierry Reding [robh: fix name to Sharp Corporation] Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9e..9a4ac79038e9 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -181,6 +181,7 @@ sbs Smart Battery System schindler Schindler seagate Seagate Technology PLC semtech Semtech Corporation +sharp Sharp Corporation sil Silicon Image silabs Silicon Laboratories siliconmitus Silicon Mitus, Inc. -- cgit v1.2.3-59-g8ed1b From e4144fe5d47c91c92d36cdbd5f31ed8d6e3a57ab Mon Sep 17 00:00:00 2001 From: Mario Carrillo Date: Mon, 24 Aug 2015 09:33:09 -0500 Subject: docs: update HOWTO for 3.x -> 4.x versioning The HOWTO document needed updating for the new kernel versioning. Signed-off-by: Mario Carrillo Signed-off-by: Jonathan Corbet --- Documentation/HOWTO | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 93aa8604630e..21152d397b88 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -218,16 +218,16 @@ The development process Linux kernel development process currently consists of a few different main kernel "branches" and lots of different subsystem-specific kernel branches. These different branches are: - - main 3.x kernel tree - - 3.x.y -stable kernel tree - - 3.x -git kernel patches + - main 4.x kernel tree + - 4.x.y -stable kernel tree + - 4.x -git kernel patches - subsystem specific kernel trees and patches - - the 3.x -next kernel tree for integration tests + - the 4.x -next kernel tree for integration tests -3.x kernel tree +4.x kernel tree ----------------- -3.x kernels are maintained by Linus Torvalds, and can be found on -kernel.org in the pub/linux/kernel/v3.x/ directory. Its development +4.x kernels are maintained by Linus Torvalds, and can be found on +kernel.org in the pub/linux/kernel/v4.x/ directory. Its development process is as follows: - As soon as a new kernel is released a two weeks window is open, during this period of time maintainers can submit big diffs to @@ -262,20 +262,20 @@ mailing list about kernel releases: released according to perceived bug status, not according to a preconceived timeline." -3.x.y -stable kernel tree +4.x.y -stable kernel tree --------------------------- Kernels with 3-part versions are -stable kernels. They contain relatively small and critical fixes for security problems or significant -regressions discovered in a given 3.x kernel. +regressions discovered in a given 4.x kernel. This is the recommended branch for users who want the most recent stable kernel and are not interested in helping test development/experimental versions. -If no 3.x.y kernel is available, then the highest numbered 3.x +If no 4.x.y kernel is available, then the highest numbered 4.x kernel is the current stable kernel. -3.x.y are maintained by the "stable" team , and +4.x.y are maintained by the "stable" team , and are released as needs dictate. The normal release period is approximately two weeks, but it can be longer if there are no pressing problems. A security-related problem, instead, can cause a release to happen almost @@ -285,7 +285,7 @@ The file Documentation/stable_kernel_rules.txt in the kernel tree documents what kinds of changes are acceptable for the -stable tree, and how the release process works. -3.x -git patches +4.x -git patches ------------------ These are daily snapshots of Linus' kernel tree which are managed in a git repository (hence the name.) These patches are usually released @@ -317,9 +317,9 @@ revisions to it, and maintainers can mark patches as under review, accepted, or rejected. Most of these patchwork sites are listed at http://patchwork.kernel.org/. -3.x -next kernel tree for integration tests +4.x -next kernel tree for integration tests --------------------------------------------- -Before updates from subsystem trees are merged into the mainline 3.x +Before updates from subsystem trees are merged into the mainline 4.x tree, they need to be integration-tested. For this purpose, a special testing repository exists into which virtually all subsystem trees are pulled on an almost daily basis: -- cgit v1.2.3-59-g8ed1b From 61a88a76b43ce35254415821047aeefde3f656a9 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Thu, 20 Aug 2015 18:17:10 +0800 Subject: Documentation/Intel-IOMMU.txt: Modify definition of DRHD Hi all, According to "Intel Virtualization Technology for Directed I/O" specification, DRHD stands for "DMA Remapping Hardware Unit Definition" , not "DMA Engine Reporting Structure". Signed-off-by: Nan Xiao --- Documentation/Intel-IOMMU.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/Intel-IOMMU.txt b/Documentation/Intel-IOMMU.txt index cf9431db8731..7b57fc087088 100644 --- a/Documentation/Intel-IOMMU.txt +++ b/Documentation/Intel-IOMMU.txt @@ -10,7 +10,7 @@ This guide gives a quick cheat sheet for some basic understanding. Some Keywords DMAR - DMA remapping -DRHD - DMA Engine Reporting Structure +DRHD - DMA Remapping Hardware Unit Definition RMRR - Reserved memory Region Reporting Structure ZLR - Zero length reads from PCI devices IOVA - IO Virtual address. -- cgit v1.2.3-59-g8ed1b From 0fe0965e63c80dbc4bb005253ecff3494cbefc04 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Fri, 21 Aug 2015 15:19:06 +0600 Subject: Documentation/x86: Rename IRQSTACKSIZE to IRQ_STACK_SIZE The IRQSTACKSIZE was renamed to the IRQ_STACK_SIZE in the (26f80bd6a9 x86-64: Convert irqstacks to per-cpu) commit, but it still named IRQSTACKSIZE in the documentation. This patch fixes this. Signed-off-by: Alexander Kuleshov Signed-off-by: Jonathan Corbet --- Documentation/x86/kernel-stacks | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/x86/kernel-stacks b/Documentation/x86/kernel-stacks index 0f3a6c201943..9a0aa4d3a866 100644 --- a/Documentation/x86/kernel-stacks +++ b/Documentation/x86/kernel-stacks @@ -16,7 +16,7 @@ associated with each CPU. These stacks are only used while the kernel is in control on that CPU; when a CPU returns to user space the specialized stacks contain no useful data. The main CPU stacks are: -* Interrupt stack. IRQSTACKSIZE +* Interrupt stack. IRQ_STACK_SIZE Used for external hardware interrupts. If this is the first external hardware interrupt (i.e. not a nested hardware interrupt) then the -- cgit v1.2.3-59-g8ed1b From 32ecaf89bdfd842c9669b3f38ff82907e3cd60d0 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Thu, 6 Aug 2015 16:05:13 +0100 Subject: clk: versatile: Add SP810 device tree bindings document Signed-off-by: Pawel Moll Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/arm/sp810.txt | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/sp810.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/sp810.txt b/Documentation/devicetree/bindings/arm/sp810.txt new file mode 100644 index 000000000000..440ee0892a4d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sp810.txt @@ -0,0 +1,35 @@ +SP810 System Controller +----------------------- + +Required properties: + +- compatible: standard compatible string for a Primecell peripheral, + see Documentation/devicetree/bindings/arm/primecell.txt + for more details + should be: "arm,sp810", "arm,primecell" + +- reg: standard registers property, physical address and size + of the control registers + +- clock-names: from the common clock bindings, for more details see + Documentation/devicetree/bindings/clock/clock-bindings.txt; + should be: "refclk", "timclk", "apb_pclk" + +- clocks: from the common clock bindings, phandle and clock + specifier pairs for the entries of clock-names property + +- #clock-cells: from the common clock bindings; + should be: <1> + +- clock-output-names: from the common clock bindings; + should be: "timerclken0", "timerclken1", "timerclken2", "timerclken3" + +Example: + sysctl@020000 { + compatible = "arm,sp810", "arm,primecell"; + reg = <0x020000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; + }; -- cgit v1.2.3-59-g8ed1b From 62f477119834d912a8471e775d2aeaca0166ab29 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 30 Jul 2015 17:20:57 -0700 Subject: clk: versatile: Switch to assigned clock parents We're removing struct clk from the clk provider API. This code is calling the consumer APIs to change the parent to a 1 MHz fixed rate clock for each of the clocks that the driver provides. Move to using the assigned-clock-parents DT property for this instead. Because this is an ABI break, detect if the property is missing and fall back to setting the parent explicitly before the clocks are registered. Acked-by: Pawel Moll Cc: Linus Walleij Tested-by: Sudeep Holla Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/arm/sp810.txt | 13 ++++- drivers/clk/versatile/clk-sp810.c | 76 +++++-------------------- 2 files changed, 27 insertions(+), 62 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/sp810.txt b/Documentation/devicetree/bindings/arm/sp810.txt index 440ee0892a4d..6808fb5dee40 100644 --- a/Documentation/devicetree/bindings/arm/sp810.txt +++ b/Documentation/devicetree/bindings/arm/sp810.txt @@ -24,12 +24,23 @@ Required properties: - clock-output-names: from the common clock bindings; should be: "timerclken0", "timerclken1", "timerclken2", "timerclken3" +- assigned-clocks: from the common clock binding; + should be: clock specifier for each output clock of this + provider node + +- assigned-clock-parents: from the common clock binding; + should be: phandle of input clock listed in clocks + property with the highest frequency + Example: - sysctl@020000 { + v2m_sysctl: sysctl@020000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; clock-names = "refclk", "timclk", "apb_pclk"; #clock-cells = <1>; clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; + assigned-clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_sysctl 3>, <&v2m_sysctl 3>; + assigned-clock-parents = <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>; + }; diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index 7fbe4d4bf35e..a1cdef6b0f90 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -33,12 +33,9 @@ struct clk_sp810_timerclken { struct clk_sp810 { struct device_node *node; - int refclk_index, timclk_index; void __iomem *base; spinlock_t lock; struct clk_sp810_timerclken timerclken[4]; - struct clk *refclk; - struct clk *timclk; }; static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw) @@ -71,55 +68,7 @@ static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index) return 0; } -/* - * FIXME - setting the parent every time .prepare is invoked is inefficient. - * This is better handled by a dedicated clock tree configuration mechanism at - * init-time. Revisit this later when such a mechanism exists - */ -static int clk_sp810_timerclken_prepare(struct clk_hw *hw) -{ - struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); - struct clk_sp810 *sp810 = timerclken->sp810; - struct clk *old_parent = __clk_get_parent(hw->clk); - struct clk *new_parent; - - if (!sp810->refclk) - sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index); - - if (!sp810->timclk) - sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index); - - if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk))) - return -ENOENT; - - /* Select fastest parent */ - if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk)) - new_parent = sp810->refclk; - else - new_parent = sp810->timclk; - - /* Switch the parent if necessary */ - if (old_parent != new_parent) { - clk_prepare(new_parent); - clk_set_parent(hw->clk, new_parent); - clk_unprepare(old_parent); - } - - return 0; -} - -static void clk_sp810_timerclken_unprepare(struct clk_hw *hw) -{ - struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); - struct clk_sp810 *sp810 = timerclken->sp810; - - clk_put(sp810->timclk); - clk_put(sp810->refclk); -} - static const struct clk_ops clk_sp810_timerclken_ops = { - .prepare = clk_sp810_timerclken_prepare, - .unprepare = clk_sp810_timerclken_unprepare, .get_parent = clk_sp810_timerclken_get_parent, .set_parent = clk_sp810_timerclken_set_parent, }; @@ -140,24 +89,18 @@ static void __init clk_sp810_of_setup(struct device_node *node) { struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL); const char *parent_names[2]; + int num = ARRAY_SIZE(parent_names); char name[12]; struct clk_init_data init; int i; + bool deprecated; if (!sp810) { pr_err("Failed to allocate memory for SP810!\n"); return; } - sp810->refclk_index = of_property_match_string(node, "clock-names", - "refclk"); - parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index); - - sp810->timclk_index = of_property_match_string(node, "clock-names", - "timclk"); - parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index); - - if (!parent_names[0] || !parent_names[1]) { + if (of_clk_parent_fill(node, parent_names, num) != num) { pr_warn("Failed to obtain parent clocks for SP810!\n"); return; } @@ -170,7 +113,9 @@ static void __init clk_sp810_of_setup(struct device_node *node) init.ops = &clk_sp810_timerclken_ops; init.flags = CLK_IS_BASIC; init.parent_names = parent_names; - init.num_parents = ARRAY_SIZE(parent_names); + init.num_parents = num; + + deprecated = !of_find_property(node, "assigned-clock-parents", NULL); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); @@ -179,6 +124,15 @@ static void __init clk_sp810_of_setup(struct device_node *node) sp810->timerclken[i].channel = i; sp810->timerclken[i].hw.init = &init; + /* + * If DT isn't setting the parent, force it to be + * the 1 MHz clock without going through the framework. + * We do this before clk_register() so that it can determine + * the parent and setup the tree properly. + */ + if (deprecated) + init.ops->set_parent(&sp810->timerclken[i].hw, 1); + sp810->timerclken[i].clk = clk_register(NULL, &sp810->timerclken[i].hw); WARN_ON(IS_ERR(sp810->timerclken[i].clk)); -- cgit v1.2.3-59-g8ed1b From 7e2a51e0cf75028888e5c670b3a3963e1716bdff Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 4 Aug 2015 15:27:26 +0800 Subject: dt-bindings: arm: Hi6220: add doc for SRAM controller Document "hisilicon,hi6220-sramctrl" for SRAM controller. Signed-off-by: Leo Yan Signed-off-by: Stephen Boyd --- .../devicetree/bindings/arm/hisilicon/hisilicon.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt index c431c67524d6..c733e28e18e5 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt @@ -127,6 +127,24 @@ Example: #clock-cells = <1>; }; + +Hisilicon Hi6220 SRAM controller + +Required properties: +- compatible : "hisilicon,hi6220-sramctrl", "syscon" +- reg : Register address and size + +Hisilicon's SoCs use sram for multiple purpose; on Hi6220 there have several +SRAM banks for power management, modem, security, etc. Further, use "syscon" +managing the common sram which can be shared by multiple modules. + +Example: + /*for Hi6220*/ + sram: sram@fff80000 { + compatible = "hisilicon,hi6220-sramctrl", "syscon"; + reg = <0x0 0xfff80000 0x0 0x12000>; + }; + ----------------------------------------------------------------------- Hisilicon HiP01 system controller -- cgit v1.2.3-59-g8ed1b From 832446e8aaaeaf9365da18f95f01a42e6da27279 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 4 Aug 2015 15:27:27 +0800 Subject: dt-bindings: clk: Hi6220: Document stub clock driver Document the new compatible for stub clock driver which is used for CPU and DDR's dynamic frequency scaling. Signed-off-by: Leo Yan Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/hi6220-clock.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt index 259e30af9597..e4d5feaebc29 100644 --- a/Documentation/devicetree/bindings/clock/hi6220-clock.txt +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt @@ -15,19 +15,36 @@ Required Properties: - "hisilicon,hi6220-sysctrl" - "hisilicon,hi6220-mediactrl" - "hisilicon,hi6220-pmctrl" + - "hisilicon,hi6220-stub-clk" - reg: physical base address of the controller and length of memory mapped region. - #clock-cells: should be 1. -For example: +Optional Properties: + +- hisilicon,hi6220-clk-sram: phandle to the syscon managing the SoC internal sram; + the driver need use the sram to pass parameters for frequency change. + +- mboxes: use the label reference for the mailbox as the first parameter, the + second parameter is the channel number. + +Example 1: sys_ctrl: sys_ctrl@f7030000 { compatible = "hisilicon,hi6220-sysctrl", "syscon"; reg = <0x0 0xf7030000 0x0 0x2000>; #clock-cells = <1>; }; +Example 2: + stub_clock: stub_clock { + compatible = "hisilicon,hi6220-stub-clk"; + hisilicon,hi6220-clk-sram = <&sram>; + #clock-cells = <1>; + mboxes = <&mailbox 1>; + }; + Each clock is assigned an identifier and client nodes use this identifier to specify the clock which they consume. -- cgit v1.2.3-59-g8ed1b From 67c9a1b5dadf05e22d7e2d32604fb2b21bf3f666 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jul 2015 15:20:00 +0200 Subject: clk: add bindings for the Ux500 clocks These Ux500 clocks have been around for years and were never properly documented. Add the proper binding documentation. Cc: Ulf Hansson Signed-off-by: Linus Walleij Acked-by: Michael Turquette Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/ux500.txt | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ux500.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/ux500.txt b/Documentation/devicetree/bindings/clock/ux500.txt new file mode 100644 index 000000000000..e52bd4b72348 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ux500.txt @@ -0,0 +1,64 @@ +Clock bindings for ST-Ericsson Ux500 clocks + +Required properties : +- compatible : shall contain only one of the following: + "stericsson,u8500-clks" + "stericsson,u8540-clks" + "stericsson,u9540-clks" +- reg : shall contain base register location and length for + CLKRST1, 2, 3, 5, and 6 in an array. Note the absence of + CLKRST4, which does not exist. + +Required subnodes: +- prcmu-clock: a subnode with one clock cell for PRCMU (power, + reset, control unit) clocks. The cell indicates which PRCMU + clock in the prcmu-clock node the consumer wants to use. +- prcc-periph-clock: a subnode with two clock cells for + PRCC (programmable reset- and clock controller) peripheral clocks. + The first cell indicates which PRCC block the consumer + wants to use, possible values are 1, 2, 3, 5, 6. The second + cell indicates which clock inside the PRCC block it wants, + possible values are 0 thru 31. +- prcc-kernel-clock: a subnode with two clock cells for + PRCC (programmable reset- and clock controller) kernel clocks + The first cell indicates which PRCC block the consumer + wants to use, possible values are 1, 2, 3, 5, 6. The second + cell indicates which clock inside the PRCC block it wants, + possible values are 0 thru 31. +- rtc32k-clock: a subnode with zero clock cells for the 32kHz + RTC clock. +- smp-twd-clock: a subnode for the ARM SMP Timer Watchdog cluster + with zero clock cells. + +Example: + +clocks { + compatible = "stericsson,u8500-clks"; + /* + * Registers for the CLKRST block on peripheral + * groups 1, 2, 3, 5, 6, + */ + reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>, + <0x8000f000 0x1000>, <0xa03ff000 0x1000>, + <0xa03cf000 0x1000>; + + prcmu_clk: prcmu-clock { + #clock-cells = <1>; + }; + + prcc_pclk: prcc-periph-clock { + #clock-cells = <2>; + }; + + prcc_kclk: prcc-kernel-clock { + #clock-cells = <2>; + }; + + rtc_clk: rtc32k-clock { + #clock-cells = <0>; + }; + + smp_twd_clk: smp-twd-clock { + #clock-cells = <0>; + }; +}; -- cgit v1.2.3-59-g8ed1b From 068627a5978a885b33f0f49da81860ce78c3ac6f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 15:11:21 +0200 Subject: of: Add vendor prefix for JEDEC Solid State Technology Association Add the "jedec" vendor prefix for the "JEDEC Solid State Technology Association" (formerly known as the "Joint Electron Device Engineering Council"), which is already in use in several bindings. Signed-off-by: Geert Uytterhoeven Acked-by: Brian Norris Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 9a4ac79038e9..953aa8f173cf 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -112,6 +112,7 @@ intel Intel Corporation intercontrol Inter Control Group isee ISEE 2007 S.L. isil Intersil +jedec JEDEC Solid State Technology Association karo Ka-Ro electronics GmbH keymile Keymile GmbH kinetic Kinetic Technologies -- cgit v1.2.3-59-g8ed1b From 126b16e2ad98c46aa0f53dbf62f71c09ba6b1d99 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 23 Jul 2015 17:52:43 +0100 Subject: Docs: dt: add generic MSI bindings Currently msi-parent is used in a couple of drivers despite being fairly underspecified. This patch adds a generic binding for MSIs (including the existing msi-parent property) enabling the description of platform devices capable of using MSIs. While MSIs are primarily distinguished by doorbell and payload, some MSI controllers (e.g. the GICv3 ITS) also use side-band information accompanying the write to identify the master which originated the MSI, to allow for sandboxing. This sideband information is non-probeable and needs to be described in the DT. Other MSI controllers may have additional configuration details which need to be described per-master. This patch adds a generic msi-parent binding document, extending the de-facto standard with a new (optional) #msi-cells which can be used to express any per-master configuration and/or sideband data. This is sufficient to describe non-hotpluggable devices. For busses where sideband data may be derived from some bus-specific master ID scheme, other properties will be required to describe the mapping. Signed-off-by: Mark Rutland Acked-by: Marc Zyngier Signed-off-by: Rob Herring --- .../bindings/interrupt-controller/msi.txt | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/msi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/msi.txt b/Documentation/devicetree/bindings/interrupt-controller/msi.txt new file mode 100644 index 000000000000..c60c034dcf19 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/msi.txt @@ -0,0 +1,135 @@ +This document describes the generic device tree binding for MSI controllers and +their master(s). + +Message Signaled Interrupts (MSIs) are a class of interrupts generated by a +write to an MMIO address. + +MSIs were originally specified by PCI (and are used with PCIe), but may also be +used with other busses, and hence a mechanism is required to relate devices on +those busses to the MSI controllers which they are capable of using, +potentially including additional information. + +MSIs are distinguished by some combination of: + +- The doorbell (the MMIO address written to). + + Devices may be configured by software to write to arbitrary doorbells which + they can address. An MSI controller may feature a number of doorbells. + +- The payload (the value written to the doorbell). + + Devices may be configured to write an arbitrary payload chosen by software. + MSI controllers may have restrictions on permitted payloads. + +- Sideband information accompanying the write. + + Typically this is neither configurable nor probeable, and depends on the path + taken through the memory system (i.e. it is a property of the combination of + MSI controller and device rather than a property of either in isolation). + + +MSI controllers: +================ + +An MSI controller signals interrupts to a CPU when a write is made to an MMIO +address by some master. An MSI controller may feature a number of doorbells. + +Required properties: +-------------------- + +- msi-controller: Identifies the node as an MSI controller. + +Optional properties: +-------------------- + +- #msi-cells: The number of cells in an msi-specifier, required if not zero. + + Typically this will encode information related to sideband data, and will + not encode doorbells or payloads as these can be configured dynamically. + + The meaning of the msi-specifier is defined by the device tree binding of + the specific MSI controller. + + +MSI clients +=========== + +MSI clients are devices which generate MSIs. For each MSI they wish to +generate, the doorbell and payload may be configured, though sideband +information may not be configurable. + +Required properties: +-------------------- + +- msi-parent: A list of phandle + msi-specifier pairs, one for each MSI + controller which the device is capable of using. + + This property is unordered, and MSIs may be allocated from any combination of + MSI controllers listed in the msi-parent property. + + If a device has restrictions on the allocation of MSIs, these restrictions + must be described with additional properties. + + When #msi-cells is non-zero, busses with an msi-parent will require + additional properties to describe the relationship between devices on the bus + and the set of MSIs they can potentially generate. + + +Example +======= + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi_a: msi-controller@a { + reg = <0xa 0xf00>; + compatible = "vendor-a,some-controller"; + msi-controller; + /* No sideband data, so #msi-cells omitted */ + }; + + msi_b: msi-controller@b { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + msi_c: msi-controller@c { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + dev@0 { + reg = <0x0 0xf00>; + compatible = "vendor-c,some-device"; + + /* Can only generate MSIs to msi_a */ + msi-parent = <&msi_a>; + }; + + dev@1 { + reg = <0x1 0xf00>; + compatible = "vendor-c,some-device"; + + /* + * Can generate MSIs to either A or B. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>; + }; + + dev@2 { + reg = <0x2 0xf00>; + compatible = "vendor-c,some-device"; + /* + * Has different IDs at each MSI controller. + * Can generate MSIs to all of the MSI controllers. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>, <&msi_c 0x53>; + }; +}; -- cgit v1.2.3-59-g8ed1b From 65be2c79acc3aa0f9c0e8d4871f5a451d854465a Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Thu, 13 Aug 2015 21:47:43 -0500 Subject: cxlflash: Superpipe support Add superpipe supporting infrastructure to device driver for the IBM CXL Flash adapter. This patch allows userspace applications to take advantage of the accelerated I/O features that this adapter provides and bypass the traditional filesystem stack. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Michael Neuling Reviewed-by: Wen Xiong Reviewed-by: Brian King Signed-off-by: James Bottomley --- Documentation/ioctl/ioctl-number.txt | 1 + Documentation/powerpc/cxlflash.txt | 257 +++++ drivers/scsi/cxlflash/Makefile | 2 +- drivers/scsi/cxlflash/common.h | 19 + drivers/scsi/cxlflash/lunmgt.c | 263 +++++ drivers/scsi/cxlflash/main.c | 38 +- drivers/scsi/cxlflash/sislite.h | 5 +- drivers/scsi/cxlflash/superpipe.c | 2014 ++++++++++++++++++++++++++++++++++ drivers/scsi/cxlflash/superpipe.h | 132 +++ include/uapi/scsi/Kbuild | 1 + include/uapi/scsi/cxlflash_ioctl.h | 140 +++ 11 files changed, 2868 insertions(+), 4 deletions(-) create mode 100644 Documentation/powerpc/cxlflash.txt create mode 100644 drivers/scsi/cxlflash/lunmgt.c create mode 100644 drivers/scsi/cxlflash/superpipe.c create mode 100644 drivers/scsi/cxlflash/superpipe.h create mode 100644 include/uapi/scsi/cxlflash_ioctl.h (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d24..9bd118d26a8a 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -314,6 +314,7 @@ Code Seq#(hex) Include File Comments 0xB3 00 linux/mmc/ioctl.h 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h +0xCA 80-8F uapi/scsi/cxlflash_ioctl.h 0xCB 00-1F CBM serial IEC bus in development: 0xCD 01 linux/reiserfs_fs.h diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt new file mode 100644 index 000000000000..f943967f90ce --- /dev/null +++ b/Documentation/powerpc/cxlflash.txt @@ -0,0 +1,257 @@ +Introduction +============ + + The IBM Power architecture provides support for CAPI (Coherent + Accelerator Power Interface), which is available to certain PCIe slots + on Power 8 systems. CAPI can be thought of as a special tunneling + protocol through PCIe that allow PCIe adapters to look like special + purpose co-processors which can read or write an application's + memory and generate page faults. As a result, the host interface to + an adapter running in CAPI mode does not require the data buffers to + be mapped to the device's memory (IOMMU bypass) nor does it require + memory to be pinned. + + On Linux, Coherent Accelerator (CXL) kernel services present CAPI + devices as a PCI device by implementing a virtual PCI host bridge. + This abstraction simplifies the infrastructure and programming + model, allowing for drivers to look similar to other native PCI + device drivers. + + CXL provides a mechanism by which user space applications can + directly talk to a device (network or storage) bypassing the typical + kernel/device driver stack. The CXL Flash Adapter Driver enables a + user space application direct access to Flash storage. + + The CXL Flash Adapter Driver is a kernel module that sits in the + SCSI stack as a low level device driver (below the SCSI disk and + protocol drivers) for the IBM CXL Flash Adapter. This driver is + responsible for the initialization of the adapter, setting up the + special path for user space access, and performing error recovery. It + communicates directly the Flash Accelerator Functional Unit (AFU) + as described in Documentation/powerpc/cxl.txt. + + The cxlflash driver supports two, mutually exclusive, modes of + operation at the device (LUN) level: + + - Any flash device (LUN) can be configured to be accessed as a + regular disk device (i.e.: /dev/sdc). This is the default mode. + + - Any flash device (LUN) can be configured to be accessed from + user space with a special block library. This mode further + specifies the means of accessing the device and provides for + either raw access to the entire LUN (referred to as direct + or physical LUN access) or access to a kernel/AFU-mediated + partition of the LUN (referred to as virtual LUN access). The + segmentation of a disk device into virtual LUNs is assisted + by special translation services provided by the Flash AFU. + +Overview +======== + + The Coherent Accelerator Interface Architecture (CAIA) introduces a + concept of a master context. A master typically has special privileges + granted to it by the kernel or hypervisor allowing it to perform AFU + wide management and control. The master may or may not be involved + directly in each user I/O, but at the minimum is involved in the + initial setup before the user application is allowed to send requests + directly to the AFU. + + The CXL Flash Adapter Driver establishes a master context with the + AFU. It uses memory mapped I/O (MMIO) for this control and setup. The + Adapter Problem Space Memory Map looks like this: + + +-------------------------------+ + | 512 * 64 KB User MMIO | + | (per context) | + | User Accessible | + +-------------------------------+ + | 512 * 128 B per context | + | Provisioning and Control | + | Trusted Process accessible | + +-------------------------------+ + | 64 KB Global | + | Trusted Process accessible | + +-------------------------------+ + + This driver configures itself into the SCSI software stack as an + adapter driver. The driver is the only entity that is considered a + Trusted Process to program the Provisioning and Control and Global + areas in the MMIO Space shown above. The master context driver + discovers all LUNs attached to the CXL Flash adapter and instantiates + scsi block devices (/dev/sdb, /dev/sdc etc.) for each unique LUN + seen from each path. + + Once these scsi block devices are instantiated, an application + written to a specification provided by the block library may get + access to the Flash from user space (without requiring a system call). + + This master context driver also provides a series of ioctls for this + block library to enable this user space access. The driver supports + two modes for accessing the block device. + + The first mode is called a virtual mode. In this mode a single scsi + block device (/dev/sdb) may be carved up into any number of distinct + virtual LUNs. The virtual LUNs may be resized as long as the sum of + the sizes of all the virtual LUNs, along with the meta-data associated + with it does not exceed the physical capacity. + + The second mode is called the physical mode. In this mode a single + block device (/dev/sdb) may be opened directly by the block library + and the entire space for the LUN is available to the application. + + Only the physical mode provides persistence of the data. i.e. The + data written to the block device will survive application exit and + restart and also reboot. The virtual LUNs do not persist (i.e. do + not survive after the application terminates or the system reboots). + + +Block library API +================= + + Applications intending to get access to the CXL Flash from user + space should use the block library, as it abstracts the details of + interfacing directly with the cxlflash driver that are necessary for + performing administrative actions (i.e.: setup, tear down, resize). + The block library can be thought of as a 'user' of services, + implemented as IOCTLs, that are provided by the cxlflash driver + specifically for devices (LUNs) operating in user space access + mode. While it is not a requirement that applications understand + the interface between the block library and the cxlflash driver, + a high-level overview of each supported service (IOCTL) is provided + below. + + The block library can be found on GitHub: + http://www.github.com/mikehollinger/ibmcapikv + + +CXL Flash Driver IOCTLs +======================= + + Users, such as the block library, that wish to interface with a flash + device (LUN) via user space access need to use the services provided + by the cxlflash driver. As these services are implemented as ioctls, + a file descriptor handle must first be obtained in order to establish + the communication channel between a user and the kernel. This file + descriptor is obtained by opening the device special file associated + with the scsi disk device (/dev/sdb) that was created during LUN + discovery. As per the location of the cxlflash driver within the + SCSI protocol stack, this open is actually not seen by the cxlflash + driver. Upon successful open, the user receives a file descriptor + (herein referred to as fd1) that should be used for issuing the + subsequent ioctls listed below. + + The structure definitions for these IOCTLs are available in: + uapi/scsi/cxlflash_ioctl.h + +DK_CXLFLASH_ATTACH +------------------ + + This ioctl obtains, initializes, and starts a context using the CXL + kernel services. These services specify a context id (u16) by which + to uniquely identify the context and its allocated resources. The + services additionally provide a second file descriptor (herein + referred to as fd2) that is used by the block library to initiate + memory mapped I/O (via mmap()) to the CXL flash device and poll for + completion events. This file descriptor is intentionally installed by + this driver and not the CXL kernel services to allow for intermediary + notification and access in the event of a non-user-initiated close(), + such as a killed process. This design point is described in further + detail in the description for the DK_CXLFLASH_DETACH ioctl. + + There are a few important aspects regarding the "tokens" (context id + and fd2) that are provided back to the user: + + - These tokens are only valid for the process under which they + were created. The child of a forked process cannot continue + to use the context id or file descriptor created by its parent. + + - These tokens are only valid for the lifetime of the context and + the process under which they were created. Once either is + destroyed, the tokens are to be considered stale and subsequent + usage will result in errors. + + - When a context is no longer needed, the user shall detach from + the context via the DK_CXLFLASH_DETACH ioctl. + + - A close on fd2 will invalidate the tokens. This operation is not + required by the user. + +DK_CXLFLASH_USER_DIRECT +----------------------- + This ioctl is responsible for transitioning the LUN to direct + (physical) mode access and configuring the AFU for direct access from + user space on a per-context basis. Additionally, the block size and + last logical block address (LBA) are returned to the user. + + As mentioned previously, when operating in user space access mode, + LUNs may be accessed in whole or in part. Only one mode is allowed + at a time and if one mode is active (outstanding references exist), + requests to use the LUN in a different mode are denied. + + The AFU is configured for direct access from user space by adding an + entry to the AFU's resource handle table. The index of the entry is + treated as a resource handle that is returned to the user. The user + is then able to use the handle to reference the LUN during I/O. + +DK_CXLFLASH_RELEASE +------------------- + This ioctl is responsible for releasing a previously obtained + reference to either a physical or virtual LUN. This can be + thought of as the inverse of the DK_CXLFLASH_USER_DIRECT or + DK_CXLFLASH_USER_VIRTUAL ioctls. Upon success, the resource handle + is no longer valid and the entry in the resource handle table is + made available to be used again. + + As part of the release process for virtual LUNs, the virtual LUN + is first resized to 0 to clear out and free the translation tables + associated with the virtual LUN reference. + +DK_CXLFLASH_DETACH +------------------ + This ioctl is responsible for unregistering a context with the + cxlflash driver and release outstanding resources that were + not explicitly released via the DK_CXLFLASH_RELEASE ioctl. Upon + success, all "tokens" which had been provided to the user from the + DK_CXLFLASH_ATTACH onward are no longer valid. + +DK_CXLFLASH_VERIFY +------------------ + This ioctl is used to detect various changes such as the capacity of + the disk changing, the number of LUNs visible changing, etc. In cases + where the changes affect the application (such as a LUN resize), the + cxlflash driver will report the changed state to the application. + + The user calls in when they want to validate that a LUN hasn't been + changed in response to a check condition. As the user is operating out + of band from the kernel, they will see these types of events without + the kernel's knowledge. When encountered, the user's architected + behavior is to call in to this ioctl, indicating what they want to + verify and passing along any appropriate information. For now, only + verifying a LUN change (ie: size different) with sense data is + supported. + +DK_CXLFLASH_RECOVER_AFU +----------------------- + This ioctl is used to drive recovery (if such an action is warranted) + of a specified user context. Any state associated with the user context + is re-established upon successful recovery. + + User contexts are put into an error condition when the device needs to + be reset or is terminating. Users are notified of this error condition + by seeing all 0xF's on an MMIO read. Upon encountering this, the + architected behavior for a user is to call into this ioctl to recover + their context. A user may also call into this ioctl at any time to + check if the device is operating normally. If a failure is returned + from this ioctl, the user is expected to gracefully clean up their + context via release/detach ioctls. Until they do, the context they + hold is not relinquished. The user may also optionally exit the process + at which time the context/resources they held will be freed as part of + the release fop. + +DK_CXLFLASH_MANAGE_LUN +---------------------- + This ioctl is used to switch a LUN from a mode where it is available + for file-system access (legacy), to a mode where it is set aside for + exclusive user space access (superpipe). In case a LUN is visible + across multiple ports and adapters, this ioctl is used to uniquely + identify each LUN by its World Wide Node Name (WWNN). diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile index dc95e203e3af..c14d24c720d6 100644 --- a/drivers/scsi/cxlflash/Makefile +++ b/drivers/scsi/cxlflash/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CXLFLASH) += cxlflash.o -cxlflash-y += main.o +cxlflash-y += main.o superpipe.o lunmgt.o diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index ffdbc572d180..d3e54e61c7a5 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -107,6 +107,17 @@ struct cxlflash_cfg { struct pci_pool *cxlflash_cmd_pool; struct pci_dev *parent_dev; + atomic_t recovery_threads; + struct mutex ctx_recovery_mutex; + struct mutex ctx_tbl_list_mutex; + struct ctx_info *ctx_tbl[MAX_CONTEXT]; + struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ + struct file_operations cxl_fops; + + atomic_t num_user_contexts; + + struct list_head lluns; /* list of llun_info structs */ + wait_queue_head_t tmf_waitq; bool tmf_active; wait_queue_head_t limbo_waitq; @@ -182,4 +193,12 @@ int cxlflash_afu_reset(struct cxlflash_cfg *); struct afu_cmd *cxlflash_cmd_checkout(struct afu *); void cxlflash_cmd_checkin(struct afu_cmd *); int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); +void cxlflash_list_init(void); +void cxlflash_term_global_luns(void); +void cxlflash_free_errpage(void); +int cxlflash_ioctl(struct scsi_device *, int, void __user *); +void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *); +int cxlflash_mark_contexts_error(struct cxlflash_cfg *); +void cxlflash_term_local_luns(struct cxlflash_cfg *); + #endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c new file mode 100644 index 000000000000..66d5bef11ee6 --- /dev/null +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -0,0 +1,263 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#include +#include + +#include "sislite.h" +#include "common.h" +#include "superpipe.h" + +/** + * create_local() - allocate and initialize a local LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: World Wide Node Name for LUN. + * + * Return: Allocated local llun_info structure on success, NULL on failure + */ +static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) +{ + struct llun_info *lli = NULL; + + lli = kzalloc(sizeof(*lli), GFP_KERNEL); + if (unlikely(!lli)) { + pr_err("%s: could not allocate lli\n", __func__); + goto out; + } + + lli->sdev = sdev; + lli->newly_created = true; + lli->host_no = sdev->host->host_no; + + memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); +out: + return lli; +} + +/** + * create_global() - allocate and initialize a global LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: World Wide Node Name for LUN. + * + * Return: Allocated global glun_info structure on success, NULL on failure + */ +static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) +{ + struct glun_info *gli = NULL; + + gli = kzalloc(sizeof(*gli), GFP_KERNEL); + if (unlikely(!gli)) { + pr_err("%s: could not allocate gli\n", __func__); + goto out; + } + + mutex_init(&gli->mutex); + memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); +out: + return gli; +} + +/** + * refresh_local() - find and update local LUN information structure by WWID + * @cfg: Internal structure associated with the host. + * @wwid: WWID associated with LUN. + * + * When the LUN is found, mark it by updating it's newly_created field. + * + * Return: Found local lun_info structure on success, NULL on failure + * If a LUN with the WWID is found in the list, refresh it's state. + */ +static struct llun_info *refresh_local(struct cxlflash_cfg *cfg, u8 *wwid) +{ + struct llun_info *lli, *temp; + + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) + if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) { + lli->newly_created = false; + return lli; + } + + return NULL; +} + +/** + * lookup_global() - find a global LUN information structure by WWID + * @wwid: WWID associated with LUN. + * + * Return: Found global lun_info structure on success, NULL on failure + */ +static struct glun_info *lookup_global(u8 *wwid) +{ + struct glun_info *gli, *temp; + + list_for_each_entry_safe(gli, temp, &global.gluns, list) + if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) + return gli; + + return NULL; +} + +/** + * find_and_create_lun() - find or create a local LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: WWID associated with LUN. + * + * The LUN is kept both in a local list (per adapter) and in a global list + * (across all adapters). Certain attributes of the LUN are local to the + * adapter (such as index, port selection mask etc.). + * The block allocation map is shared across all adapters (i.e. associated + * wih the global list). Since different attributes are associated with + * the per adapter and global entries, allocate two separate structures for each + * LUN (one local, one global). + * + * Keep a pointer back from the local to the global entry. + * + * Return: Found/Allocated local lun_info structure on success, NULL on failure + */ +static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) +{ + struct llun_info *lli = NULL; + struct glun_info *gli = NULL; + struct Scsi_Host *shost = sdev->host; + struct cxlflash_cfg *cfg = shost_priv(shost); + + mutex_lock(&global.mutex); + if (unlikely(!wwid)) + goto out; + + lli = refresh_local(cfg, wwid); + if (lli) + goto out; + + lli = create_local(sdev, wwid); + if (unlikely(!lli)) + goto out; + + gli = lookup_global(wwid); + if (gli) { + lli->parent = gli; + list_add(&lli->list, &cfg->lluns); + goto out; + } + + gli = create_global(sdev, wwid); + if (unlikely(!gli)) { + kfree(lli); + lli = NULL; + goto out; + } + + lli->parent = gli; + list_add(&lli->list, &cfg->lluns); + + list_add(&gli->list, &global.gluns); + +out: + mutex_unlock(&global.mutex); + pr_debug("%s: returning %p\n", __func__, lli); + return lli; +} + +/** + * cxlflash_term_local_luns() - Delete all entries from local LUN list, free. + * @cfg: Internal structure associated with the host. + */ +void cxlflash_term_local_luns(struct cxlflash_cfg *cfg) +{ + struct llun_info *lli, *temp; + + mutex_lock(&global.mutex); + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { + list_del(&lli->list); + kfree(lli); + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_list_init() - initializes the global LUN list + */ +void cxlflash_list_init(void) +{ + INIT_LIST_HEAD(&global.gluns); + mutex_init(&global.mutex); + global.err_page = NULL; +} + +/** + * cxlflash_term_global_luns() - frees resources associated with global LUN list + */ +void cxlflash_term_global_luns(void) +{ + struct glun_info *gli, *temp; + + mutex_lock(&global.mutex); + list_for_each_entry_safe(gli, temp, &global.gluns, list) { + list_del(&gli->list); + kfree(gli); + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_manage_lun() - handles LUN management activities + * @sdev: SCSI device associated with LUN. + * @manage: Manage ioctl data structure. + * + * This routine is used to notify the driver about a LUN's WWID and associate + * SCSI devices (sdev) with a global LUN instance. Additionally it serves to + * change a LUN's operating mode: legacy or superpipe. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_manage_lun(struct scsi_device *sdev, + struct dk_cxlflash_manage_lun *manage) +{ + int rc = 0; + struct llun_info *lli = NULL; + u64 flags = manage->hdr.flags; + u32 chan = sdev->channel; + + lli = find_and_create_lun(sdev, manage->wwid); + pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", + __func__, get_unaligned_le64(&manage->wwid[0]), + get_unaligned_le64(&manage->wwid[8]), + manage->hdr.flags, lli); + if (unlikely(!lli)) { + rc = -ENOMEM; + goto out; + } + + if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { + if (lli->newly_created) + lli->port_sel = CHAN2PORT(chan); + else + lli->port_sel = BOTH_PORTS; + /* Store off lun in unpacked, AFU-friendly format */ + lli->lun_id[chan] = lun_to_lunid(sdev->lun); + sdev->hostdata = lli; + } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { + if (lli->parent->mode != MODE_NONE) + rc = -EBUSY; + else + sdev->hostdata = NULL; + } + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3ae8dca236ef..02d464f41b7f 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -23,6 +23,7 @@ #include #include +#include #include "main.h" #include "sislite.h" @@ -519,7 +520,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) case STATE_NORMAL: cfg->state = STATE_LIMBO; scsi_block_requests(cfg->host); - + cxlflash_mark_contexts_error(cfg); rcr = cxlflash_afu_reset(cfg); if (rcr) { rc = FAILED; @@ -662,6 +663,21 @@ static ssize_t cxlflash_store_lun_mode(struct device *dev, return count; } +/** + * cxlflash_show_ioctl_version() - presents the current ioctl version of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the ioctl version. + * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_ioctl_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); +} + /** * cxlflash_show_dev_mode() - presents the current mode of the device * @dev: Generic device associated with the device. @@ -700,11 +716,13 @@ static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, cxlflash_store_lun_mode); +static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, &dev_attr_port1, &dev_attr_lun_mode, + &dev_attr_ioctl_version, NULL }; @@ -725,6 +743,7 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = CXLFLASH_ADAPTER_NAME, .info = cxlflash_driver_info, + .ioctl = cxlflash_ioctl, .proc_name = CXLFLASH_NAME, .queuecommand = cxlflash_queuecommand, .eh_device_reset_handler = cxlflash_eh_device_reset_handler, @@ -872,9 +891,11 @@ static void cxlflash_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); cfg->state = STATE_FAILTERM; + cxlflash_stop_term_user_contexts(cfg); switch (cfg->init_state) { case INIT_STATE_SCSI: + cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); scsi_host_put(cfg->host); /* Fall through */ @@ -2274,6 +2295,10 @@ static int cxlflash_probe(struct pci_dev *pdev, INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; cfg->lr_port = -1; + mutex_init(&cfg->ctx_tbl_list_mutex); + mutex_init(&cfg->ctx_recovery_mutex); + INIT_LIST_HEAD(&cfg->ctx_err_recovery); + INIT_LIST_HEAD(&cfg->lluns); pci_set_drvdata(pdev, cfg); @@ -2335,6 +2360,7 @@ out_remove: static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { + int rc = 0; struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); struct device *dev = &cfg->dev->dev; @@ -2346,7 +2372,10 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, /* Turn off legacy I/O */ scsi_block_requests(cfg->host); - + rc = cxlflash_mark_contexts_error(cfg); + if (unlikely(rc)) + dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", + __func__, rc); term_mc(cfg, UNDO_START); stop_afu(cfg); @@ -2431,6 +2460,8 @@ static int __init init_cxlflash(void) pr_info("%s: IBM Power CXL Flash Adapter: %s\n", __func__, CXLFLASH_DRIVER_DATE); + cxlflash_list_init(); + return pci_register_driver(&cxlflash_driver); } @@ -2439,6 +2470,9 @@ static int __init init_cxlflash(void) */ static void __exit exit_cxlflash(void) { + cxlflash_term_global_luns(); + cxlflash_free_errpage(); + pci_unregister_driver(&cxlflash_driver); } diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index bf5d39978630..66b889151a4c 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -409,7 +409,10 @@ struct sisl_lxt_entry { }; -/* Per the SISlite spec, RHT entries are to be 16-byte aligned */ +/* + * RHT - Resource Handle Table + * Per the SISlite spec, RHT entries are to be 16-byte aligned + */ struct sisl_rht_entry { struct sisl_lxt_entry *lxt_start; u32 lxt_cnt; diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c new file mode 100644 index 000000000000..3c8bce8bbb0b --- /dev/null +++ b/drivers/scsi/cxlflash/superpipe.c @@ -0,0 +1,2014 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sislite.h" +#include "common.h" +#include "superpipe.h" + +struct cxlflash_global global; + +/** + * marshal_det_to_rele() - translate detach to release structure + * @detach: Destination structure for the translate/copy. + * @rele: Source structure from which to translate/copy. + */ +static void marshal_det_to_rele(struct dk_cxlflash_detach *detach, + struct dk_cxlflash_release *release) +{ + release->hdr = detach->hdr; + release->context_id = detach->context_id; +} + +/** + * cxlflash_free_errpage() - frees resources associated with global error page + */ +void cxlflash_free_errpage(void) +{ + + mutex_lock(&global.mutex); + if (global.err_page) { + __free_page(global.err_page); + global.err_page = NULL; + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_stop_term_user_contexts() - stops/terminates known user contexts + * @cfg: Internal structure associated with the host. + * + * When the host needs to go down, all users must be quiesced and their + * memory freed. This is accomplished by putting the contexts in error + * state which will notify the user and let them 'drive' the tear-down. + * Meanwhile, this routine camps until all user contexts have been removed. + */ +void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int i, found; + + cxlflash_mark_contexts_error(cfg); + + while (true) { + found = false; + + for (i = 0; i < MAX_CONTEXT; i++) + if (cfg->ctx_tbl[i]) { + found = true; + break; + } + + if (!found && list_empty(&cfg->ctx_err_recovery)) + return; + + dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", + __func__); + wake_up_all(&cfg->limbo_waitq); + ssleep(1); + } +} + +/** + * find_error_context() - locates a context by cookie on the error recovery list + * @cfg: Internal structure associated with the host. + * @rctxid: Desired context by id. + * @file: Desired context by file. + * + * Return: Found context on success, NULL on failure + */ +static struct ctx_info *find_error_context(struct cxlflash_cfg *cfg, u64 rctxid, + struct file *file) +{ + struct ctx_info *ctxi; + + list_for_each_entry(ctxi, &cfg->ctx_err_recovery, list) + if ((ctxi->ctxid == rctxid) || (ctxi->file == file)) + return ctxi; + + return NULL; +} + +/** + * get_context() - obtains a validated and locked context reference + * @cfg: Internal structure associated with the host. + * @rctxid: Desired context (raw, un-decoded format). + * @arg: LUN information or file associated with request. + * @ctx_ctrl: Control information to 'steer' desired lookup. + * + * NOTE: despite the name pid, in linux, current->pid actually refers + * to the lightweight process id (tid) and can change if the process is + * multi threaded. The tgid remains constant for the process and only changes + * when the process of fork. For all intents and purposes, think of tgid + * as a pid in the traditional sense. + * + * Return: Validated context on success, NULL on failure + */ +struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, + void *arg, enum ctx_ctrl ctx_ctrl) +{ + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct lun_access *lun_access = NULL; + struct file *file = NULL; + struct llun_info *lli = arg; + u64 ctxid = DECODE_CTXID(rctxid); + int rc; + pid_t pid = current->tgid, ctxpid = 0; + + if (ctx_ctrl & CTX_CTRL_FILE) { + lli = NULL; + file = (struct file *)arg; + } + + if (ctx_ctrl & CTX_CTRL_CLONE) + pid = current->parent->tgid; + + if (likely(ctxid < MAX_CONTEXT)) { + while (true) { + rc = mutex_lock_interruptible(&cfg->ctx_tbl_list_mutex); + if (rc) + goto out; + + ctxi = cfg->ctx_tbl[ctxid]; + if (ctxi) + if ((file && (ctxi->file != file)) || + (!file && (ctxi->ctxid != rctxid))) + ctxi = NULL; + + if ((ctx_ctrl & CTX_CTRL_ERR) || + (!ctxi && (ctx_ctrl & CTX_CTRL_ERR_FALLBACK))) + ctxi = find_error_context(cfg, rctxid, file); + if (!ctxi) { + mutex_unlock(&cfg->ctx_tbl_list_mutex); + goto out; + } + + /* + * Need to acquire ownership of the context while still + * under the table/list lock to serialize with a remove + * thread. Use the 'try' to avoid stalling the + * table/list lock for a single context. + * + * Note that the lock order is: + * + * cfg->ctx_tbl_list_mutex -> ctxi->mutex + * + * Therefore release ctx_tbl_list_mutex before retrying. + */ + rc = mutex_trylock(&ctxi->mutex); + mutex_unlock(&cfg->ctx_tbl_list_mutex); + if (rc) + break; /* got the context's lock! */ + } + + if (ctxi->unavail) + goto denied; + + ctxpid = ctxi->pid; + if (likely(!(ctx_ctrl & CTX_CTRL_NOPID))) + if (pid != ctxpid) + goto denied; + + if (lli) { + list_for_each_entry(lun_access, &ctxi->luns, list) + if (lun_access->lli == lli) + goto out; + goto denied; + } + } + +out: + dev_dbg(dev, "%s: rctxid=%016llX ctxinfo=%p ctxpid=%u pid=%u " + "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, + ctx_ctrl); + + return ctxi; + +denied: + mutex_unlock(&ctxi->mutex); + ctxi = NULL; + goto out; +} + +/** + * put_context() - release a context that was retrieved from get_context() + * @ctxi: Context to release. + * + * For now, releasing the context equates to unlocking it's mutex. + */ +void put_context(struct ctx_info *ctxi) +{ + mutex_unlock(&ctxi->mutex); +} + +/** + * afu_attach() - attach a context to the AFU + * @cfg: Internal structure associated with the host. + * @ctxi: Context to attach. + * + * Upon setting the context capabilities, they must be confirmed with + * a read back operation as the context might have been closed since + * the mailbox was unlocked. When this occurs, registration is failed. + * + * Return: 0 on success, -errno on failure + */ +static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) +{ + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct sisl_ctrl_map *ctrl_map = ctxi->ctrl_map; + int rc = 0; + u64 val; + + /* Unlock cap and restrict user to read/write cmds in translated mode */ + readq_be(&ctrl_map->mbox_r); + val = (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD); + writeq_be(val, &ctrl_map->ctx_cap); + val = readq_be(&ctrl_map->ctx_cap); + if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { + dev_err(dev, "%s: ctx may be closed val=%016llX\n", + __func__, val); + rc = -EAGAIN; + goto out; + } + + /* Set up MMIO registers pointing to the RHT */ + writeq_be((u64)ctxi->rht_start, &ctrl_map->rht_start); + val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(afu->ctx_hndl)); + writeq_be(val, &ctrl_map->rht_cnt_id); +out: + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * read_cap16() - issues a SCSI READ_CAP16 command + * @sdev: SCSI device associated with LUN. + * @lli: LUN destined for capacity request. + * + * Return: 0 on success, -errno on failure + */ +static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct glun_info *gli = lli->parent; + u8 *cmd_buf = NULL; + u8 *scsi_cmd = NULL; + u8 *sense_buf = NULL; + int rc = 0; + int result = 0; + int retry_cnt = 0; + u32 tout = (MC_DISCOVERY_TIMEOUT * HZ); + +retry: + cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); + scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); + sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (unlikely(!cmd_buf || !scsi_cmd || !sense_buf)) { + rc = -ENOMEM; + goto out; + } + + scsi_cmd[0] = SERVICE_ACTION_IN_16; /* read cap(16) */ + scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ + put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); + + dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, + retry_cnt ? "re" : "", scsi_cmd[0]); + + result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, + CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + + if (driver_byte(result) == DRIVER_SENSE) { + result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + if (result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + + scsi_normalize_sense(sense_buf, SCSI_SENSE_BUFFERSIZE, + &sshdr); + switch (sshdr.sense_key) { + case NO_SENSE: + case RECOVERED_ERROR: + /* fall through */ + case NOT_READY: + result &= ~SAM_STAT_CHECK_CONDITION; + break; + case UNIT_ATTENTION: + switch (sshdr.asc) { + case 0x29: /* Power on Reset or Device Reset */ + /* fall through */ + case 0x2A: /* Device capacity changed */ + case 0x3F: /* Report LUNs changed */ + /* Retry the command once more */ + if (retry_cnt++ < 1) { + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + goto retry; + } + } + break; + default: + break; + } + } + } + + if (result) { + dev_err(dev, "%s: command failed, result=0x%x\n", + __func__, result); + rc = -EIO; + goto out; + } + + /* + * Read cap was successful, grab values from the buffer; + * note that we don't need to worry about unaligned access + * as the buffer is allocated on an aligned boundary. + */ + mutex_lock(&gli->mutex); + gli->max_lba = be64_to_cpu(*((u64 *)&cmd_buf[0])); + gli->blk_len = be32_to_cpu(*((u32 *)&cmd_buf[8])); + mutex_unlock(&gli->mutex); + +out: + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + + dev_dbg(dev, "%s: maxlba=%lld blklen=%d rc=%d\n", + __func__, gli->max_lba, gli->blk_len, rc); + return rc; +} + +/** + * get_rhte() - obtains validated resource handle table entry reference + * @ctxi: Context owning the resource handle. + * @rhndl: Resource handle associated with entry. + * @lli: LUN associated with request. + * + * Return: Validated RHTE on success, NULL on failure + */ +struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, + struct llun_info *lli) +{ + struct sisl_rht_entry *rhte = NULL; + + if (unlikely(!ctxi->rht_start)) { + pr_debug("%s: Context does not have allocated RHT!\n", + __func__); + goto out; + } + + if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { + pr_debug("%s: Bad resource handle! (%d)\n", __func__, rhndl); + goto out; + } + + if (unlikely(ctxi->rht_lun[rhndl] != lli)) { + pr_debug("%s: Bad resource handle LUN! (%d)\n", + __func__, rhndl); + goto out; + } + + rhte = &ctxi->rht_start[rhndl]; + if (unlikely(rhte->nmask == 0)) { + pr_debug("%s: Unopened resource handle! (%d)\n", + __func__, rhndl); + rhte = NULL; + goto out; + } + +out: + return rhte; +} + +/** + * rhte_checkout() - obtains free/empty resource handle table entry + * @ctxi: Context owning the resource handle. + * @lli: LUN associated with request. + * + * Return: Free RHTE on success, NULL on failure + */ +struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, + struct llun_info *lli) +{ + struct sisl_rht_entry *rhte = NULL; + int i; + + /* Find a free RHT entry */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) + if (ctxi->rht_start[i].nmask == 0) { + rhte = &ctxi->rht_start[i]; + ctxi->rht_out++; + break; + } + + if (likely(rhte)) + ctxi->rht_lun[i] = lli; + + pr_debug("%s: returning rhte=%p (%d)\n", __func__, rhte, i); + return rhte; +} + +/** + * rhte_checkin() - releases a resource handle table entry + * @ctxi: Context owning the resource handle. + * @rhte: RHTE to release. + */ +void rhte_checkin(struct ctx_info *ctxi, + struct sisl_rht_entry *rhte) +{ + u32 rsrc_handle = rhte - ctxi->rht_start; + + rhte->nmask = 0; + rhte->fp = 0; + ctxi->rht_out--; + ctxi->rht_lun[rsrc_handle] = NULL; +} + +/** + * rhte_format1() - populates a RHTE for format 1 + * @rhte: RHTE to populate. + * @lun_id: LUN ID of LUN associated with RHTE. + * @perm: Desired permissions for RHTE. + * @port_sel: Port selection mask + */ +static void rht_format1(struct sisl_rht_entry *rhte, u64 lun_id, u32 perm, + u32 port_sel) +{ + /* + * Populate the Format 1 RHT entry for direct access (physical + * LUN) using the synchronization sequence defined in the + * SISLite specification. + */ + struct sisl_rht_entry_f1 dummy = { 0 }; + struct sisl_rht_entry_f1 *rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; + + memset(rhte_f1, 0, sizeof(*rhte_f1)); + rhte_f1->fp = SISL_RHT_FP(1U, 0); + dma_wmb(); /* Make setting of format bit visible */ + + rhte_f1->lun_id = lun_id; + dma_wmb(); /* Make setting of LUN id visible */ + + /* + * Use a dummy RHT Format 1 entry to build the second dword + * of the entry that must be populated in a single write when + * enabled (valid bit set to TRUE). + */ + dummy.valid = 0x80; + dummy.fp = SISL_RHT_FP(1U, perm); + dummy.port_sel = port_sel; + rhte_f1->dw = dummy.dw; + + dma_wmb(); /* Make remaining RHT entry fields visible */ +} + +/** + * cxlflash_lun_attach() - attaches a user to a LUN and manages the LUN's mode + * @gli: LUN to attach. + * @mode: Desired mode of the LUN. + * @locked: Mutex status on current thread. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) +{ + int rc = 0; + + if (!locked) + mutex_lock(&gli->mutex); + + if (gli->mode == MODE_NONE) + gli->mode = mode; + else if (gli->mode != mode) { + pr_debug("%s: LUN operating in mode %d, requested mode %d\n", + __func__, gli->mode, mode); + rc = -EINVAL; + goto out; + } + + gli->users++; + WARN_ON(gli->users <= 0); +out: + pr_debug("%s: Returning rc=%d gli->mode=%u gli->users=%u\n", + __func__, rc, gli->mode, gli->users); + if (!locked) + mutex_unlock(&gli->mutex); + return rc; +} + +/** + * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode + * @gli: LUN to detach. + */ +void cxlflash_lun_detach(struct glun_info *gli) +{ + mutex_lock(&gli->mutex); + WARN_ON(gli->mode == MODE_NONE); + if (--gli->users == 0) + gli->mode = MODE_NONE; + pr_debug("%s: gli->users=%u\n", __func__, gli->users); + WARN_ON(gli->users < 0); + mutex_unlock(&gli->mutex); +} + +/** + * _cxlflash_disk_release() - releases the specified resource entry + * @sdev: SCSI device associated with LUN. + * @ctxi: Context owning resources. + * @release: Release ioctl data structure. + * + * Note that the AFU sync should _not_ be performed when the context is sitting + * on the error recovery list. A context on the error recovery list is not known + * to the AFU due to reset. When the context is recovered, it will be reattached + * and made known again to the AFU. + * + * Return: 0 on success, -errno on failure + */ +int _cxlflash_disk_release(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_release *release) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct afu *afu = cfg->afu; + bool put_ctx = false; + + res_hndl_t rhndl = release->rsrc_handle; + + int rc = 0; + u64 ctxid = DECODE_CTXID(release->context_id), + rctxid = release->context_id; + + struct sisl_rht_entry *rhte; + struct sisl_rht_entry_f1 *rhte_f1; + + dev_dbg(dev, "%s: ctxid=%llu rhndl=0x%llx gli->mode=%u gli->users=%u\n", + __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", + __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + __func__, rhndl); + rc = -EINVAL; + goto out; + } + + switch (gli->mode) { + case MODE_PHYSICAL: + /* + * Clear the Format 1 RHT entry for direct access + * (physical LUN) using the synchronization sequence + * defined in the SISLite specification. + */ + rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; + + rhte_f1->valid = 0; + dma_wmb(); /* Make revocation of RHT entry visible */ + + rhte_f1->lun_id = 0; + dma_wmb(); /* Make clearing of LUN id visible */ + + rhte_f1->dw = 0; + dma_wmb(); /* Make RHT entry bottom-half clearing visible */ + + if (!ctxi->err_recovery_active) + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); + break; + default: + WARN(1, "Unsupported LUN mode!"); + goto out; + } + + rhte_checkin(ctxi, rhte); + cxlflash_lun_detach(gli); + +out: + if (put_ctx) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +int cxlflash_disk_release(struct scsi_device *sdev, + struct dk_cxlflash_release *release) +{ + return _cxlflash_disk_release(sdev, NULL, release); +} + +/** + * destroy_context() - releases a context + * @cfg: Internal structure associated with the host. + * @ctxi: Context to release. + * + * Note that the rht_lun member of the context was cut from a single + * allocation when the context was created and therefore does not need + * to be explicitly freed. Also note that we conditionally check for the + * existence of the context control map before clearing the RHT registers + * and context capabilities because it is possible to destroy a context + * while the context is in the error state (previous mapping was removed + * [so we don't have to worry about clearing] and context is waiting for + * a new mapping). + */ +static void destroy_context(struct cxlflash_cfg *cfg, + struct ctx_info *ctxi) +{ + struct afu *afu = cfg->afu; + + WARN_ON(!list_empty(&ctxi->luns)); + + /* Clear RHT registers and drop all capabilities for this context */ + if (afu->afu_map && ctxi->ctrl_map) { + writeq_be(0, &ctxi->ctrl_map->rht_start); + writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); + writeq_be(0, &ctxi->ctrl_map->ctx_cap); + } + + /* Free memory associated with context */ + free_page((ulong)ctxi->rht_start); + kfree(ctxi->rht_lun); + kfree(ctxi); + atomic_dec_if_positive(&cfg->num_user_contexts); +} + +/** + * create_context() - allocates and initializes a context + * @cfg: Internal structure associated with the host. + * @ctx: Previously obtained CXL context reference. + * @ctxid: Previously obtained process element associated with CXL context. + * @adap_fd: Previously obtained adapter fd associated with CXL context. + * @file: Previously obtained file associated with CXL context. + * @perms: User-specified permissions. + * + * The context's mutex is locked when an allocated context is returned. + * + * Return: Allocated context on success, NULL on failure + */ +static struct ctx_info *create_context(struct cxlflash_cfg *cfg, + struct cxl_context *ctx, int ctxid, + int adap_fd, struct file *file, + u32 perms) +{ + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct ctx_info *ctxi = NULL; + struct llun_info **lli = NULL; + struct sisl_rht_entry *rhte; + + ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); + lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); + if (unlikely(!ctxi || !lli)) { + dev_err(dev, "%s: Unable to allocate context!\n", __func__); + goto err; + } + + rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); + if (unlikely(!rhte)) { + dev_err(dev, "%s: Unable to allocate RHT!\n", __func__); + goto err; + } + + ctxi->rht_lun = lli; + ctxi->rht_start = rhte; + ctxi->rht_perms = perms; + + ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; + ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); + ctxi->lfd = adap_fd; + ctxi->pid = current->tgid; /* tgid = pid */ + ctxi->ctx = ctx; + ctxi->file = file; + mutex_init(&ctxi->mutex); + INIT_LIST_HEAD(&ctxi->luns); + INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ + + atomic_inc(&cfg->num_user_contexts); + mutex_lock(&ctxi->mutex); +out: + return ctxi; + +err: + kfree(lli); + kfree(ctxi); + ctxi = NULL; + goto out; +} + +/** + * _cxlflash_disk_detach() - detaches a LUN from a context + * @sdev: SCSI device associated with LUN. + * @ctxi: Context owning resources. + * @detach: Detach ioctl data structure. + * + * As part of the detach, all per-context resources associated with the LUN + * are cleaned up. When detaching the last LUN for a context, the context + * itself is cleaned up and released. + * + * Return: 0 on success, -errno on failure + */ +static int _cxlflash_disk_detach(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_detach *detach) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct lun_access *lun_access, *t; + struct dk_cxlflash_release rel; + bool put_ctx = false; + + int i; + int rc = 0; + int lfd; + u64 ctxid = DECODE_CTXID(detach->context_id), + rctxid = detach->context_id; + + dev_dbg(dev, "%s: ctxid=%llu\n", __func__, ctxid); + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", + __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + /* Cleanup outstanding resources tied to this LUN */ + if (ctxi->rht_out) { + marshal_det_to_rele(detach, &rel); + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { + if (ctxi->rht_lun[i] == lli) { + rel.rsrc_handle = i; + _cxlflash_disk_release(sdev, ctxi, &rel); + } + + /* No need to loop further if we're done */ + if (ctxi->rht_out == 0) + break; + } + } + + /* Take our LUN out of context, free the node */ + list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) + if (lun_access->lli == lli) { + list_del(&lun_access->list); + kfree(lun_access); + lun_access = NULL; + break; + } + + /* Tear down context following last LUN cleanup */ + if (list_empty(&ctxi->luns)) { + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + + /* Might not have been in error list so conditionally remove */ + if (!list_empty(&ctxi->list)) + list_del(&ctxi->list); + cfg->ctx_tbl[ctxid] = NULL; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + mutex_unlock(&ctxi->mutex); + + lfd = ctxi->lfd; + destroy_context(cfg, ctxi); + ctxi = NULL; + put_ctx = false; + + /* + * As a last step, clean up external resources when not + * already on an external cleanup thread, i.e.: close(adap_fd). + * + * NOTE: this will free up the context from the CXL services, + * allowing it to dole out the same context_id on a future + * (or even currently in-flight) disk_attach operation. + */ + if (lfd != -1) + sys_close(lfd); + } + +out: + if (put_ctx) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +static int cxlflash_disk_detach(struct scsi_device *sdev, + struct dk_cxlflash_detach *detach) +{ + return _cxlflash_disk_detach(sdev, NULL, detach); +} + +/** + * cxlflash_cxl_release() - release handler for adapter file descriptor + * @inode: File-system inode associated with fd. + * @file: File installed with adapter file descriptor. + * + * This routine is the release handler for the fops registered with + * the CXL services on an initial attach for a context. It is called + * when a close is performed on the adapter file descriptor returned + * to the user. Programmatically, the user is not required to perform + * the close, as it is handled internally via the detach ioctl when + * a context is being removed. Note that nothing prevents the user + * from performing a close, but the user should be aware that doing + * so is considered catastrophic and subsequent usage of the superpipe + * API with previously saved off tokens will fail. + * + * When initiated from an external close (either by the user or via + * a process tear down), the routine derives the context reference + * and calls detach for each LUN associated with the context. The + * final detach operation will cause the context itself to be freed. + * Note that the saved off lfd is reset prior to calling detach to + * signify that the final detach should not perform a close. + * + * When initiated from a detach operation as part of the tear down + * of a context, the context is first completely freed and then the + * close is performed. This routine will fail to derive the context + * reference (due to the context having already been freed) and then + * call into the CXL release entry point. + * + * Thus, with exception to when the CXL process element (context id) + * lookup fails (a case that should theoretically never occur), every + * call into this routine results in a complete freeing of a context. + * + * As part of the detach, all per-context resources associated with the LUN + * are cleaned up. When detaching the last LUN for a context, the context + * itself is cleaned up and released. + * + * Return: 0 on success + */ +static int cxlflash_cxl_release(struct inode *inode, struct file *file) +{ + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct dk_cxlflash_detach detach = { { 0 }, 0 }; + struct lun_access *lun_access, *t; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int ctxid; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + goto out; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); + if (!ctxi) { + dev_dbg(dev, "%s: Context %d already free!\n", + __func__, ctxid); + goto out_release; + } + + dev_dbg(dev, "%s: Another process owns context %d!\n", + __func__, ctxid); + put_context(ctxi); + goto out; + } + + dev_dbg(dev, "%s: close(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + /* Reset the file descriptor to indicate we're on a close() thread */ + ctxi->lfd = -1; + detach.context_id = ctxi->ctxid; + list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) + _cxlflash_disk_detach(lun_access->sdev, ctxi, &detach); +out_release: + cxl_fd_release(inode, file); +out: + dev_dbg(dev, "%s: returning\n", __func__); + return 0; +} + +/** + * unmap_context() - clears a previously established mapping + * @ctxi: Context owning the mapping. + * + * This routine is used to switch between the error notification page + * (dummy page of all 1's) and the real mapping (established by the CXL + * fault handler). + */ +static void unmap_context(struct ctx_info *ctxi) +{ + unmap_mapping_range(ctxi->file->f_mapping, 0, 0, 1); +} + +/** + * get_err_page() - obtains and allocates the error notification page + * + * Return: error notification page on success, NULL on failure + */ +static struct page *get_err_page(void) +{ + struct page *err_page = global.err_page; + + if (unlikely(!err_page)) { + err_page = alloc_page(GFP_KERNEL); + if (unlikely(!err_page)) { + pr_err("%s: Unable to allocate err_page!\n", __func__); + goto out; + } + + memset(page_address(err_page), -1, PAGE_SIZE); + + /* Serialize update w/ other threads to avoid a leak */ + mutex_lock(&global.mutex); + if (likely(!global.err_page)) + global.err_page = err_page; + else { + __free_page(err_page); + err_page = global.err_page; + } + mutex_unlock(&global.mutex); + } + +out: + pr_debug("%s: returning err_page=%p\n", __func__, err_page); + return err_page; +} + +/** + * cxlflash_mmap_fault() - mmap fault handler for adapter file descriptor + * @vma: VM area associated with mapping. + * @vmf: VM fault associated with current fault. + * + * To support error notification via MMIO, faults are 'caught' by this routine + * that was inserted before passing back the adapter file descriptor on attach. + * When a fault occurs, this routine evaluates if error recovery is active and + * if so, installs the error page to 'notify' the user about the error state. + * During normal operation, the fault is simply handled by the original fault + * handler that was installed by CXL services as part of initializing the + * adapter file descriptor. The VMA's page protection bits are toggled to + * indicate cached/not-cached depending on the memory backing the fault. + * + * Return: 0 on success, VM_FAULT_SIGBUS on failure + */ +static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct page *err_page = NULL; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int rc = 0; + int ctxid; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + goto err; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + goto err; + } + + dev_dbg(dev, "%s: fault(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + if (likely(!ctxi->err_recovery_active)) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + rc = ctxi->cxl_mmap_vmops->fault(vma, vmf); + } else { + dev_dbg(dev, "%s: err recovery active, use err_page!\n", + __func__); + + err_page = get_err_page(); + if (unlikely(!err_page)) { + dev_err(dev, "%s: Could not obtain error page!\n", + __func__); + rc = VM_FAULT_RETRY; + goto out; + } + + get_page(err_page); + vmf->page = err_page; + vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); + } + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; + +err: + rc = VM_FAULT_SIGBUS; + goto out; +} + +/* + * Local MMAP vmops to 'catch' faults + */ +static const struct vm_operations_struct cxlflash_mmap_vmops = { + .fault = cxlflash_mmap_fault, +}; + +/** + * cxlflash_cxl_mmap() - mmap handler for adapter file descriptor + * @file: File installed with adapter file descriptor. + * @vma: VM area associated with mapping. + * + * Installs local mmap vmops to 'catch' faults for error notification support. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int ctxid; + int rc = 0; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + rc = -EIO; + goto out; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + rc = -EIO; + goto out; + } + + dev_dbg(dev, "%s: mmap(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + rc = cxl_fd_mmap(file, vma); + if (likely(!rc)) { + /* Insert ourself in the mmap fault handler path */ + ctxi->cxl_mmap_vmops = vma->vm_ops; + vma->vm_ops = &cxlflash_mmap_vmops; + } + +out: + if (likely(ctxi)) + put_context(ctxi); + return rc; +} + +/* + * Local fops for adapter file descriptor + */ +static const struct file_operations cxlflash_cxl_fops = { + .owner = THIS_MODULE, + .mmap = cxlflash_cxl_mmap, + .release = cxlflash_cxl_release, +}; + +/** + * cxlflash_mark_contexts_error() - move contexts to error state and list + * @cfg: Internal structure associated with the host. + * + * A context is only moved over to the error list when there are no outstanding + * references to it. This ensures that a running operation has completed. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg) +{ + int i, rc = 0; + struct ctx_info *ctxi = NULL; + + mutex_lock(&cfg->ctx_tbl_list_mutex); + + for (i = 0; i < MAX_CONTEXT; i++) { + ctxi = cfg->ctx_tbl[i]; + if (ctxi) { + mutex_lock(&ctxi->mutex); + cfg->ctx_tbl[i] = NULL; + list_add(&ctxi->list, &cfg->ctx_err_recovery); + ctxi->err_recovery_active = true; + ctxi->ctrl_map = NULL; + unmap_context(ctxi); + mutex_unlock(&ctxi->mutex); + } + } + + mutex_unlock(&cfg->ctx_tbl_list_mutex); + return rc; +} + +/* + * Dummy NULL fops + */ +static const struct file_operations null_fops = { + .owner = THIS_MODULE, +}; + +/** + * cxlflash_disk_attach() - attach a LUN to a context + * @sdev: SCSI device associated with LUN. + * @attach: Attach ioctl data structure. + * + * Creates a context and attaches LUN to it. A LUN can only be attached + * one time to a context (subsequent attaches for the same context/LUN pair + * are not supported). Additional LUNs can be attached to a context by + * specifying the 'reuse' flag defined in the cxlflash_ioctl.h header. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_attach(struct scsi_device *sdev, + struct dk_cxlflash_attach *attach) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct cxl_ioctl_start_work *work; + struct ctx_info *ctxi = NULL; + struct lun_access *lun_access = NULL; + int rc = 0; + u32 perms; + int ctxid = -1; + u64 rctxid = 0UL; + struct file *file; + + struct cxl_context *ctx; + + int fd = -1; + + /* On first attach set fileops */ + if (atomic_read(&cfg->num_user_contexts) == 0) + cfg->cxl_fops = cxlflash_cxl_fops; + + if (attach->num_interrupts > 4) { + dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", + __func__, attach->num_interrupts); + rc = -EINVAL; + goto out; + } + + if (gli->max_lba == 0) { + dev_dbg(dev, "%s: No capacity info for this LUN (%016llX)\n", + __func__, lli->lun_id[sdev->channel]); + rc = read_cap16(sdev, lli); + if (rc) { + dev_err(dev, "%s: Invalid device! (%d)\n", + __func__, rc); + rc = -ENODEV; + goto out; + } + dev_dbg(dev, "%s: LBA = %016llX\n", __func__, gli->max_lba); + dev_dbg(dev, "%s: BLK_LEN = %08X\n", __func__, gli->blk_len); + } + + if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { + rctxid = attach->context_id; + ctxi = get_context(cfg, rctxid, NULL, 0); + if (!ctxi) { + dev_dbg(dev, "%s: Bad context! (%016llX)\n", + __func__, rctxid); + rc = -EINVAL; + goto out; + } + + list_for_each_entry(lun_access, &ctxi->luns, list) + if (lun_access->lli == lli) { + dev_dbg(dev, "%s: Already attached!\n", + __func__); + rc = -EINVAL; + goto out; + } + } + + lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); + if (unlikely(!lun_access)) { + dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); + rc = -ENOMEM; + goto out; + } + + lun_access->lli = lli; + lun_access->sdev = sdev; + + /* Non-NULL context indicates reuse */ + if (ctxi) { + dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", + __func__, rctxid); + list_add(&lun_access->list, &ctxi->luns); + fd = ctxi->lfd; + goto out_attach; + } + + ctx = cxl_dev_context_init(cfg->dev); + if (unlikely(IS_ERR_OR_NULL(ctx))) { + dev_err(dev, "%s: Could not initialize context %p\n", + __func__, ctx); + rc = -ENODEV; + goto err0; + } + + ctxid = cxl_process_element(ctx); + if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { + dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + rc = -EPERM; + goto err1; + } + + file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); + if (unlikely(fd < 0)) { + rc = -ENODEV; + dev_err(dev, "%s: Could not get file descriptor\n", __func__); + goto err1; + } + + /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ + perms = SISL_RHT_PERM(attach->hdr.flags + 1); + + ctxi = create_context(cfg, ctx, ctxid, fd, file, perms); + if (unlikely(!ctxi)) { + dev_err(dev, "%s: Failed to create context! (%d)\n", + __func__, ctxid); + goto err2; + } + + work = &ctxi->work; + work->num_interrupts = attach->num_interrupts; + work->flags = CXL_START_WORK_NUM_IRQS; + + rc = cxl_start_work(ctx, work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err3; + } + + rc = afu_attach(cfg, ctxi); + if (unlikely(rc)) { + dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); + goto err4; + } + + /* + * No error paths after this point. Once the fd is installed it's + * visible to user space and can't be undone safely on this thread. + * There is no need to worry about a deadlock here because no one + * knows about us yet; we can be the only one holding our mutex. + */ + list_add(&lun_access->list, &ctxi->luns); + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + cfg->ctx_tbl[ctxid] = ctxi; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + fd_install(fd, file); + +out_attach: + attach->hdr.return_flags = 0; + attach->context_id = ctxi->ctxid; + attach->block_size = gli->blk_len; + attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); + attach->last_lba = gli->max_lba; + attach->max_xfer = (sdev->host->max_sectors * 512) / gli->blk_len; + +out: + attach->adap_fd = fd; + + if (ctxi) + put_context(ctxi); + + dev_dbg(dev, "%s: returning ctxid=%d fd=%d bs=%lld rc=%d llba=%lld\n", + __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); + return rc; + +err4: + cxl_stop_context(ctx); +err3: + put_context(ctxi); + destroy_context(cfg, ctxi); + ctxi = NULL; +err2: + /* + * Here, we're overriding the fops with a dummy all-NULL fops because + * fput() calls the release fop, which will cause us to mistakenly + * call into the CXL code. Rather than try to add yet more complexity + * to that routine (cxlflash_cxl_release) we should try to fix the + * issue here. + */ + file->f_op = &null_fops; + fput(file); + put_unused_fd(fd); + fd = -1; +err1: + cxl_release_context(ctx); +err0: + kfree(lun_access); + goto out; +} + +/** + * recover_context() - recovers a context in error + * @cfg: Internal structure associated with the host. + * @ctxi: Context to release. + * + * Restablishes the state for a context-in-error. + * + * Return: 0 on success, -errno on failure + */ +static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + int old_fd, fd = -1; + int ctxid = -1; + struct file *file; + struct cxl_context *ctx; + struct afu *afu = cfg->afu; + + ctx = cxl_dev_context_init(cfg->dev); + if (unlikely(IS_ERR_OR_NULL(ctx))) { + dev_err(dev, "%s: Could not initialize context %p\n", + __func__, ctx); + rc = -ENODEV; + goto out; + } + + ctxid = cxl_process_element(ctx); + if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { + dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + rc = -EPERM; + goto err1; + } + + file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); + if (unlikely(fd < 0)) { + rc = -ENODEV; + dev_err(dev, "%s: Could not get file descriptor\n", __func__); + goto err1; + } + + rc = cxl_start_work(ctx, &ctxi->work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err2; + } + + /* Update with new MMIO area based on updated context id */ + ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; + + rc = afu_attach(cfg, ctxi); + if (rc) { + dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); + goto err3; + } + + /* + * No error paths after this point. Once the fd is installed it's + * visible to user space and can't be undone safely on this thread. + */ + old_fd = ctxi->lfd; + ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); + ctxi->lfd = fd; + ctxi->ctx = ctx; + ctxi->file = file; + + /* + * Put context back in table (note the reinit of the context list); + * we must first drop the context's mutex and then acquire it in + * order with the table/list mutex to avoid a deadlock - safe to do + * here because no one can find us at this moment in time. + */ + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + list_del_init(&ctxi->list); + cfg->ctx_tbl[ctxid] = ctxi; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + fd_install(fd, file); + + /* Release the original adapter fd and associated CXL resources */ + sys_close(old_fd); +out: + dev_dbg(dev, "%s: returning ctxid=%d fd=%d rc=%d\n", + __func__, ctxid, fd, rc); + return rc; + +err3: + cxl_stop_context(ctx); +err2: + fput(file); + put_unused_fd(fd); +err1: + cxl_release_context(ctx); + goto out; +} + +/** + * check_state() - checks and responds to the current adapter state + * @cfg: Internal structure associated with the host. + * + * This routine can block and should only be used on process context. + * Note that when waking up from waiting in limbo, the state is unknown + * and must be checked again before proceeding. + * + * Return: 0 on success, -errno on failure + */ +static int check_state(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + +retry: + switch (cfg->state) { + case STATE_LIMBO: + dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__); + rc = wait_event_interruptible(cfg->limbo_waitq, + cfg->state != STATE_LIMBO); + if (unlikely(rc)) + break; + goto retry; + case STATE_FAILTERM: + dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + rc = -ENODEV; + break; + default: + break; + } + + return rc; +} + +/** + * cxlflash_afu_recover() - initiates AFU recovery + * @sdev: SCSI device associated with LUN. + * @recover: Recover ioctl data structure. + * + * Only a single recovery is allowed at a time to avoid exhausting CXL + * resources (leading to recovery failure) in the event that we're up + * against the maximum number of contexts limit. For similar reasons, + * a context recovery is retried if there are multiple recoveries taking + * place at the same time and the failure was due to CXL services being + * unable to keep up. + * + * Because a user can detect an error condition before the kernel, it is + * quite possible for this routine to act as the kernel's EEH detection + * source (MMIO read of mbox_r). Because of this, there is a window of + * time where an EEH might have been detected but not yet 'serviced' + * (callback invoked, causing the device to enter limbo state). To avoid + * looping in this routine during that window, a 1 second sleep is in place + * between the time the MMIO failure is detected and the time a wait on the + * limbo wait queue is attempted via check_state(). + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_afu_recover(struct scsi_device *sdev, + struct dk_cxlflash_recover_afu *recover) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct afu *afu = cfg->afu; + struct ctx_info *ctxi = NULL; + struct mutex *mutex = &cfg->ctx_recovery_mutex; + u64 ctxid = DECODE_CTXID(recover->context_id), + rctxid = recover->context_id; + long reg; + int lretry = 20; /* up to 2 seconds */ + int rc = 0; + + atomic_inc(&cfg->recovery_threads); + rc = mutex_lock_interruptible(mutex); + if (rc) + goto out; + + dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n", + __func__, recover->reason, rctxid); + +retry: + /* Ensure that this process is attached to the context */ + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + if (ctxi->err_recovery_active) { +retry_recover: + rc = recover_context(cfg, ctxi); + if (unlikely(rc)) { + dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n", + __func__, ctxid, rc); + if ((rc == -ENODEV) && + ((atomic_read(&cfg->recovery_threads) > 1) || + (lretry--))) { + dev_dbg(dev, "%s: Going to try again!\n", + __func__); + mutex_unlock(mutex); + msleep(100); + rc = mutex_lock_interruptible(mutex); + if (rc) + goto out; + goto retry_recover; + } + + goto out; + } + + ctxi->err_recovery_active = false; + recover->context_id = ctxi->ctxid; + recover->adap_fd = ctxi->lfd; + recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); + recover->hdr.return_flags |= + DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; + goto out; + } + + /* Test if in error state */ + reg = readq_be(&afu->ctrl_map->mbox_r); + if (reg == -1) { + dev_dbg(dev, "%s: MMIO read fail! Wait for recovery...\n", + __func__); + mutex_unlock(&ctxi->mutex); + ctxi = NULL; + ssleep(1); + rc = check_state(cfg); + if (unlikely(rc)) + goto out; + goto retry; + } + + dev_dbg(dev, "%s: MMIO working, no recovery required!\n", __func__); +out: + if (likely(ctxi)) + put_context(ctxi); + mutex_unlock(mutex); + atomic_dec_if_positive(&cfg->recovery_threads); + return rc; +} + +/** + * process_sense() - evaluates and processes sense data + * @sdev: SCSI device associated with LUN. + * @verify: Verify ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +static int process_sense(struct scsi_device *sdev, + struct dk_cxlflash_verify *verify) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + u64 prev_lba = gli->max_lba; + struct scsi_sense_hdr sshdr = { 0 }; + int rc = 0; + + rc = scsi_normalize_sense((const u8 *)&verify->sense_data, + DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); + if (!rc) { + dev_err(dev, "%s: Failed to normalize sense data!\n", __func__); + rc = -EINVAL; + goto out; + } + + switch (sshdr.sense_key) { + case NO_SENSE: + case RECOVERED_ERROR: + /* fall through */ + case NOT_READY: + break; + case UNIT_ATTENTION: + switch (sshdr.asc) { + case 0x29: /* Power on Reset or Device Reset */ + /* fall through */ + case 0x2A: /* Device settings/capacity changed */ + rc = read_cap16(sdev, lli); + if (rc) { + rc = -ENODEV; + break; + } + if (prev_lba != gli->max_lba) + dev_dbg(dev, "%s: Capacity changed old=%lld " + "new=%lld\n", __func__, prev_lba, + gli->max_lba); + break; + case 0x3F: /* Report LUNs changed, Rescan. */ + scsi_scan_host(cfg->host); + break; + default: + rc = -EIO; + break; + } + break; + default: + rc = -EIO; + break; + } +out: + dev_dbg(dev, "%s: sense_key %x asc %x ascq %x rc %d\n", __func__, + sshdr.sense_key, sshdr.asc, sshdr.ascq, rc); + return rc; +} + +/** + * cxlflash_disk_verify() - verifies a LUN is the same and handle size changes + * @sdev: SCSI device associated with LUN. + * @verify: Verify ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_verify(struct scsi_device *sdev, + struct dk_cxlflash_verify *verify) +{ + int rc = 0; + struct ctx_info *ctxi = NULL; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct sisl_rht_entry *rhte = NULL; + res_hndl_t rhndl = verify->rsrc_handle; + u64 ctxid = DECODE_CTXID(verify->context_id), + rctxid = verify->context_id; + u64 last_lba = 0; + + dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llX, hint=%016llX, " + "flags=%016llX\n", __func__, ctxid, verify->rsrc_handle, + verify->hint, verify->hdr.flags); + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + __func__, rhndl); + rc = -EINVAL; + goto out; + } + + /* + * Look at the hint/sense to see if it requires us to redrive + * inquiry (i.e. the Unit attention is due to the WWN changing). + */ + if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { + rc = process_sense(sdev, verify); + if (unlikely(rc)) { + dev_err(dev, "%s: Failed to validate sense data (%d)\n", + __func__, rc); + goto out; + } + } + + switch (gli->mode) { + case MODE_PHYSICAL: + last_lba = gli->max_lba; + break; + default: + WARN(1, "Unsupported LUN mode!"); + } + + verify->last_lba = last_lba; + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d llba=%llX\n", + __func__, rc, verify->last_lba); + return rc; +} + +/** + * decode_ioctl() - translates an encoded ioctl to an easily identifiable string + * @cmd: The ioctl command to decode. + * + * Return: A string identifying the decoded ioctl. + */ +static char *decode_ioctl(int cmd) +{ + switch (cmd) { + case DK_CXLFLASH_ATTACH: + return __stringify_1(DK_CXLFLASH_ATTACH); + case DK_CXLFLASH_USER_DIRECT: + return __stringify_1(DK_CXLFLASH_USER_DIRECT); + case DK_CXLFLASH_RELEASE: + return __stringify_1(DK_CXLFLASH_RELEASE); + case DK_CXLFLASH_DETACH: + return __stringify_1(DK_CXLFLASH_DETACH); + case DK_CXLFLASH_VERIFY: + return __stringify_1(DK_CXLFLASH_VERIFY); + case DK_CXLFLASH_RECOVER_AFU: + return __stringify_1(DK_CXLFLASH_RECOVER_AFU); + case DK_CXLFLASH_MANAGE_LUN: + return __stringify_1(DK_CXLFLASH_MANAGE_LUN); + } + + return "UNKNOWN"; +} + +/** + * cxlflash_disk_direct_open() - opens a direct (physical) disk + * @sdev: SCSI device associated with LUN. + * @arg: UDirect ioctl data structure. + * + * On successful return, the user is informed of the resource handle + * to be used to identify the direct lun and the size (in blocks) of + * the direct lun in last LBA format. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + + struct dk_cxlflash_udirect *pphys = (struct dk_cxlflash_udirect *)arg; + + u64 ctxid = DECODE_CTXID(pphys->context_id), + rctxid = pphys->context_id; + u64 lun_size = 0; + u64 last_lba = 0; + u64 rsrc_handle = -1; + u32 port = CHAN2PORT(sdev->channel); + + int rc = 0; + + struct ctx_info *ctxi = NULL; + struct sisl_rht_entry *rhte = NULL; + + pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + + rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Failed to attach to LUN! (PHYSICAL)\n", + __func__); + goto out; + } + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto err1; + } + + rhte = rhte_checkout(ctxi, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: too many opens for this context\n", __func__); + rc = -EMFILE; /* too many opens */ + goto err1; + } + + rsrc_handle = (rhte - ctxi->rht_start); + + rht_format1(rhte, lli->lun_id[sdev->channel], ctxi->rht_perms, port); + cxlflash_afu_sync(afu, ctxid, rsrc_handle, AFU_LW_SYNC); + + last_lba = gli->max_lba; + pphys->hdr.return_flags = 0; + pphys->last_lba = last_lba; + pphys->rsrc_handle = rsrc_handle; + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning handle 0x%llx rc=%d llba %lld\n", + __func__, rsrc_handle, rc, last_lba); + return rc; + +err1: + cxlflash_lun_detach(gli); + goto out; +} + +/** + * ioctl_common() - common IOCTL handler for driver + * @sdev: SCSI device associated with LUN. + * @cmd: IOCTL command. + * + * Handles common fencing operations that are valid for multiple ioctls. Always + * allow through ioctls that are cleanup oriented in nature, even when operating + * in a failed/terminating state. + * + * Return: 0 on success, -errno on failure + */ +static int ioctl_common(struct scsi_device *sdev, int cmd) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + int rc = 0; + + if (unlikely(!lli)) { + dev_dbg(dev, "%s: Unknown LUN\n", __func__); + rc = -EINVAL; + goto out; + } + + rc = check_state(cfg); + if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { + switch (cmd) { + case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_DETACH: + dev_dbg(dev, "%s: Command override! (%d)\n", + __func__, rc); + rc = 0; + break; + } + } +out: + return rc; +} + +/** + * cxlflash_ioctl() - IOCTL handler for driver + * @sdev: SCSI device associated with LUN. + * @cmd: IOCTL command. + * @arg: Userspace ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +{ + typedef int (*sioctl) (struct scsi_device *, void *); + + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct dk_cxlflash_hdr *hdr; + char buf[sizeof(union cxlflash_ioctls)]; + size_t size = 0; + bool known_ioctl = false; + int idx; + int rc = 0; + struct Scsi_Host *shost = sdev->host; + sioctl do_ioctl = NULL; + + static const struct { + size_t size; + sioctl ioctl; + } ioctl_tbl[] = { /* NOTE: order matters here */ + {sizeof(struct dk_cxlflash_attach), (sioctl)cxlflash_disk_attach}, + {sizeof(struct dk_cxlflash_udirect), cxlflash_disk_direct_open}, + {sizeof(struct dk_cxlflash_release), (sioctl)cxlflash_disk_release}, + {sizeof(struct dk_cxlflash_detach), (sioctl)cxlflash_disk_detach}, + {sizeof(struct dk_cxlflash_verify), (sioctl)cxlflash_disk_verify}, + {sizeof(struct dk_cxlflash_recover_afu), (sioctl)cxlflash_afu_recover}, + {sizeof(struct dk_cxlflash_manage_lun), (sioctl)cxlflash_manage_lun}, + }; + + /* Restrict command set to physical support only for internal LUN */ + if (afu->internal_lun) + switch (cmd) { + case DK_CXLFLASH_RELEASE: + dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", + __func__, decode_ioctl(cmd), afu->internal_lun); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + switch (cmd) { + case DK_CXLFLASH_ATTACH: + case DK_CXLFLASH_USER_DIRECT: + case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_DETACH: + case DK_CXLFLASH_VERIFY: + case DK_CXLFLASH_RECOVER_AFU: + dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", + __func__, decode_ioctl(cmd), cmd, shost->host_no, + sdev->channel, sdev->id, sdev->lun); + rc = ioctl_common(sdev, cmd); + if (unlikely(rc)) + goto cxlflash_ioctl_exit; + + /* fall through */ + + case DK_CXLFLASH_MANAGE_LUN: + known_ioctl = true; + idx = _IOC_NR(cmd) - _IOC_NR(DK_CXLFLASH_ATTACH); + size = ioctl_tbl[idx].size; + do_ioctl = ioctl_tbl[idx].ioctl; + + if (likely(do_ioctl)) + break; + + /* fall through */ + default: + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + if (unlikely(copy_from_user(&buf, arg, size))) { + dev_err(dev, "%s: copy_from_user() fail! " + "size=%lu cmd=%d (%s) arg=%p\n", + __func__, size, cmd, decode_ioctl(cmd), arg); + rc = -EFAULT; + goto cxlflash_ioctl_exit; + } + + hdr = (struct dk_cxlflash_hdr *)&buf; + if (hdr->version != DK_CXLFLASH_VERSION_0) { + dev_dbg(dev, "%s: Version %u not supported for %s\n", + __func__, hdr->version, decode_ioctl(cmd)); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { + dev_dbg(dev, "%s: Reserved/rflags populated!\n", __func__); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + rc = do_ioctl(sdev, (void *)&buf); + if (likely(!rc)) + if (unlikely(copy_to_user(arg, &buf, size))) { + dev_err(dev, "%s: copy_to_user() fail! " + "size=%lu cmd=%d (%s) arg=%p\n", + __func__, size, cmd, decode_ioctl(cmd), arg); + rc = -EFAULT; + } + + /* fall through to exit */ + +cxlflash_ioctl_exit: + if (unlikely(rc && known_ioctl)) + dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " + "returned rc %d\n", __func__, + decode_ioctl(cmd), cmd, shost->host_no, + sdev->channel, sdev->id, sdev->lun, rc); + else + dev_dbg(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " + "returned rc %d\n", __func__, decode_ioctl(cmd), + cmd, shost->host_no, sdev->channel, sdev->id, + sdev->lun, rc); + return rc; +} diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h new file mode 100644 index 000000000000..ae39b9627118 --- /dev/null +++ b/drivers/scsi/cxlflash/superpipe.h @@ -0,0 +1,132 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CXLFLASH_SUPERPIPE_H +#define _CXLFLASH_SUPERPIPE_H + +extern struct cxlflash_global global; + +/* + * Terminology: use afu (and not adapter) to refer to the HW. + * Adapter is the entire slot and includes PSL out of which + * only the AFU is visible to user space. + */ + +/* Chunk size parms: note sislite minimum chunk size is + 0x10000 LBAs corresponding to a NMASK or 16. +*/ +#define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ + +#define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ + +#define CHAN2PORT(_x) ((_x) + 1) + +enum lun_mode { + MODE_NONE = 0, + MODE_PHYSICAL +}; + +/* Global (entire driver, spans adapters) lun_info structure */ +struct glun_info { + u64 max_lba; /* from read cap(16) */ + u32 blk_len; /* from read cap(16) */ + enum lun_mode mode; /* NONE, PHYSICAL */ + int users; /* Number of users w/ references to LUN */ + + u8 wwid[16]; + + struct mutex mutex; + + struct list_head list; +}; + +/* Local (per-adapter) lun_info structure */ +struct llun_info { + u64 lun_id[CXLFLASH_NUM_FC_PORTS]; /* from REPORT_LUNS */ + u32 lun_index; /* Index in the LUN table */ + u32 host_no; /* host_no from Scsi_host */ + u32 port_sel; /* What port to use for this LUN */ + bool newly_created; /* Whether the LUN was just discovered */ + + u8 wwid[16]; /* Keep a duplicate copy here? */ + + struct glun_info *parent; /* Pointer to entry in global LUN structure */ + struct scsi_device *sdev; + struct list_head list; +}; + +struct lun_access { + struct llun_info *lli; + struct scsi_device *sdev; + struct list_head list; +}; + +enum ctx_ctrl { + CTX_CTRL_CLONE = (1 << 1), + CTX_CTRL_ERR = (1 << 2), + CTX_CTRL_ERR_FALLBACK = (1 << 3), + CTX_CTRL_NOPID = (1 << 4), + CTX_CTRL_FILE = (1 << 5) +}; + +#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0) << 28) | _id) +#define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) + +struct ctx_info { + struct sisl_ctrl_map *ctrl_map; /* initialized at startup */ + struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), + alloc/free on attach/detach */ + u32 rht_out; /* Number of checked out RHT entries */ + u32 rht_perms; /* User-defined permissions for RHT entries */ + struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ + + struct cxl_ioctl_start_work work; + u64 ctxid; + int lfd; + pid_t pid; + bool unavail; + bool err_recovery_active; + struct mutex mutex; /* Context protection */ + struct cxl_context *ctx; + struct list_head luns; /* LUNs attached to this context */ + const struct vm_operations_struct *cxl_mmap_vmops; + struct file *file; + struct list_head list; /* Link contexts in error recovery */ +}; + +struct cxlflash_global { + struct mutex mutex; + struct list_head gluns;/* list of glun_info structs */ + struct page *err_page; /* One page of all 0xF for error notification */ +}; + +int cxlflash_disk_release(struct scsi_device *, struct dk_cxlflash_release *); +int _cxlflash_disk_release(struct scsi_device *, struct ctx_info *, + struct dk_cxlflash_release *); + +int cxlflash_lun_attach(struct glun_info *, enum lun_mode, bool); +void cxlflash_lun_detach(struct glun_info *); + +struct ctx_info *get_context(struct cxlflash_cfg *, u64, void *, enum ctx_ctrl); +void put_context(struct ctx_info *); + +struct sisl_rht_entry *get_rhte(struct ctx_info *, res_hndl_t, + struct llun_info *); + +struct sisl_rht_entry *rhte_checkout(struct ctx_info *, struct llun_info *); +void rhte_checkin(struct ctx_info *, struct sisl_rht_entry *); + +int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); + +#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/include/uapi/scsi/Kbuild b/include/uapi/scsi/Kbuild index 75746d52f208..d791e0ad509d 100644 --- a/include/uapi/scsi/Kbuild +++ b/include/uapi/scsi/Kbuild @@ -3,3 +3,4 @@ header-y += fc/ header-y += scsi_bsg_fc.h header-y += scsi_netlink.h header-y += scsi_netlink_fc.h +header-y += cxlflash_ioctl.h diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h new file mode 100644 index 000000000000..570773406531 --- /dev/null +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -0,0 +1,140 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CXLFLASH_IOCTL_H +#define _CXLFLASH_IOCTL_H + +#include + +/* + * Structure and flag definitions CXL Flash superpipe ioctls + */ + +#define DK_CXLFLASH_VERSION_0 0 + +struct dk_cxlflash_hdr { + __u16 version; /* Version data */ + __u16 rsvd[3]; /* Reserved for future use */ + __u64 flags; /* Input flags */ + __u64 return_flags; /* Returned flags */ +}; + +/* + * Notes: + * ----- + * The 'context_id' field of all ioctl structures contains the context + * identifier for a context in the lower 32-bits (upper 32-bits are not + * to be used when identifying a context to the AFU). That said, the value + * in its entirety (all 64-bits) is to be treated as an opaque cookie and + * should be presented as such when issuing ioctls. + * + * For DK_CXLFLASH_ATTACH ioctl, user specifies read/write access + * permissions via the O_RDONLY, O_WRONLY, and O_RDWR flags defined in + * the fcntl.h header file. + */ +#define DK_CXLFLASH_ATTACH_REUSE_CONTEXT 0x8000000000000000ULL + +struct dk_cxlflash_attach { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 num_interrupts; /* Requested number of interrupts */ + __u64 context_id; /* Returned context */ + __u64 mmio_size; /* Returned size of MMIO area */ + __u64 block_size; /* Returned block size, in bytes */ + __u64 adap_fd; /* Returned adapter file descriptor */ + __u64 last_lba; /* Returned last LBA on the device */ + __u64 max_xfer; /* Returned max transfer size, blocks */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_detach { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to detach */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_udirect { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to own physical resources */ + __u64 rsrc_handle; /* Returned resource handle */ + __u64 last_lba; /* Returned last LBA on the device */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_release { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources */ + __u64 rsrc_handle; /* Resource handle to release */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_VERIFY_SENSE_LEN 18 +#define DK_CXLFLASH_VERIFY_HINT_SENSE 0x8000000000000000ULL + +struct dk_cxlflash_verify { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources to verify */ + __u64 rsrc_handle; /* Resource handle of LUN */ + __u64 hint; /* Reasons for verify */ + __u64 last_lba; /* Returned last LBA of device */ + __u8 sense_data[DK_CXLFLASH_VERIFY_SENSE_LEN]; /* SCSI sense data */ + __u8 pad[6]; /* Pad to next 8-byte boundary */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET 0x8000000000000000ULL + +struct dk_cxlflash_recover_afu { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 reason; /* Reason for recovery request */ + __u64 context_id; /* Context to recover / updated ID */ + __u64 mmio_size; /* Returned size of MMIO area */ + __u64 adap_fd; /* Returned adapter file descriptor */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_MANAGE_LUN_WWID_LEN 16 +#define DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE 0x8000000000000000ULL +#define DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE 0x4000000000000000ULL +#define DK_CXLFLASH_MANAGE_LUN_ALL_PORTS_ACCESSIBLE 0x2000000000000000ULL + +struct dk_cxlflash_manage_lun { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u8 wwid[DK_CXLFLASH_MANAGE_LUN_WWID_LEN]; /* Page83 WWID, NAA-6 */ + __u64 reserved[8]; /* Rsvd, future use */ +}; + +union cxlflash_ioctls { + struct dk_cxlflash_attach attach; + struct dk_cxlflash_detach detach; + struct dk_cxlflash_udirect udirect; + struct dk_cxlflash_release release; + struct dk_cxlflash_verify verify; + struct dk_cxlflash_recover_afu recover_afu; + struct dk_cxlflash_manage_lun manage_lun; +}; + +#define MAX_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ioctls)) + +#define CXL_MAGIC 0xCA +#define CXL_IOWR(_n, _s) _IOWR(CXL_MAGIC, _n, struct _s) + +#define DK_CXLFLASH_ATTACH CXL_IOWR(0x80, dk_cxlflash_attach) +#define DK_CXLFLASH_USER_DIRECT CXL_IOWR(0x81, dk_cxlflash_udirect) +#define DK_CXLFLASH_RELEASE CXL_IOWR(0x82, dk_cxlflash_release) +#define DK_CXLFLASH_DETACH CXL_IOWR(0x83, dk_cxlflash_detach) +#define DK_CXLFLASH_VERIFY CXL_IOWR(0x84, dk_cxlflash_verify) +#define DK_CXLFLASH_RECOVER_AFU CXL_IOWR(0x85, dk_cxlflash_recover_afu) +#define DK_CXLFLASH_MANAGE_LUN CXL_IOWR(0x86, dk_cxlflash_manage_lun) + +#endif /* ifndef _CXLFLASH_IOCTL_H */ -- cgit v1.2.3-59-g8ed1b From 2cb79266d6b229dbebd31fe114af1bdab25c8076 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Thu, 13 Aug 2015 21:47:53 -0500 Subject: cxlflash: Virtual LUN support Add support for physical LUN segmentation (virtual LUNs) to device driver supporting the IBM CXL Flash adapter. This patch allows user space applications to virtually segment a physical LUN into N virtual LUNs, taking advantage of the translation features provided by this adapter. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Michael Neuling Reviewed-by: Wen Xiong Signed-off-by: James Bottomley --- Documentation/powerpc/cxlflash.txt | 63 +- drivers/scsi/cxlflash/Makefile | 2 +- drivers/scsi/cxlflash/common.h | 4 + drivers/scsi/cxlflash/lunmgt.c | 3 + drivers/scsi/cxlflash/main.c | 13 + drivers/scsi/cxlflash/sislite.h | 20 +- drivers/scsi/cxlflash/superpipe.c | 82 ++- drivers/scsi/cxlflash/superpipe.h | 17 +- drivers/scsi/cxlflash/vlun.c | 1243 ++++++++++++++++++++++++++++++++++++ drivers/scsi/cxlflash/vlun.h | 86 +++ include/uapi/scsi/cxlflash_ioctl.h | 34 + 11 files changed, 1550 insertions(+), 17 deletions(-) create mode 100644 drivers/scsi/cxlflash/vlun.c create mode 100644 drivers/scsi/cxlflash/vlun.h (limited to 'Documentation') diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index f943967f90ce..4202d1bc583c 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -163,7 +163,8 @@ DK_CXLFLASH_ATTACH - These tokens are only valid for the process under which they were created. The child of a forked process cannot continue - to use the context id or file descriptor created by its parent. + to use the context id or file descriptor created by its parent + (see DK_CXLFLASH_VLUN_CLONE for further details). - These tokens are only valid for the lifetime of the context and the process under which they were created. Once either is @@ -193,6 +194,45 @@ DK_CXLFLASH_USER_DIRECT treated as a resource handle that is returned to the user. The user is then able to use the handle to reference the LUN during I/O. +DK_CXLFLASH_USER_VIRTUAL +------------------------ + This ioctl is responsible for transitioning the LUN to virtual mode + of access and configuring the AFU for virtual access from user space + on a per-context basis. Additionally, the block size and last logical + block address (LBA) are returned to the user. + + As mentioned previously, when operating in user space access mode, + LUNs may be accessed in whole or in part. Only one mode is allowed + at a time and if one mode is active (outstanding references exist), + requests to use the LUN in a different mode are denied. + + The AFU is configured for virtual access from user space by adding + an entry to the AFU's resource handle table. The index of the entry + is treated as a resource handle that is returned to the user. The + user is then able to use the handle to reference the LUN during I/O. + + By default, the virtual LUN is created with a size of 0. The user + would need to use the DK_CXLFLASH_VLUN_RESIZE ioctl to adjust the grow + the virtual LUN to a desired size. To avoid having to perform this + resize for the initial creation of the virtual LUN, the user has the + option of specifying a size as part of the DK_CXLFLASH_USER_VIRTUAL + ioctl, such that when success is returned to the user, the + resource handle that is provided is already referencing provisioned + storage. This is reflected by the last LBA being a non-zero value. + +DK_CXLFLASH_VLUN_RESIZE +----------------------- + This ioctl is responsible for resizing a previously created virtual + LUN and will fail if invoked upon a LUN that is not in virtual + mode. Upon success, an updated last LBA is returned to the user + indicating the new size of the virtual LUN associated with the + resource handle. + + The partitioning of virtual LUNs is jointly mediated by the cxlflash + driver and the AFU. An allocation table is kept for each LUN that is + operating in the virtual mode and used to program a LUN translation + table that the AFU references when provided with a resource handle. + DK_CXLFLASH_RELEASE ------------------- This ioctl is responsible for releasing a previously obtained @@ -214,6 +254,27 @@ DK_CXLFLASH_DETACH success, all "tokens" which had been provided to the user from the DK_CXLFLASH_ATTACH onward are no longer valid. +DK_CXLFLASH_VLUN_CLONE +---------------------- + This ioctl is responsible for cloning a previously created + context to a more recently created context. It exists solely to + support maintaining user space access to storage after a process + forks. Upon success, the child process (which invoked the ioctl) + will have access to the same LUNs via the same resource handle(s) + and fd2 as the parent, but under a different context. + + Context sharing across processes is not supported with CXL and + therefore each fork must be met with establishing a new context + for the child process. This ioctl simplifies the state management + and playback required by a user in such a scenario. When a process + forks, child process can clone the parents context by first creating + a context (via DK_CXLFLASH_ATTACH) and then using this ioctl to + perform the clone from the parent to the child. + + The clone itself is fairly simple. The resource handle and lun + translation tables are copied from the parent context to the child's + and then synced with the AFU. + DK_CXLFLASH_VERIFY ------------------ This ioctl is used to detect various changes such as the capacity of diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile index c14d24c720d6..9e39866d473b 100644 --- a/drivers/scsi/cxlflash/Makefile +++ b/drivers/scsi/cxlflash/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CXLFLASH) += cxlflash.o -cxlflash-y += main.o superpipe.o lunmgt.o +cxlflash-y += main.o superpipe.o lunmgt.o vlun.o diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index d3e54e61c7a5..1c56037146e1 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -116,6 +116,9 @@ struct cxlflash_cfg { atomic_t num_user_contexts; + /* Parameters that are LUN table related */ + int last_lun_index[CXLFLASH_NUM_FC_PORTS]; + int promote_lun_index; struct list_head lluns; /* list of llun_info structs */ wait_queue_head_t tmf_waitq; @@ -200,5 +203,6 @@ int cxlflash_ioctl(struct scsi_device *, int, void __user *); void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *); int cxlflash_mark_contexts_error(struct cxlflash_cfg *); void cxlflash_term_local_luns(struct cxlflash_cfg *); +void cxlflash_restore_luntable(struct cxlflash_cfg *); #endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 66d5bef11ee6..d98ad0ff64c1 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -20,6 +20,7 @@ #include "sislite.h" #include "common.h" +#include "vlun.h" #include "superpipe.h" /** @@ -42,6 +43,7 @@ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) lli->sdev = sdev; lli->newly_created = true; lli->host_no = sdev->host->host_no; + lli->in_table = false; memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); out: @@ -208,6 +210,7 @@ void cxlflash_term_global_luns(void) mutex_lock(&global.mutex); list_for_each_entry_safe(gli, temp, &global.gluns, list) { list_del(&gli->list); + cxlflash_ba_terminate(&gli->blka.ba_lun); kfree(gli); } mutex_unlock(&global.mutex); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 02d464f41b7f..458ed838f83a 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1989,6 +1989,8 @@ static int init_afu(struct cxlflash_cfg *cfg) afu_err_intr_init(cfg->afu); atomic64_set(&afu->room, readq_be(&afu->host_map->cmd_room)); + /* Restore the LUN mappings */ + cxlflash_restore_luntable(cfg); err1: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; @@ -2286,6 +2288,17 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; + + /* + * The promoted LUNs move to the top of the LUN table. The rest stay + * on the bottom half. The bottom half grows from the end + * (index = 255), whereas the top half grows from the beginning + * (index = 0). + */ + cfg->promote_lun_index = 0; + cfg->last_lun_index[0] = CXLFLASH_NUM_VLUNS/2 - 1; + cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1; + cfg->dev_id = (struct pci_device_id *)dev_id; cfg->mcctx = NULL; diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 66b889151a4c..63bf394fe78c 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -397,16 +397,17 @@ struct cxlflash_afu_map { }; }; -/* LBA translation control blocks */ - +/* + * LXT - LBA Translation Table + * LXT control blocks + */ struct sisl_lxt_entry { u64 rlba_base; /* bits 0:47 is base - * b48:55 is lun index - * b58:59 is write & read perms - * (if no perm, afu_rc=0x15) - * b60:63 is port_sel mask - */ - + * b48:55 is lun index + * b58:59 is write & read perms + * (if no perm, afu_rc=0x15) + * b60:63 is port_sel mask + */ }; /* @@ -465,4 +466,7 @@ struct sisl_rht_entry_f1 { #define TMF_LUN_RESET 0x1U #define TMF_CLEAR_ACA 0x2U + +#define SISLITE_MAX_WS_BLOCKS 512 + #endif /* _SISLITE_H */ diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 3c8bce8bbb0b..f1b62cea75b1 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -26,10 +26,24 @@ #include "sislite.h" #include "common.h" +#include "vlun.h" #include "superpipe.h" struct cxlflash_global global; +/** + * marshal_rele_to_resize() - translate release to resize structure + * @rele: Source structure from which to translate/copy. + * @resize: Destination structure for the translate/copy. + */ +static void marshal_rele_to_resize(struct dk_cxlflash_release *release, + struct dk_cxlflash_resize *resize) +{ + resize->hdr = release->hdr; + resize->context_id = release->context_id; + resize->rsrc_handle = release->rsrc_handle; +} + /** * marshal_det_to_rele() - translate detach to release structure * @detach: Destination structure for the translate/copy. @@ -449,6 +463,7 @@ void rhte_checkin(struct ctx_info *ctxi, rhte->fp = 0; ctxi->rht_out--; ctxi->rht_lun[rsrc_handle] = NULL; + ctxi->rht_needs_ws[rsrc_handle] = false; } /** @@ -526,13 +541,21 @@ out: /** * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode * @gli: LUN to detach. + * + * When resetting the mode, terminate block allocation resources as they + * are no longer required (service is safe to call even when block allocation + * resources were not present - such as when transitioning from physical mode). + * These resources will be reallocated when needed (subsequent transition to + * virtual mode). */ void cxlflash_lun_detach(struct glun_info *gli) { mutex_lock(&gli->mutex); WARN_ON(gli->mode == MODE_NONE); - if (--gli->users == 0) + if (--gli->users == 0) { gli->mode = MODE_NONE; + cxlflash_ba_terminate(&gli->blka.ba_lun); + } pr_debug("%s: gli->users=%u\n", __func__, gli->users); WARN_ON(gli->users < 0); mutex_unlock(&gli->mutex); @@ -544,10 +567,12 @@ void cxlflash_lun_detach(struct glun_info *gli) * @ctxi: Context owning resources. * @release: Release ioctl data structure. * - * Note that the AFU sync should _not_ be performed when the context is sitting - * on the error recovery list. A context on the error recovery list is not known - * to the AFU due to reset. When the context is recovered, it will be reattached - * and made known again to the AFU. + * For LUNs in virtual mode, the virtual LUN associated with the specified + * resource handle is resized to 0 prior to releasing the RHTE. Note that the + * AFU sync should _not_ be performed when the context is sitting on the error + * recovery list. A context on the error recovery list is not known to the AFU + * due to reset. When the context is recovered, it will be reattached and made + * known again to the AFU. * * Return: 0 on success, -errno on failure */ @@ -562,6 +587,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct afu *afu = cfg->afu; bool put_ctx = false; + struct dk_cxlflash_resize size; res_hndl_t rhndl = release->rsrc_handle; int rc = 0; @@ -594,7 +620,24 @@ int _cxlflash_disk_release(struct scsi_device *sdev, goto out; } + /* + * Resize to 0 for virtual LUNS by setting the size + * to 0. This will clear LXT_START and LXT_CNT fields + * in the RHT entry and properly sync with the AFU. + * + * Afterwards we clear the remaining fields. + */ switch (gli->mode) { + case MODE_VIRTUAL: + marshal_rele_to_resize(release, &size); + size.req_size = 0; + rc = _cxlflash_vlun_resize(sdev, ctxi, &size); + if (rc) { + dev_dbg(dev, "%s: resize failed rc %d\n", __func__, rc); + goto out; + } + + break; case MODE_PHYSICAL: /* * Clear the Format 1 RHT entry for direct access @@ -666,6 +709,7 @@ static void destroy_context(struct cxlflash_cfg *cfg, /* Free memory associated with context */ free_page((ulong)ctxi->rht_start); + kfree(ctxi->rht_needs_ws); kfree(ctxi->rht_lun); kfree(ctxi); atomic_dec_if_positive(&cfg->num_user_contexts); @@ -693,11 +737,13 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct llun_info **lli = NULL; + bool *ws = NULL; struct sisl_rht_entry *rhte; ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); - if (unlikely(!ctxi || !lli)) { + ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); + if (unlikely(!ctxi || !lli || !ws)) { dev_err(dev, "%s: Unable to allocate context!\n", __func__); goto err; } @@ -709,6 +755,7 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, } ctxi->rht_lun = lli; + ctxi->rht_needs_ws = ws; ctxi->rht_start = rhte; ctxi->rht_perms = perms; @@ -728,6 +775,7 @@ out: return ctxi; err: + kfree(ws); kfree(lli); kfree(ctxi); ctxi = NULL; @@ -1729,6 +1777,12 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, case MODE_PHYSICAL: last_lba = gli->max_lba; break; + case MODE_VIRTUAL: + /* Cast lxt_cnt to u64 for multiply to be treated as 64bit op */ + last_lba = ((u64)rhte->lxt_cnt * MC_CHUNK_SIZE * gli->blk_len); + last_lba /= CXLFLASH_BLOCK_SIZE; + last_lba--; + break; default: WARN(1, "Unsupported LUN mode!"); } @@ -1756,12 +1810,18 @@ static char *decode_ioctl(int cmd) return __stringify_1(DK_CXLFLASH_ATTACH); case DK_CXLFLASH_USER_DIRECT: return __stringify_1(DK_CXLFLASH_USER_DIRECT); + case DK_CXLFLASH_USER_VIRTUAL: + return __stringify_1(DK_CXLFLASH_USER_VIRTUAL); + case DK_CXLFLASH_VLUN_RESIZE: + return __stringify_1(DK_CXLFLASH_VLUN_RESIZE); case DK_CXLFLASH_RELEASE: return __stringify_1(DK_CXLFLASH_RELEASE); case DK_CXLFLASH_DETACH: return __stringify_1(DK_CXLFLASH_DETACH); case DK_CXLFLASH_VERIFY: return __stringify_1(DK_CXLFLASH_VERIFY); + case DK_CXLFLASH_VLUN_CLONE: + return __stringify_1(DK_CXLFLASH_VLUN_CLONE); case DK_CXLFLASH_RECOVER_AFU: return __stringify_1(DK_CXLFLASH_RECOVER_AFU); case DK_CXLFLASH_MANAGE_LUN: @@ -1876,6 +1936,7 @@ static int ioctl_common(struct scsi_device *sdev, int cmd) rc = check_state(cfg); if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { switch (cmd) { + case DK_CXLFLASH_VLUN_RESIZE: case DK_CXLFLASH_RELEASE: case DK_CXLFLASH_DETACH: dev_dbg(dev, "%s: Command override! (%d)\n", @@ -1923,12 +1984,18 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) {sizeof(struct dk_cxlflash_verify), (sioctl)cxlflash_disk_verify}, {sizeof(struct dk_cxlflash_recover_afu), (sioctl)cxlflash_afu_recover}, {sizeof(struct dk_cxlflash_manage_lun), (sioctl)cxlflash_manage_lun}, + {sizeof(struct dk_cxlflash_uvirtual), cxlflash_disk_virtual_open}, + {sizeof(struct dk_cxlflash_resize), (sioctl)cxlflash_vlun_resize}, + {sizeof(struct dk_cxlflash_clone), (sioctl)cxlflash_disk_clone}, }; /* Restrict command set to physical support only for internal LUN */ if (afu->internal_lun) switch (cmd) { case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_USER_VIRTUAL: + case DK_CXLFLASH_VLUN_RESIZE: + case DK_CXLFLASH_VLUN_CLONE: dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", __func__, decode_ioctl(cmd), afu->internal_lun); rc = -EINVAL; @@ -1942,6 +2009,9 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) case DK_CXLFLASH_DETACH: case DK_CXLFLASH_VERIFY: case DK_CXLFLASH_RECOVER_AFU: + case DK_CXLFLASH_USER_VIRTUAL: + case DK_CXLFLASH_VLUN_RESIZE: + case DK_CXLFLASH_VLUN_CLONE: dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", __func__, decode_ioctl(cmd), cmd, shost->host_no, sdev->channel, sdev->id, sdev->lun); diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index ae39b9627118..d7dc88bc64a4 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -31,9 +31,11 @@ extern struct cxlflash_global global; #define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ #define CHAN2PORT(_x) ((_x) + 1) +#define PORT2CHAN(_x) ((_x) - 1) enum lun_mode { MODE_NONE = 0, + MODE_VIRTUAL, MODE_PHYSICAL }; @@ -41,13 +43,14 @@ enum lun_mode { struct glun_info { u64 max_lba; /* from read cap(16) */ u32 blk_len; /* from read cap(16) */ - enum lun_mode mode; /* NONE, PHYSICAL */ + enum lun_mode mode; /* NONE, VIRTUAL, PHYSICAL */ int users; /* Number of users w/ references to LUN */ u8 wwid[16]; struct mutex mutex; + struct blka blka; struct list_head list; }; @@ -58,6 +61,7 @@ struct llun_info { u32 host_no; /* host_no from Scsi_host */ u32 port_sel; /* What port to use for this LUN */ bool newly_created; /* Whether the LUN was just discovered */ + bool in_table; /* Whether a LUN table entry was created */ u8 wwid[16]; /* Keep a duplicate copy here? */ @@ -90,6 +94,7 @@ struct ctx_info { u32 rht_out; /* Number of checked out RHT entries */ u32 rht_perms; /* User-defined permissions for RHT entries */ struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ + bool *rht_needs_ws; /* User-desired write-same function per RHTE */ struct cxl_ioctl_start_work work; u64 ctxid; @@ -111,10 +116,18 @@ struct cxlflash_global { struct page *err_page; /* One page of all 0xF for error notification */ }; +int cxlflash_vlun_resize(struct scsi_device *, struct dk_cxlflash_resize *); +int _cxlflash_vlun_resize(struct scsi_device *, struct ctx_info *, + struct dk_cxlflash_resize *); + int cxlflash_disk_release(struct scsi_device *, struct dk_cxlflash_release *); int _cxlflash_disk_release(struct scsi_device *, struct ctx_info *, struct dk_cxlflash_release *); +int cxlflash_disk_clone(struct scsi_device *, struct dk_cxlflash_clone *); + +int cxlflash_disk_virtual_open(struct scsi_device *, void *); + int cxlflash_lun_attach(struct glun_info *, enum lun_mode, bool); void cxlflash_lun_detach(struct glun_info *); @@ -127,6 +140,8 @@ struct sisl_rht_entry *get_rhte(struct ctx_info *, res_hndl_t, struct sisl_rht_entry *rhte_checkout(struct ctx_info *, struct llun_info *); void rhte_checkin(struct ctx_info *, struct sisl_rht_entry *); +void cxlflash_ba_terminate(struct ba_lun *); + int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); #endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c new file mode 100644 index 000000000000..6155cb1d4ed3 --- /dev/null +++ b/drivers/scsi/cxlflash/vlun.c @@ -0,0 +1,1243 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "sislite.h" +#include "common.h" +#include "vlun.h" +#include "superpipe.h" + +/** + * marshal_virt_to_resize() - translate uvirtual to resize structure + * @virt: Source structure from which to translate/copy. + * @resize: Destination structure for the translate/copy. + */ +static void marshal_virt_to_resize(struct dk_cxlflash_uvirtual *virt, + struct dk_cxlflash_resize *resize) +{ + resize->hdr = virt->hdr; + resize->context_id = virt->context_id; + resize->rsrc_handle = virt->rsrc_handle; + resize->req_size = virt->lun_size; + resize->last_lba = virt->last_lba; +} + +/** + * marshal_clone_to_rele() - translate clone to release structure + * @clone: Source structure from which to translate/copy. + * @rele: Destination structure for the translate/copy. + */ +static void marshal_clone_to_rele(struct dk_cxlflash_clone *clone, + struct dk_cxlflash_release *release) +{ + release->hdr = clone->hdr; + release->context_id = clone->context_id_dst; +} + +/** + * ba_init() - initializes a block allocator + * @ba_lun: Block allocator to initialize. + * + * Return: 0 on success, -errno on failure + */ +static int ba_init(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = NULL; + int lun_size_au = 0, i = 0; + int last_word_underflow = 0; + u64 *lam; + + pr_debug("%s: Initializing LUN: lun_id = %llX, " + "ba_lun->lsize = %lX, ba_lun->au_size = %lX\n", + __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); + + /* Calculate bit map size */ + lun_size_au = ba_lun->lsize / ba_lun->au_size; + if (lun_size_au == 0) { + pr_debug("%s: Requested LUN size of 0!\n", __func__); + return -EINVAL; + } + + /* Allocate lun information container */ + bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); + if (unlikely(!bali)) { + pr_err("%s: Failed to allocate lun_info for lun_id %llX\n", + __func__, ba_lun->lun_id); + return -ENOMEM; + } + + bali->total_aus = lun_size_au; + bali->lun_bmap_size = lun_size_au / BITS_PER_LONG; + + if (lun_size_au % BITS_PER_LONG) + bali->lun_bmap_size++; + + /* Allocate bitmap space */ + bali->lun_alloc_map = kzalloc((bali->lun_bmap_size * sizeof(u64)), + GFP_KERNEL); + if (unlikely(!bali->lun_alloc_map)) { + pr_err("%s: Failed to allocate lun allocation map: " + "lun_id = %llX\n", __func__, ba_lun->lun_id); + kfree(bali); + return -ENOMEM; + } + + /* Initialize the bit map size and set all bits to '1' */ + bali->free_aun_cnt = lun_size_au; + + for (i = 0; i < bali->lun_bmap_size; i++) + bali->lun_alloc_map[i] = 0xFFFFFFFFFFFFFFFFULL; + + /* If the last word not fully utilized, mark extra bits as allocated */ + last_word_underflow = (bali->lun_bmap_size * BITS_PER_LONG); + last_word_underflow -= bali->free_aun_cnt; + if (last_word_underflow > 0) { + lam = &bali->lun_alloc_map[bali->lun_bmap_size - 1]; + for (i = (HIBIT - last_word_underflow + 1); + i < BITS_PER_LONG; + i++) + clear_bit(i, (ulong *)lam); + } + + /* Initialize high elevator index, low/curr already at 0 from kzalloc */ + bali->free_high_idx = bali->lun_bmap_size; + + /* Allocate clone map */ + bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), + GFP_KERNEL); + if (unlikely(!bali->aun_clone_map)) { + pr_err("%s: Failed to allocate clone map: lun_id = %llX\n", + __func__, ba_lun->lun_id); + kfree(bali->lun_alloc_map); + kfree(bali); + return -ENOMEM; + } + + /* Pass the allocated lun info as a handle to the user */ + ba_lun->ba_lun_handle = bali; + + pr_debug("%s: Successfully initialized the LUN: " + "lun_id = %llX, bitmap size = %X, free_aun_cnt = %llX\n", + __func__, ba_lun->lun_id, bali->lun_bmap_size, + bali->free_aun_cnt); + return 0; +} + +/** + * find_free_range() - locates a free bit within the block allocator + * @low: First word in block allocator to start search. + * @high: Last word in block allocator to search. + * @bali: LUN information structure owning the block allocator to search. + * @bit_word: Passes back the word in the block allocator owning the free bit. + * + * Return: The bit position within the passed back word, -1 on failure + */ +static int find_free_range(u32 low, + u32 high, + struct ba_lun_info *bali, int *bit_word) +{ + int i; + u64 bit_pos = -1; + ulong *lam, num_bits; + + for (i = low; i < high; i++) + if (bali->lun_alloc_map[i] != 0) { + lam = (ulong *)&bali->lun_alloc_map[i]; + num_bits = (sizeof(*lam) * BITS_PER_BYTE); + bit_pos = find_first_bit(lam, num_bits); + + pr_devel("%s: Found free bit %llX in lun " + "map entry %llX at bitmap index = %X\n", + __func__, bit_pos, bali->lun_alloc_map[i], + i); + + *bit_word = i; + bali->free_aun_cnt--; + clear_bit(bit_pos, lam); + break; + } + + return bit_pos; +} + +/** + * ba_alloc() - allocates a block from the block allocator + * @ba_lun: Block allocator from which to allocate a block. + * + * Return: The allocated block, -1 on failure + */ +static u64 ba_alloc(struct ba_lun *ba_lun) +{ + u64 bit_pos = -1; + int bit_word = 0; + struct ba_lun_info *bali = NULL; + + bali = ba_lun->ba_lun_handle; + + pr_debug("%s: Received block allocation request: " + "lun_id = %llX, free_aun_cnt = %llX\n", + __func__, ba_lun->lun_id, bali->free_aun_cnt); + + if (bali->free_aun_cnt == 0) { + pr_debug("%s: No space left on LUN: lun_id = %llX\n", + __func__, ba_lun->lun_id); + return -1ULL; + } + + /* Search to find a free entry, curr->high then low->curr */ + bit_pos = find_free_range(bali->free_curr_idx, + bali->free_high_idx, bali, &bit_word); + if (bit_pos == -1) { + bit_pos = find_free_range(bali->free_low_idx, + bali->free_curr_idx, + bali, &bit_word); + if (bit_pos == -1) { + pr_debug("%s: Could not find an allocation unit on LUN:" + " lun_id = %llX\n", __func__, ba_lun->lun_id); + return -1ULL; + } + } + + /* Update the free_curr_idx */ + if (bit_pos == HIBIT) + bali->free_curr_idx = bit_word + 1; + else + bali->free_curr_idx = bit_word; + + pr_debug("%s: Allocating AU number %llX, on lun_id %llX, " + "free_aun_cnt = %llX\n", __func__, + ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, + bali->free_aun_cnt); + + return (u64) ((bit_word * BITS_PER_LONG) + bit_pos); +} + +/** + * validate_alloc() - validates the specified block has been allocated + * @ba_lun_info: LUN info owning the block allocator. + * @aun: Block to validate. + * + * Return: 0 on success, -1 on failure + */ +static int validate_alloc(struct ba_lun_info *bali, u64 aun) +{ + int idx = 0, bit_pos = 0; + + idx = aun / BITS_PER_LONG; + bit_pos = aun % BITS_PER_LONG; + + if (test_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx])) + return -1; + + return 0; +} + +/** + * ba_free() - frees a block from the block allocator + * @ba_lun: Block allocator from which to allocate a block. + * @to_free: Block to free. + * + * Return: 0 on success, -1 on failure + */ +static int ba_free(struct ba_lun *ba_lun, u64 to_free) +{ + int idx = 0, bit_pos = 0; + struct ba_lun_info *bali = NULL; + + bali = ba_lun->ba_lun_handle; + + if (validate_alloc(bali, to_free)) { + pr_debug("%s: The AUN %llX is not allocated on lun_id %llX\n", + __func__, to_free, ba_lun->lun_id); + return -1; + } + + pr_debug("%s: Received a request to free AU %llX on lun_id %llX, " + "free_aun_cnt = %llX\n", __func__, to_free, ba_lun->lun_id, + bali->free_aun_cnt); + + if (bali->aun_clone_map[to_free] > 0) { + pr_debug("%s: AUN %llX on lun_id %llX has been cloned. Clone " + "count = %X\n", __func__, to_free, ba_lun->lun_id, + bali->aun_clone_map[to_free]); + bali->aun_clone_map[to_free]--; + return 0; + } + + idx = to_free / BITS_PER_LONG; + bit_pos = to_free % BITS_PER_LONG; + + set_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx]); + bali->free_aun_cnt++; + + if (idx < bali->free_low_idx) + bali->free_low_idx = idx; + else if (idx > bali->free_high_idx) + bali->free_high_idx = idx; + + pr_debug("%s: Successfully freed AU at bit_pos %X, bit map index %X on " + "lun_id %llX, free_aun_cnt = %llX\n", __func__, bit_pos, idx, + ba_lun->lun_id, bali->free_aun_cnt); + + return 0; +} + +/** + * ba_clone() - Clone a chunk of the block allocation table + * @ba_lun: Block allocator from which to allocate a block. + * @to_free: Block to free. + * + * Return: 0 on success, -1 on failure + */ +static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + if (validate_alloc(bali, to_clone)) { + pr_debug("%s: AUN %llX is not allocated on lun_id %llX\n", + __func__, to_clone, ba_lun->lun_id); + return -1; + } + + pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n", + __func__, to_clone, ba_lun->lun_id); + + if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { + pr_debug("%s: AUN %llX on lun_id %llX hit max clones already\n", + __func__, to_clone, ba_lun->lun_id); + return -1; + } + + bali->aun_clone_map[to_clone]++; + + return 0; +} + +/** + * ba_space() - returns the amount of free space left in the block allocator + * @ba_lun: Block allocator. + * + * Return: Amount of free space in block allocator + */ +static u64 ba_space(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + return bali->free_aun_cnt; +} + +/** + * cxlflash_ba_terminate() - frees resources associated with the block allocator + * @ba_lun: Block allocator. + * + * Safe to call in a partially allocated state. + */ +void cxlflash_ba_terminate(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + if (bali) { + kfree(bali->aun_clone_map); + kfree(bali->lun_alloc_map); + kfree(bali); + ba_lun->ba_lun_handle = NULL; + } +} + +/** + * init_vlun() - initializes a LUN for virtual use + * @lun_info: LUN information structure that owns the block allocator. + * + * Return: 0 on success, -errno on failure + */ +static int init_vlun(struct llun_info *lli) +{ + int rc = 0; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + + memset(blka, 0, sizeof(*blka)); + mutex_init(&blka->mutex); + + /* LUN IDs are unique per port, save the index instead */ + blka->ba_lun.lun_id = lli->lun_index; + blka->ba_lun.lsize = gli->max_lba + 1; + blka->ba_lun.lba_size = gli->blk_len; + + blka->ba_lun.au_size = MC_CHUNK_SIZE; + blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE; + + rc = ba_init(&blka->ba_lun); + if (unlikely(rc)) + pr_debug("%s: cannot init block_alloc, rc=%d\n", __func__, rc); + + pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli); + return rc; +} + +/** + * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN + * @sdev: SCSI device associated with LUN. + * @lba: Logical block address to start write same. + * @nblks: Number of logical blocks to write same. + * + * Return: 0 on success, -errno on failure + */ +static int write_same16(struct scsi_device *sdev, + u64 lba, + u32 nblks) +{ + u8 *cmd_buf = NULL; + u8 *scsi_cmd = NULL; + u8 *sense_buf = NULL; + int rc = 0; + int result = 0; + int ws_limit = SISLITE_MAX_WS_BLOCKS; + u64 offset = lba; + int left = nblks; + u32 tout = sdev->request_queue->rq_timeout; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + + cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); + scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); + sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (unlikely(!cmd_buf || !scsi_cmd || !sense_buf)) { + rc = -ENOMEM; + goto out; + } + + while (left > 0) { + + scsi_cmd[0] = WRITE_SAME_16; + put_unaligned_be64(offset, &scsi_cmd[2]); + put_unaligned_be32(ws_limit < left ? ws_limit : left, + &scsi_cmd[10]); + + result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, + CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + if (result) { + dev_err_ratelimited(dev, "%s: command failed for " + "offset %lld result=0x%x\n", + __func__, offset, result); + rc = -EIO; + goto out; + } + left -= ws_limit; + offset += ws_limit; + } + +out: + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * grow_lxt() - expands the translation table associated with the specified RHTE + * @afu: AFU associated with the host. + * @sdev: SCSI device associated with LUN. + * @ctxid: Context ID of context owning the RHTE. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Resource handle entry (RHTE). + * @new_size: Number of translation entries associated with RHTE. + * + * By design, this routine employs a 'best attempt' allocation and will + * truncate the requested size down if there is not sufficient space in + * the block allocator to satisfy the request but there does exist some + * amount of space. The user is made aware of this by returning the size + * allocated. + * + * Return: 0 on success, -errno on failure + */ +static int grow_lxt(struct afu *afu, + struct scsi_device *sdev, + ctx_hndl_t ctxid, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + u64 *new_size) +{ + struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + u32 av_size; + u32 ngrps, ngrps_old; + u64 aun; /* chunk# allocated by block allocator */ + u64 delta = *new_size - rhte->lxt_cnt; + u64 my_new_size; + int i, rc = 0; + + /* + * Check what is available in the block allocator before re-allocating + * LXT array. This is done up front under the mutex which must not be + * released until after allocation is complete. + */ + mutex_lock(&blka->mutex); + av_size = ba_space(&blka->ba_lun); + if (unlikely(av_size <= 0)) { + pr_debug("%s: ba_space error: av_size %d\n", __func__, av_size); + mutex_unlock(&blka->mutex); + rc = -ENOSPC; + goto out; + } + + if (av_size < delta) + delta = av_size; + + lxt_old = rhte->lxt_start; + ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); + ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt + delta); + + if (ngrps != ngrps_old) { + /* reallocate to fit new size */ + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) { + mutex_unlock(&blka->mutex); + rc = -ENOMEM; + goto out; + } + + /* copy over all old entries */ + memcpy(lxt, lxt_old, (sizeof(*lxt) * rhte->lxt_cnt)); + } else + lxt = lxt_old; + + /* nothing can fail from now on */ + my_new_size = rhte->lxt_cnt + delta; + + /* add new entries to the end */ + for (i = rhte->lxt_cnt; i < my_new_size; i++) { + /* + * Due to the earlier check of available space, ba_alloc + * cannot fail here. If it did due to internal error, + * leave a rlba_base of -1u which will likely be a + * invalid LUN (too large). + */ + aun = ba_alloc(&blka->ba_lun); + if ((aun == -1ULL) || (aun >= blka->nchunk)) + pr_debug("%s: ba_alloc error: allocated chunk# %llX, " + "max %llX\n", __func__, aun, blka->nchunk - 1); + + /* select both ports, use r/w perms from RHT */ + lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | + (lli->lun_index << LXT_LUNIDX_SHIFT) | + (RHT_PERM_RW << LXT_PERM_SHIFT | + lli->port_sel)); + } + + mutex_unlock(&blka->mutex); + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when adding LXT entries. + */ + dma_wmb(); /* Make LXT updates are visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + rhte->lxt_cnt = my_new_size; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); + + /* free old lxt if reallocated */ + if (lxt != lxt_old) + kfree(lxt_old); + *new_size = my_new_size; +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * shrink_lxt() - reduces translation table associated with the specified RHTE + * @afu: AFU associated with the host. + * @sdev: SCSI device associated with LUN. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Resource handle entry (RHTE). + * @ctxi: Context owning resources. + * @new_size: Number of translation entries associated with RHTE. + * + * Return: 0 on success, -errno on failure + */ +static int shrink_lxt(struct afu *afu, + struct scsi_device *sdev, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + struct ctx_info *ctxi, + u64 *new_size) +{ + struct sisl_lxt_entry *lxt, *lxt_old; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + ctx_hndl_t ctxid = DECODE_CTXID(ctxi->ctxid); + bool needs_ws = ctxi->rht_needs_ws[rhndl]; + bool needs_sync = !ctxi->err_recovery_active; + u32 ngrps, ngrps_old; + u64 aun; /* chunk# allocated by block allocator */ + u64 delta = rhte->lxt_cnt - *new_size; + u64 my_new_size; + int i, rc = 0; + + lxt_old = rhte->lxt_start; + ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); + ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt - delta); + + if (ngrps != ngrps_old) { + /* Reallocate to fit new size unless new size is 0 */ + if (ngrps) { + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) { + rc = -ENOMEM; + goto out; + } + + /* Copy over old entries that will remain */ + memcpy(lxt, lxt_old, + (sizeof(*lxt) * (rhte->lxt_cnt - delta))); + } else + lxt = NULL; + } else + lxt = lxt_old; + + /* Nothing can fail from now on */ + my_new_size = rhte->lxt_cnt - delta; + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when removing LXT entries. + */ + rhte->lxt_cnt = my_new_size; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + if (needs_sync) + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); + + if (needs_ws) { + /* + * Mark the context as unavailable, so that we can release + * the mutex safely. + */ + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); + } + + /* Free LBAs allocated to freed chunks */ + mutex_lock(&blka->mutex); + for (i = delta - 1; i >= 0; i--) { + /* Mask the higher 48 bits before shifting, even though + * it is a noop + */ + aun = (lxt_old[my_new_size + i].rlba_base & SISL_ASTATUS_MASK); + aun = (aun >> MC_CHUNK_SHIFT); + if (needs_ws) + write_same16(sdev, aun, MC_CHUNK_SIZE); + ba_free(&blka->ba_lun, aun); + } + mutex_unlock(&blka->mutex); + + if (needs_ws) { + /* Make the context visible again */ + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; + } + + /* Free old lxt if reallocated */ + if (lxt != lxt_old) + kfree(lxt_old); + *new_size = my_new_size; +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * _cxlflash_vlun_resize() - changes the size of a virtual lun + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @ctxi: Context owning resources. + * @resize: Resize ioctl data structure. + * + * On successful return, the user is informed of the new size (in blocks) + * of the virtual lun in last LBA format. When the size of the virtual + * lun is zero, the last LBA is reflected as -1. See comment in the + * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts + * on the error recovery list. + * + * Return: 0 on success, -errno on failure + */ +int _cxlflash_vlun_resize(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_resize *resize) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct afu *afu = cfg->afu; + bool put_ctx = false; + + res_hndl_t rhndl = resize->rsrc_handle; + u64 new_size; + u64 nsectors; + u64 ctxid = DECODE_CTXID(resize->context_id), + rctxid = resize->context_id; + + struct sisl_rht_entry *rhte; + + int rc = 0; + + /* + * The requested size (req_size) is always assumed to be in 4k blocks, + * so we have to convert it here from 4k to chunk size. + */ + nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; + new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); + + pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx," + "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle, + resize->req_size, new_size); + + if (unlikely(gli->mode != MODE_VIRTUAL)) { + pr_debug("%s: LUN mode does not support resize! (%d)\n", + __func__, gli->mode); + rc = -EINVAL; + goto out; + + } + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + pr_debug("%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + pr_debug("%s: Bad resource handle! (%u)\n", __func__, rhndl); + rc = -EINVAL; + goto out; + } + + if (new_size > rhte->lxt_cnt) + rc = grow_lxt(afu, sdev, ctxid, rhndl, rhte, &new_size); + else if (new_size < rhte->lxt_cnt) + rc = shrink_lxt(afu, sdev, rhndl, rhte, ctxi, &new_size); + + resize->hdr.return_flags = 0; + resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len); + resize->last_lba /= CXLFLASH_BLOCK_SIZE; + resize->last_lba--; + +out: + if (put_ctx) + put_context(ctxi); + pr_debug("%s: resized to %lld returning rc=%d\n", + __func__, resize->last_lba, rc); + return rc; +} + +int cxlflash_vlun_resize(struct scsi_device *sdev, + struct dk_cxlflash_resize *resize) +{ + return _cxlflash_vlun_resize(sdev, NULL, resize); +} + +/** + * cxlflash_restore_luntable() - Restore LUN table to prior state + * @cfg: Internal structure associated with the host. + */ +void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) +{ + struct llun_info *lli, *temp; + u32 chan; + u32 lind; + struct afu *afu = cfg->afu; + struct sisl_global_map *agm = &afu->afu_map->global; + + mutex_lock(&global.mutex); + + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { + if (!lli->in_table) + continue; + + lind = lli->lun_index; + + if (lli->port_sel == BOTH_PORTS) { + writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); + writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); + pr_debug("%s: Virtual LUN on slot %d id0=%llx, " + "id1=%llx\n", __func__, lind, + lli->lun_id[0], lli->lun_id[1]); + } else { + chan = PORT2CHAN(lli->port_sel); + writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); + pr_debug("%s: Virtual LUN on slot %d chan=%d, " + "id=%llx\n", __func__, lind, chan, + lli->lun_id[chan]); + } + } + + mutex_unlock(&global.mutex); +} + +/** + * init_luntable() - write an entry in the LUN table + * @cfg: Internal structure associated with the host. + * @lli: Per adapter LUN information structure. + * + * On successful return, a LUN table entry is created. + * At the top for LUNs visible on both ports. + * At the bottom for LUNs visible only on one port. + * + * Return: 0 on success, -errno on failure + */ +static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) +{ + u32 chan; + u32 lind; + int rc = 0; + struct afu *afu = cfg->afu; + struct sisl_global_map *agm = &afu->afu_map->global; + + mutex_lock(&global.mutex); + + if (lli->in_table) + goto out; + + if (lli->port_sel == BOTH_PORTS) { + /* + * If this LUN is visible from both ports, we will put + * it in the top half of the LUN table. + */ + if ((cfg->promote_lun_index == cfg->last_lun_index[0]) || + (cfg->promote_lun_index == cfg->last_lun_index[1])) { + rc = -ENOSPC; + goto out; + } + + lind = lli->lun_index = cfg->promote_lun_index; + writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); + writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); + cfg->promote_lun_index++; + pr_debug("%s: Virtual LUN on slot %d id0=%llx, id1=%llx\n", + __func__, lind, lli->lun_id[0], lli->lun_id[1]); + } else { + /* + * If this LUN is visible only from one port, we will put + * it in the bottom half of the LUN table. + */ + chan = PORT2CHAN(lli->port_sel); + if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { + rc = -ENOSPC; + goto out; + } + + lind = lli->lun_index = cfg->last_lun_index[chan]; + writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); + cfg->last_lun_index[chan]--; + pr_debug("%s: Virtual LUN on slot %d chan=%d, id=%llx\n", + __func__, lind, chan, lli->lun_id[chan]); + } + + lli->in_table = true; +out: + mutex_unlock(&global.mutex); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_disk_virtual_open() - open a virtual disk of specified size + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @arg: UVirtual ioctl data structure. + * + * On successful return, the user is informed of the resource handle + * to be used to identify the virtual lun and the size (in blocks) of + * the virtual lun in last LBA format. When the size of the virtual lun + * is zero, the last LBA is reflected as -1. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + + struct dk_cxlflash_uvirtual *virt = (struct dk_cxlflash_uvirtual *)arg; + struct dk_cxlflash_resize resize; + + u64 ctxid = DECODE_CTXID(virt->context_id), + rctxid = virt->context_id; + u64 lun_size = virt->lun_size; + u64 last_lba = 0; + u64 rsrc_handle = -1; + + int rc = 0; + + struct ctx_info *ctxi = NULL; + struct sisl_rht_entry *rhte = NULL; + + pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + + mutex_lock(&gli->mutex); + if (gli->mode == MODE_NONE) { + /* Setup the LUN table and block allocator on first call */ + rc = init_luntable(cfg, lli); + if (rc) { + dev_err(dev, "%s: call to init_luntable failed " + "rc=%d!\n", __func__, rc); + goto err0; + } + + rc = init_vlun(lli); + if (rc) { + dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", + __func__, rc); + rc = -ENOMEM; + goto err0; + } + } + + rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); + if (unlikely(rc)) { + dev_err(dev, "%s: Failed to attach to LUN! (VIRTUAL)\n", + __func__); + goto err0; + } + mutex_unlock(&gli->mutex); + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto err1; + } + + rhte = rhte_checkout(ctxi, lli); + if (unlikely(!rhte)) { + dev_err(dev, "%s: too many opens for this context\n", __func__); + rc = -EMFILE; /* too many opens */ + goto err1; + } + + rsrc_handle = (rhte - ctxi->rht_start); + + /* Populate RHT format 0 */ + rhte->nmask = MC_RHT_NMASK; + rhte->fp = SISL_RHT_FP(0U, ctxi->rht_perms); + + /* Resize even if requested size is 0 */ + marshal_virt_to_resize(virt, &resize); + resize.rsrc_handle = rsrc_handle; + rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); + if (rc) { + dev_err(dev, "%s: resize failed rc %d\n", __func__, rc); + goto err2; + } + last_lba = resize.last_lba; + + if (virt->hdr.flags & DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME) + ctxi->rht_needs_ws[rsrc_handle] = true; + + virt->hdr.return_flags = 0; + virt->last_lba = last_lba; + virt->rsrc_handle = rsrc_handle; + +out: + if (likely(ctxi)) + put_context(ctxi); + pr_debug("%s: returning handle 0x%llx rc=%d llba %lld\n", + __func__, rsrc_handle, rc, last_lba); + return rc; + +err2: + rhte_checkin(ctxi, rhte); +err1: + cxlflash_lun_detach(gli); + goto out; +err0: + /* Special common cleanup prior to successful LUN attach */ + cxlflash_ba_terminate(&gli->blka.ba_lun); + mutex_unlock(&gli->mutex); + goto out; +} + +/** + * clone_lxt() - copies translation tables from source to destination RHTE + * @afu: AFU associated with the host. + * @blka: Block allocator associated with LUN. + * @ctxid: Context ID of context owning the RHTE. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Destination resource handle entry (RHTE). + * @rhte_src: Source resource handle entry (RHTE). + * + * Return: 0 on success, -errno on failure + */ +static int clone_lxt(struct afu *afu, + struct blka *blka, + ctx_hndl_t ctxid, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + struct sisl_rht_entry *rhte_src) +{ + struct sisl_lxt_entry *lxt; + u32 ngrps; + u64 aun; /* chunk# allocated by block allocator */ + int i, j; + + ngrps = LXT_NUM_GROUPS(rhte_src->lxt_cnt); + + if (ngrps) { + /* allocate new LXTs for clone */ + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) + return -ENOMEM; + + /* copy over */ + memcpy(lxt, rhte_src->lxt_start, + (sizeof(*lxt) * rhte_src->lxt_cnt)); + + /* clone the LBAs in block allocator via ref_cnt */ + mutex_lock(&blka->mutex); + for (i = 0; i < rhte_src->lxt_cnt; i++) { + aun = (lxt[i].rlba_base >> MC_CHUNK_SHIFT); + if (ba_clone(&blka->ba_lun, aun) == -1ULL) { + /* free the clones already made */ + for (j = 0; j < i; j++) { + aun = (lxt[j].rlba_base >> + MC_CHUNK_SHIFT); + ba_free(&blka->ba_lun, aun); + } + + mutex_unlock(&blka->mutex); + kfree(lxt); + return -EIO; + } + } + mutex_unlock(&blka->mutex); + } else { + lxt = NULL; + } + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when adding LXT entries. + */ + dma_wmb(); /* Make LXT updates are visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + rhte->lxt_cnt = rhte_src->lxt_cnt; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); + + pr_debug("%s: returning\n", __func__); + return 0; +} + +/** + * cxlflash_disk_clone() - clone a context by making snapshot of another + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @clone: Clone ioctl data structure. + * + * This routine effectively performs cxlflash_disk_open operation for each + * in-use virtual resource in the source context. Note that the destination + * context must be in pristine state and cannot have any resource handles + * open at the time of the clone. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_disk_clone(struct scsi_device *sdev, + struct dk_cxlflash_clone *clone) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + struct afu *afu = cfg->afu; + struct dk_cxlflash_release release = { { 0 }, 0 }; + + struct ctx_info *ctxi_src = NULL, + *ctxi_dst = NULL; + struct lun_access *lun_access_src, *lun_access_dst; + u32 perms; + u64 ctxid_src = DECODE_CTXID(clone->context_id_src), + ctxid_dst = DECODE_CTXID(clone->context_id_dst), + rctxid_src = clone->context_id_src, + rctxid_dst = clone->context_id_dst; + int adap_fd_src = clone->adap_fd_src; + int i, j; + int rc = 0; + bool found; + LIST_HEAD(sidecar); + + pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu adap_fd_src=%d\n", + __func__, ctxid_src, ctxid_dst, adap_fd_src); + + /* Do not clone yourself */ + if (unlikely(rctxid_src == rctxid_dst)) { + rc = -EINVAL; + goto out; + } + + if (unlikely(gli->mode != MODE_VIRTUAL)) { + rc = -EINVAL; + pr_debug("%s: Clone not supported on physical LUNs! (%d)\n", + __func__, gli->mode); + goto out; + } + + ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); + ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); + if (unlikely(!ctxi_src || !ctxi_dst)) { + pr_debug("%s: Bad context! (%llu,%llu)\n", __func__, + ctxid_src, ctxid_dst); + rc = -EINVAL; + goto out; + } + + if (unlikely(adap_fd_src != ctxi_src->lfd)) { + pr_debug("%s: Invalid source adapter fd! (%d)\n", + __func__, adap_fd_src); + rc = -EINVAL; + goto out; + } + + /* Verify there is no open resource handle in the destination context */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) + if (ctxi_dst->rht_start[i].nmask != 0) { + rc = -EINVAL; + goto out; + } + + /* Clone LUN access list */ + list_for_each_entry(lun_access_src, &ctxi_src->luns, list) { + found = false; + list_for_each_entry(lun_access_dst, &ctxi_dst->luns, list) + if (lun_access_dst->sdev == lun_access_src->sdev) { + found = true; + break; + } + + if (!found) { + lun_access_dst = kzalloc(sizeof(*lun_access_dst), + GFP_KERNEL); + if (unlikely(!lun_access_dst)) { + pr_err("%s: Unable to allocate lun_access!\n", + __func__); + rc = -ENOMEM; + goto out; + } + + *lun_access_dst = *lun_access_src; + list_add(&lun_access_dst->list, &sidecar); + } + } + + if (unlikely(!ctxi_src->rht_out)) { + pr_debug("%s: Nothing to clone!\n", __func__); + goto out_success; + } + + /* User specified permission on attach */ + perms = ctxi_dst->rht_perms; + + /* + * Copy over checked-out RHT (and their associated LXT) entries by + * hand, stopping after we've copied all outstanding entries and + * cleaning up if the clone fails. + * + * Note: This loop is equivalent to performing cxlflash_disk_open and + * cxlflash_vlun_resize. As such, LUN accounting needs to be taken into + * account by attaching after each successful RHT entry clone. In the + * event that a clone failure is experienced, the LUN detach is handled + * via the cleanup performed by _cxlflash_disk_release. + */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { + if (ctxi_src->rht_out == ctxi_dst->rht_out) + break; + if (ctxi_src->rht_start[i].nmask == 0) + continue; + + /* Consume a destination RHT entry */ + ctxi_dst->rht_out++; + ctxi_dst->rht_start[i].nmask = ctxi_src->rht_start[i].nmask; + ctxi_dst->rht_start[i].fp = + SISL_RHT_FP_CLONE(ctxi_src->rht_start[i].fp, perms); + ctxi_dst->rht_lun[i] = ctxi_src->rht_lun[i]; + + rc = clone_lxt(afu, blka, ctxid_dst, i, + &ctxi_dst->rht_start[i], + &ctxi_src->rht_start[i]); + if (rc) { + marshal_clone_to_rele(clone, &release); + for (j = 0; j < i; j++) { + release.rsrc_handle = j; + _cxlflash_disk_release(sdev, ctxi_dst, + &release); + } + + /* Put back the one we failed on */ + rhte_checkin(ctxi_dst, &ctxi_dst->rht_start[i]); + goto err; + } + + cxlflash_lun_attach(gli, gli->mode, false); + } + +out_success: + list_splice(&sidecar, &ctxi_dst->luns); + sys_close(adap_fd_src); + + /* fall through */ +out: + if (ctxi_src) + put_context(ctxi_src); + if (ctxi_dst) + put_context(ctxi_dst); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; + +err: + list_for_each_entry_safe(lun_access_src, lun_access_dst, &sidecar, list) + kfree(lun_access_src); + goto out; +} diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h new file mode 100644 index 000000000000..8b29a74946e4 --- /dev/null +++ b/drivers/scsi/cxlflash/vlun.h @@ -0,0 +1,86 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CXLFLASH_VLUN_H +#define _CXLFLASH_VLUN_H + +/* RHT - Resource Handle Table */ +#define MC_RHT_NMASK 16 /* in bits */ +#define MC_CHUNK_SHIFT MC_RHT_NMASK /* shift to go from LBA to chunk# */ + +#define HIBIT (BITS_PER_LONG - 1) + +#define MAX_AUN_CLONE_CNT 0xFF + +/* + * LXT - LBA Translation Table + * + * +-------+-------+-------+-------+-------+-------+-------+---+---+ + * | RLBA_BASE |LUN_IDX| P |SEL| + * +-------+-------+-------+-------+-------+-------+-------+---+---+ + * + * The LXT Entry contains the physical LBA where the chunk starts (RLBA_BASE). + * AFU ORes the low order bits from the virtual LBA (offset into the chunk) + * with RLBA_BASE. The result is the physical LBA to be sent to storage. + * The LXT Entry also contains an index to a LUN TBL and a bitmask of which + * outgoing (FC) * ports can be selected. The port select bit-mask is ANDed + * with a global port select bit-mask maintained by the driver. + * In addition, it has permission bits that are ANDed with the + * RHT permissions to arrive at the final permissions for the chunk. + * + * LXT tables are allocated dynamically in groups. This is done to avoid + * a malloc/free overhead each time the LXT has to grow or shrink. + * + * Based on the current lxt_cnt (used), it is always possible to know + * how many are allocated (used+free). The number of allocated entries is + * not stored anywhere. + * + * The LXT table is re-allocated whenever it needs to cross into another group. +*/ +#define LXT_GROUP_SIZE 8 +#define LXT_NUM_GROUPS(lxt_cnt) (((lxt_cnt) + 7)/8) /* alloc'ed groups */ +#define LXT_LUNIDX_SHIFT 8 /* LXT entry, shift for LUN index */ +#define LXT_PERM_SHIFT 4 /* LXT entry, shift for permission bits */ + +struct ba_lun_info { + u64 *lun_alloc_map; + u32 lun_bmap_size; + u32 total_aus; + u64 free_aun_cnt; + + /* indices to be used for elevator lookup of free map */ + u32 free_low_idx; + u32 free_curr_idx; + u32 free_high_idx; + + u8 *aun_clone_map; +}; + +struct ba_lun { + u64 lun_id; + u64 wwpn; + size_t lsize; /* LUN size in number of LBAs */ + size_t lba_size; /* LBA size in number of bytes */ + size_t au_size; /* Allocation Unit size in number of LBAs */ + struct ba_lun_info *ba_lun_handle; +}; + +/* Block Allocator */ +struct blka { + struct ba_lun ba_lun; + u64 nchunk; /* number of chunks */ + struct mutex mutex; +}; + +#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index 570773406531..831351b2e660 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -71,6 +71,17 @@ struct dk_cxlflash_udirect { __u64 reserved[8]; /* Reserved for future use */ }; +#define DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME 0x8000000000000000ULL + +struct dk_cxlflash_uvirtual { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to own virtual resources */ + __u64 lun_size; /* Requested size, in 4K blocks */ + __u64 rsrc_handle; /* Returned resource handle */ + __u64 last_lba; /* Returned last LBA of LUN */ + __u64 reserved[8]; /* Reserved for future use */ +}; + struct dk_cxlflash_release { struct dk_cxlflash_hdr hdr; /* Common fields */ __u64 context_id; /* Context owning resources */ @@ -78,6 +89,23 @@ struct dk_cxlflash_release { __u64 reserved[8]; /* Reserved for future use */ }; +struct dk_cxlflash_resize { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources */ + __u64 rsrc_handle; /* Resource handle of LUN to resize */ + __u64 req_size; /* New requested size, in 4K blocks */ + __u64 last_lba; /* Returned last LBA of LUN */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_clone { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id_src; /* Context to clone from */ + __u64 context_id_dst; /* Context to clone to */ + __u64 adap_fd_src; /* Source context adapter fd */ + __u64 reserved[8]; /* Reserved for future use */ +}; + #define DK_CXLFLASH_VERIFY_SENSE_LEN 18 #define DK_CXLFLASH_VERIFY_HINT_SENSE 0x8000000000000000ULL @@ -118,7 +146,10 @@ union cxlflash_ioctls { struct dk_cxlflash_attach attach; struct dk_cxlflash_detach detach; struct dk_cxlflash_udirect udirect; + struct dk_cxlflash_uvirtual uvirtual; struct dk_cxlflash_release release; + struct dk_cxlflash_resize resize; + struct dk_cxlflash_clone clone; struct dk_cxlflash_verify verify; struct dk_cxlflash_recover_afu recover_afu; struct dk_cxlflash_manage_lun manage_lun; @@ -136,5 +167,8 @@ union cxlflash_ioctls { #define DK_CXLFLASH_VERIFY CXL_IOWR(0x84, dk_cxlflash_verify) #define DK_CXLFLASH_RECOVER_AFU CXL_IOWR(0x85, dk_cxlflash_recover_afu) #define DK_CXLFLASH_MANAGE_LUN CXL_IOWR(0x86, dk_cxlflash_manage_lun) +#define DK_CXLFLASH_USER_VIRTUAL CXL_IOWR(0x87, dk_cxlflash_uvirtual) +#define DK_CXLFLASH_VLUN_RESIZE CXL_IOWR(0x88, dk_cxlflash_resize) +#define DK_CXLFLASH_VLUN_CLONE CXL_IOWR(0x89, dk_cxlflash_clone) #endif /* ifndef _CXLFLASH_IOCTL_H */ -- cgit v1.2.3-59-g8ed1b From 9b28829d6da391f67a76dbba07a167e2b554bd10 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 18 Nov 2014 17:36:11 +0530 Subject: ARCv2: perf: Finally introduce HS perf unit With all features in place, the ARC HS pct block can now be effectively allowed to be probed/used Acked-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta --- Documentation/devicetree/bindings/arc/archs-pct.txt | 17 +++++++++++++++++ MAINTAINERS | 2 +- arch/arc/include/asm/perf_event.h | 5 ++++- arch/arc/kernel/perf_event.c | 3 ++- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/arc/archs-pct.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arc/archs-pct.txt b/Documentation/devicetree/bindings/arc/archs-pct.txt new file mode 100644 index 000000000000..1ae98b87c640 --- /dev/null +++ b/Documentation/devicetree/bindings/arc/archs-pct.txt @@ -0,0 +1,17 @@ +* ARC HS Performance Counters + +The ARC HS can be configured with a pipeline performance monitor for counting +CPU and cache events like cache misses and hits. Like conventional PCT there +are 100+ hardware conditions dynamically mapped to upto 32 counters. +It also supports overflow interrupts. + +Required properties: + +- compatible : should contain + "snps,archs-pct" + +Example: + +pmu { + compatible = "snps,archs-pct"; +}; diff --git a/MAINTAINERS b/MAINTAINERS index d7ab7363b263..d4cda4273131 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9874,7 +9874,7 @@ SYNOPSYS ARC ARCHITECTURE M: Vineet Gupta S: Supported F: arch/arc/ -F: Documentation/devicetree/bindings/arc/ +F: Documentation/devicetree/bindings/arc/* F: drivers/tty/serial/arc_uart.c T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git diff --git a/arch/arc/include/asm/perf_event.h b/arch/arc/include/asm/perf_event.h index 5824ab46cb71..5f071762fb1c 100644 --- a/arch/arc/include/asm/perf_event.h +++ b/arch/arc/include/asm/perf_event.h @@ -105,8 +105,11 @@ static const char * const arc_pmu_ev_hw_map[] = { [PERF_COUNT_HW_INSTRUCTIONS] = "iall", [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmp", /* Excludes ZOL jumps */ [PERF_COUNT_ARC_BPOK] = "bpok", /* NP-NT, PT-T, PNT-NT */ +#ifdef CONFIG_ISA_ARCV2 + [PERF_COUNT_HW_BRANCH_MISSES] = "bpmp", +#else [PERF_COUNT_HW_BRANCH_MISSES] = "bpfail", /* NP-T, PT-NT, PNT-T */ - +#endif [PERF_COUNT_ARC_LDC] = "imemrdc", /* Instr: mem read cached */ [PERF_COUNT_ARC_STC] = "imemwrc", /* Instr: mem write cached */ diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index 743065251e23..0c08bb1ce15a 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -551,6 +551,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id arc_pmu_match[] = { { .compatible = "snps,arc700-pct" }, + { .compatible = "snps,archs-pct" }, {}, }; MODULE_DEVICE_TABLE(of, arc_pmu_match); @@ -558,7 +559,7 @@ MODULE_DEVICE_TABLE(of, arc_pmu_match); static struct platform_driver arc_pmu_driver = { .driver = { - .name = "arc700-pct", + .name = "arc-pct", .of_match_table = of_match_ptr(arc_pmu_match), }, .probe = arc_pmu_device_probe, -- cgit v1.2.3-59-g8ed1b From 5aeb5d205e122b70742df94a7d51a3502f1a8277 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:37 +0800 Subject: hwmon: (fam15h_power) Add documentation for new processors support This patch updates description of fam15h_power driver, its scope is extended to family 16h processsors. Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- Documentation/hwmon/fam15h_power | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power index 80654813d04a..e2b1b69eebea 100644 --- a/Documentation/hwmon/fam15h_power +++ b/Documentation/hwmon/fam15h_power @@ -3,12 +3,13 @@ Kernel driver fam15h_power Supported chips: * AMD Family 15h Processors +* AMD Family 16h Processors Prefix: 'fam15h_power' Addresses scanned: PCI space Datasheets: BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors - (not yet published) + BIOS and Kernel Developer's Guide (BKDG) For AMD Family 16h Processors Author: Andreas Herrmann @@ -16,10 +17,11 @@ Description ----------- This driver permits reading of registers providing power information -of AMD Family 15h processors. +of AMD Family 15h and 16h processors. -For AMD Family 15h processors the following power values can be -calculated using different processor northbridge function registers: +For AMD Family 15h and 16h processors the following power values can +be calculated using different processor northbridge function +registers: * BasePwrWatts: Specifies in watts the maximum amount of power consumed by the processor for NB and logic external to the core. -- cgit v1.2.3-59-g8ed1b From 2baa891e42d84159b693eadd44f6fe1486285bdc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 24 Aug 2015 12:13:33 -0700 Subject: x86/mm/mtrr: Remove kernel internal MTRR interfaces: unexport mtrr_add() and mtrr_del() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The effort to replace mtrr_add() with architecture agnostic arch_phys_wc_add() is complete, this will ensure write-combining implementations (PAT on x86) is taken advantage instead of using MTRR. With the effort done now, hide direct MTRR access for drivers. The legacy user-space /proc/mtrr ABI is not affected. Update x86 documentation on MTRR to reflect the completion of the phasing out of direct access to MTRR, also add a note on platform firmware code use of MTRRs based on the obituary discussion of MTRRs on Linux [0]. [0] http://lkml.kernel.org/r/1438991330.3109.196.camel@hp.com Signed-off-by: Luis R. Rodriguez Cc: Cc: Andy Lutomirski Cc: Andy Walls Cc: Antonino Daplas Cc: Borislav Petkov Cc: Daniel Vetter Cc: Dave Airlie Cc: Dave Hansen Cc: Davidlohr Bueso Cc: Doug Ledford Cc: H. Peter Anvin Cc: Jean-Christophe Plagniol-Villard Cc: Juergen Gross Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Suresh Siddha Cc: Thomas Gleixner Cc: Tomi Valkeinen Cc: Toshi Kani Cc: Ville Syrjälä Cc: Vlastimil Babka Cc: airlied@linux.ie Cc: benh@kernel.crashing.org Cc: bhelgaas@google.com Cc: dan.j.williams@intel.com Cc: konrad.wilk@oracle.com Cc: linux-fbdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-media@vger.kernel.org Cc: mst@redhat.com Cc: netdev@vger.kernel.org Cc: vinod.koul@intel.com Cc: xen-devel@lists.xensource.com Link: http://lkml.kernel.org/r/1440443613-13696-12-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- Documentation/x86/mtrr.txt | 20 ++++++++++++++++---- arch/x86/kernel/cpu/mtrr/main.c | 2 -- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt index 860bc3adc223..dc3e703913ac 100644 --- a/Documentation/x86/mtrr.txt +++ b/Documentation/x86/mtrr.txt @@ -6,10 +6,22 @@ Luis R. Rodriguez - April 9, 2015 =============================================================================== Phasing out MTRR use -MTRR use is replaced on modern x86 hardware with PAT. Over time the only type -of effective MTRR that is expected to be supported will be for write-combining. -As MTRR use is phased out device drivers should use arch_phys_wc_add() to make -MTRR effective on non-PAT systems while a no-op on PAT enabled systems. +MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by +drivers on Linux is now completely phased out, device drivers should use +arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on +non-PAT systems while a no-op but equally effective on PAT enabled systems. + +Even if Linux does not use MTRRs directly, some x86 platform firmware may still +set up MTRRs early before booting the OS. They do this as some platform +firmware may still have implemented access to MTRRs which would be controlled +and handled by the platform firmware directly. An example of platform use of +MTRRs is through the use of SMI handlers, one case could be for fan control, +the platform code would need uncachable access to some of its fan control +registers. Such platform access does not need any Operating System MTRR code in +place other than mtrr_type_lookup() to ensure any OS specific mapping requests +are aligned with platform MTRR setup. If MTRRs are only set up by the platform +firmware code though and the OS does not make any specific MTRR mapping +requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID. For details refer to Documentation/x86/pat.txt. diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index e7ed0d8ebacb..f891b4750f04 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -448,7 +448,6 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } -EXPORT_SYMBOL(mtrr_add); /** * mtrr_del_page - delete a memory type region @@ -537,7 +536,6 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) return -EINVAL; return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } -EXPORT_SYMBOL(mtrr_del); /** * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable -- cgit v1.2.3-59-g8ed1b From aa14318aa02f14044acf81f418e1a1cbda29fcfc Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Fri, 10 Apr 2015 10:36:56 +0200 Subject: DT: leds: Improve description of flash LEDs related properties 1. Since max-microamp property has had no users so far, then rename it to more descriptive led-max-microamp. 2. Since flash-timeout-us property has had no users so far, then rename it to more accurate flash-max-timeout-us. 3. Describe led-max-microamp property as mandatory for specific board configurations. 4. Make flash-max-microamp and flash-max-timeout-us properties mandatory for devices with configurable flash current and flash timeout settings respectively. Signed-off-by: Jacek Anaszewski Cc: Richard Purdie Cc: Pavel Machek Cc: devicetree@vger.kernel.org Acked-by: Sakari Ailus Acked-by: Sylwester Nawrocki --- Documentation/devicetree/bindings/leds/common.txt | 27 +++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt index 747c53805eec..68419843e32f 100644 --- a/Documentation/devicetree/bindings/leds/common.txt +++ b/Documentation/devicetree/bindings/leds/common.txt @@ -29,14 +29,23 @@ Optional properties for child nodes: "ide-disk" - LED indicates disk activity "timer" - LED flashes at a fixed, configurable rate -- max-microamp : maximum intensity in microamperes of the LED - (torch LED for flash devices) -- flash-max-microamp : maximum intensity in microamperes of the - flash LED; it is mandatory if the LED should - support the flash mode -- flash-timeout-us : timeout in microseconds after which the flash - LED is turned off +- led-max-microamp : Maximum LED supply current in microamperes. This property + can be made mandatory for the board configurations + introducing a risk of hardware damage in case an excessive + current is set. + For flash LED controllers with configurable current this + property is mandatory for the LEDs in the non-flash modes + (e.g. torch or indicator). +Required properties for flash LED child nodes: +- flash-max-microamp : Maximum flash LED supply current in microamperes. +- flash-max-timeout-us : Maximum timeout in microseconds after which the flash + LED is turned off. + +For controllers that have no configurable current the flash-max-microamp +property can be omitted. +For controllers that have no configurable timeout the flash-max-timeout-us +property can be omitted. Examples: @@ -49,7 +58,7 @@ system-status { camera-flash { label = "Flash"; led-sources = <0>, <1>; - max-microamp = <50000>; + led-max-microamp = <50000>; flash-max-microamp = <320000>; - flash-timeout-us = <500000>; + flash-max-timeout-us = <500000>; }; -- cgit v1.2.3-59-g8ed1b From f7fafd083ccc340502448903aaddc76f10785c8c Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Thu, 2 Jul 2015 19:56:40 +0200 Subject: leds: leds-ns2: move LED modes mapping outside of the driver On the board n090401 (Seagate NAS 4-Bay), the LED mode mapping (GPIO values to LED mode) is different from the one used on other boards supported by the leds-ns2 driver. With this patch the hardcoded mapping is removed from leds-ns2. Now, it must be defined either in the platform data (if an old-fashion board setup file is used) or in the DT node. In order to allow the later, this patch also introduces a modes-map property for the leds-ns2 DT binding. Signed-off-by: Vincent Donnefort Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/leds/leds-ns2.txt | 9 ++ drivers/leds/leds-ns2.c | 102 +++++++++++---------- include/dt-bindings/leds/leds-ns2.h | 8 ++ include/linux/platform_data/leds-kirkwood-ns2.h | 14 +++ 4 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 include/dt-bindings/leds/leds-ns2.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/leds-ns2.txt b/Documentation/devicetree/bindings/leds/leds-ns2.txt index aef3aca34d2d..9f81258a5b6e 100644 --- a/Documentation/devicetree/bindings/leds/leds-ns2.txt +++ b/Documentation/devicetree/bindings/leds/leds-ns2.txt @@ -8,6 +8,9 @@ Each LED is represented as a sub-node of the ns2-leds device. Required sub-node properties: - cmd-gpio: Command LED GPIO. See OF device-tree GPIO specification. - slow-gpio: Slow LED GPIO. See OF device-tree GPIO specification. +- modes-map: A mapping between LED modes (off, on or SATA activity blinking) and + the corresponding cmd-gpio/slow-gpio values. All the GPIO values combinations + should be given in order to avoid having an unknown mode at driver probe time. Optional sub-node properties: - label: Name for this LED. If omitted, the label is taken from the node name. @@ -15,6 +18,8 @@ Optional sub-node properties: Example: +#include + ns2-leds { compatible = "lacie,ns2-leds"; @@ -22,5 +27,9 @@ ns2-leds { label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = ; }; }; diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 1fd6adbb43b7..b0bc03539dbb 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -33,46 +33,20 @@ #include /* - * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in - * relation with the SATA activity. This capability is exposed through the - * "sata" sysfs attribute. - * - * The following array detail the different LED registers and the combination - * of their possible values: - * - * cmd_led | slow_led | /SATA active | LED state - * | | | - * 1 | 0 | x | off - * - | 1 | x | on - * 0 | 0 | 1 | on - * 0 | 0 | 0 | blink (rate 300ms) + * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED + * modes are available: off, on and SATA activity blinking. The LED modes are + * controlled through two GPIOs (command and slow): each combination of values + * for the command/slow GPIOs corresponds to a LED mode. */ -enum ns2_led_modes { - NS_V2_LED_OFF, - NS_V2_LED_ON, - NS_V2_LED_SATA, -}; - -struct ns2_led_mode_value { - enum ns2_led_modes mode; - int cmd_level; - int slow_level; -}; - -static struct ns2_led_mode_value ns2_led_modval[] = { - { NS_V2_LED_OFF , 1, 0 }, - { NS_V2_LED_ON , 0, 1 }, - { NS_V2_LED_ON , 1, 1 }, - { NS_V2_LED_SATA, 0, 0 }, -}; - struct ns2_led_data { struct led_classdev cdev; unsigned cmd; unsigned slow; unsigned char sata; /* True when SATA mode active. */ rwlock_t rw_lock; /* Lock GPIOs. */ + int num_modes; + struct ns2_led_modval *modval; }; static int ns2_led_get_mode(struct ns2_led_data *led_dat, @@ -88,10 +62,10 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat, cmd_level = gpio_get_value(led_dat->cmd); slow_level = gpio_get_value(led_dat->slow); - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { - if (cmd_level == ns2_led_modval[i].cmd_level && - slow_level == ns2_led_modval[i].slow_level) { - *mode = ns2_led_modval[i].mode; + for (i = 0; i < led_dat->num_modes; i++) { + if (cmd_level == led_dat->modval[i].cmd_level && + slow_level == led_dat->modval[i].slow_level) { + *mode = led_dat->modval[i].mode; ret = 0; break; } @@ -110,12 +84,12 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat, write_lock_irqsave(&led_dat->rw_lock, flags); - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { - if (mode == ns2_led_modval[i].mode) { + for (i = 0; i < led_dat->num_modes; i++) { + if (mode == led_dat->modval[i].mode) { gpio_set_value(led_dat->cmd, - ns2_led_modval[i].cmd_level); + led_dat->modval[i].cmd_level); gpio_set_value(led_dat->slow, - ns2_led_modval[i].slow_level); + led_dat->modval[i].slow_level); } } @@ -228,6 +202,8 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, led_dat->cdev.groups = ns2_led_groups; led_dat->cmd = template->cmd; led_dat->slow = template->slow; + led_dat->modval = template->modval; + led_dat->num_modes = template->num_modes; ret = ns2_led_get_mode(led_dat, &mode); if (ret < 0) @@ -259,9 +235,8 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) { struct device_node *np = dev->of_node; struct device_node *child; - struct ns2_led *leds; + struct ns2_led *led, *leds; int num_leds = 0; - int i = 0; num_leds = of_get_child_count(np); if (!num_leds) @@ -272,26 +247,57 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) if (!leds) return -ENOMEM; + led = leds; for_each_child_of_node(np, child) { const char *string; - int ret; + int ret, i, num_modes; + struct ns2_led_modval *modval; ret = of_get_named_gpio(child, "cmd-gpio", 0); if (ret < 0) return ret; - leds[i].cmd = ret; + led->cmd = ret; ret = of_get_named_gpio(child, "slow-gpio", 0); if (ret < 0) return ret; - leds[i].slow = ret; + led->slow = ret; ret = of_property_read_string(child, "label", &string); - leds[i].name = (ret == 0) ? string : child->name; + led->name = (ret == 0) ? string : child->name; ret = of_property_read_string(child, "linux,default-trigger", &string); if (ret == 0) - leds[i].default_trigger = string; + led->default_trigger = string; + + ret = of_property_count_u32_elems(child, "modes-map"); + if (ret < 0 || ret % 3) { + dev_err(dev, + "Missing or malformed modes-map property\n"); + return -EINVAL; + } + + num_modes = ret / 3; + modval = devm_kzalloc(dev, + num_modes * sizeof(struct ns2_led_modval), + GFP_KERNEL); + if (!modval) + return -ENOMEM; + + for (i = 0; i < num_modes; i++) { + of_property_read_u32_index(child, + "modes-map", 3 * i, + (u32 *) &modval[i].mode); + of_property_read_u32_index(child, + "modes-map", 3 * i + 1, + (u32 *) &modval[i].cmd_level); + of_property_read_u32_index(child, + "modes-map", 3 * i + 2, + (u32 *) &modval[i].slow_level); + } + + led->num_modes = num_modes; + led->modval = modval; - i++; + led++; } pdata->leds = leds; diff --git a/include/dt-bindings/leds/leds-ns2.h b/include/dt-bindings/leds/leds-ns2.h new file mode 100644 index 000000000000..491c5f974a92 --- /dev/null +++ b/include/dt-bindings/leds/leds-ns2.h @@ -0,0 +1,8 @@ +#ifndef _DT_BINDINGS_LEDS_NS2_H +#define _DT_BINDINGS_LEDS_NS2_H + +#define NS_V2_LED_OFF 0 +#define NS_V2_LED_ON 1 +#define NS_V2_LED_SATA 2 + +#endif diff --git a/include/linux/platform_data/leds-kirkwood-ns2.h b/include/linux/platform_data/leds-kirkwood-ns2.h index 6a9fed57f346..eb8a6860e816 100644 --- a/include/linux/platform_data/leds-kirkwood-ns2.h +++ b/include/linux/platform_data/leds-kirkwood-ns2.h @@ -9,11 +9,25 @@ #ifndef __LEDS_KIRKWOOD_NS2_H #define __LEDS_KIRKWOOD_NS2_H +enum ns2_led_modes { + NS_V2_LED_OFF, + NS_V2_LED_ON, + NS_V2_LED_SATA, +}; + +struct ns2_led_modval { + enum ns2_led_modes mode; + int cmd_level; + int slow_level; +}; + struct ns2_led { const char *name; const char *default_trigger; unsigned cmd; unsigned slow; + int num_modes; + struct ns2_led_modval *modval; }; struct ns2_led_platform_data { -- cgit v1.2.3-59-g8ed1b From ce14c5831364118324b10c0355dead062b9ddd40 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 25 Aug 2015 13:34:53 -0400 Subject: Documentation, add kernel-parameters.txt entry for dis_ucode_ldr dis_ucode_ldr was introduced in 65cef13 ("x86, microcode: Add a disable chicken bit") and will disable microcode loading on x86. This kernel parameter is buried in the code and should be added to the Documentation. Signed-off-by: Prarit Bhargava Signed-off-by: Jonathan Corbet --- Documentation/kernel-parameters.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d6f0459cd7b..34f2afbf7c15 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -910,6 +910,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Disable PIN 1 of APIC timer Can be useful to work around chipset bugs. + dis_ucode_ldr [X86] Disable the microcode loader. + dma_debug=off If the kernel is compiled with DMA_API_DEBUG support, this option disables the debugging code at boot. -- cgit v1.2.3-59-g8ed1b From bf9628373418328daf67b6508fc3713fc6f5067d Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Thu, 27 Aug 2015 17:49:29 +0530 Subject: spi: Add DT bindings documentation for Netlogic XLP SPI controller Add DT bindings documentation for SPI controller driver used by Netlogic XLP MIPS64 SoCs. Signed-off-by: Kamlakant Patel Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-xlp.txt | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-xlp.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-xlp.txt b/Documentation/devicetree/bindings/spi/spi-xlp.txt new file mode 100644 index 000000000000..40e82d51efec --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-xlp.txt @@ -0,0 +1,39 @@ +SPI Master controller for Netlogic XLP MIPS64 SOCs +================================================== + +Currently this SPI controller driver is supported for the following +Netlogic XLP SoCs: + XLP832, XLP316, XLP208, XLP980, XLP532 + +Required properties: +- compatible : Should be "netlogic,xlp832-spi". +- #address-cells : Number of cells required to define a chip select address + on the SPI bus. +- #size-cells : Should be zero. +- reg : Should contain register location and length. +- clocks : Phandle of the spi clock +- interrupts : Interrupt number used by this controller. +- interrupt-parent : Phandle of the parent interrupt controller. + +SPI slave nodes must be children of the SPI master node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + + spi: xlp_spi@3a100 { + compatible = "netlogic,xlp832-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x3a100 0x100>; + clocks = <&spi_clk>; + interrupts = <34>; + interrupt-parent = <&pic>; + + spi_nor@1 { + compatible = "spansion,s25sl12801"; + #address-cells = <1>; + #size-cells = <1>; + reg = <1>; /* Chip Select */ + spi-max-frequency = <40000000>; + }; +}; -- cgit v1.2.3-59-g8ed1b From 72b236d60218fe211a8e1210be31c31e81684b86 Mon Sep 17 00:00:00 2001 From: Aaron Skomra Date: Thu, 20 Aug 2015 16:05:17 -0700 Subject: HID: wacom: Add support for Express Key Remote. This device is pad (buttons) only, there is no stylus or touch. Up to five remotes can pair with the device's associated USB dongle. Signed-off-by: Aaron Skomra Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-wacom | 19 +++ drivers/hid/wacom.h | 7 +- drivers/hid/wacom_sys.c | 195 +++++++++++++++++++++++++++ drivers/hid/wacom_wac.c | 144 ++++++++++++++++++++ drivers/hid/wacom_wac.h | 7 +- 5 files changed, 370 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index c4f0fed64a6e..dca429340772 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -77,3 +77,22 @@ Description: The format is also scrambled, like in the USB mode, and it can be summarized by converting 76543210 into GECA6420. HGFEDCBA HFDB7531 + +What: /sys/bus/hid/devices/::./wacom_remote/unpair_remote +Date: July 2015 +Contact: linux-input@vger.kernel.org +Description: + Writing the character sequence '*' followed by a newline to + this file will delete all of the current pairings on the + device. Other character sequences are reserved. This file is + write only. + +What: /sys/bus/hid/devices/::./wacom_remote//remote_mode +Date: July 2015 +Contact: linux-input@vger.kernel.org +Description: + Reading from this file reports the mode status of the + remote as indicated by the LED lights on the device. If no + reports have been received from the paired device, reading + from this file will report '-1'. The mode is read-only + and cannot be set through the driver. diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index a533787a6d85..4681a65a4579 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -113,7 +113,7 @@ struct wacom { struct mutex lock; struct work_struct work; struct wacom_led { - u8 select[2]; /* status led selector (0..3) */ + u8 select[5]; /* status led selector (0..3) */ u8 llv; /* status led brightness no button (1..127) */ u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ @@ -123,6 +123,8 @@ struct wacom { struct power_supply *ac; struct power_supply_desc battery_desc; struct power_supply_desc ac_desc; + struct kobject *remote_dir; + struct attribute_group remote_group[5]; }; static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) @@ -147,4 +149,7 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_battery_work(struct work_struct *work); +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, + int index); +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 6edb7d136476..5f6e48e55df9 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -23,9 +23,13 @@ #define WAC_CMD_ICON_XFER 0x23 #define WAC_CMD_ICON_BT_XFER 0x26 #define WAC_CMD_RETRIES 10 +#define WAC_CMD_DELETE_PAIRING 0x20 +#define WAC_CMD_UNPAIR_ALL 0xFF +#define WAC_REMOTE_SERIAL_MAX_STRLEN 9 #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) +#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, size_t size, unsigned int retries) @@ -1119,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev, static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM, wacom_show_speed, wacom_store_speed); + +static ssize_t wacom_show_remote_mode(struct kobject *kobj, + struct kobj_attribute *kattr, + char *buf, int index) +{ + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + u8 mode; + + mode = wacom->led.select[index]; + if (mode >= 0 && mode < 3) + return snprintf(buf, PAGE_SIZE, "%d\n", mode); + else + return snprintf(buf, PAGE_SIZE, "%d\n", -1); +} + +#define DEVICE_EKR_ATTR_GROUP(SET_ID) \ +static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \ + struct kobj_attribute *kattr, char *buf) \ +{ \ + return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \ +} \ +static struct kobj_attribute remote##SET_ID##_mode_attr = { \ + .attr = {.name = "remote_mode", \ + .mode = DEV_ATTR_RO_PERM}, \ + .show = wacom_show_remote##SET_ID##_mode, \ +}; \ +static struct attribute *remote##SET_ID##_serial_attrs[] = { \ + &remote##SET_ID##_mode_attr.attr, \ + NULL \ +}; \ +static struct attribute_group remote##SET_ID##_serial_group = { \ + .name = NULL, \ + .attrs = remote##SET_ID##_serial_attrs, \ +} + +DEVICE_EKR_ATTR_GROUP(0); +DEVICE_EKR_ATTR_GROUP(1); +DEVICE_EKR_ATTR_GROUP(2); +DEVICE_EKR_ATTR_GROUP(3); +DEVICE_EKR_ATTR_GROUP(4); + +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index) +{ + int error = 0; + char *buf; + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + wacom_wac->serial[index] = serial; + + buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial); + wacom->remote_group[index].name = buf; + + error = sysfs_create_group(wacom->remote_dir, + &wacom->remote_group[index]); + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + kobject_put(wacom->remote_dir); + return error; + } + + return 0; +} + +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial) +{ + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + int i; + + if (!serial) + return; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) { + wacom_wac->serial[i] = 0; + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + if (wacom->remote_group[i].name) { + sysfs_remove_group(wacom->remote_dir, + &wacom->remote_group[i]); + kfree(wacom->remote_group[i].name); + wacom->remote_group[i].name = NULL; + } + } + } +} + +static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector) +{ + const size_t buf_size = 2; + unsigned char *buf; + int retval; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = WAC_CMD_DELETE_PAIRING; + buf[1] = selector; + + retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf, + buf_size, WAC_CMD_RETRIES); + kfree(buf); + + return retval; +} + +static ssize_t wacom_store_unpair_remote(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned char selector = 0; + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + int err; + + if (!strncmp(buf, "*\n", 2)) { + selector = WAC_CMD_UNPAIR_ALL; + } else { + hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n", + buf); + return -1; + } + + mutex_lock(&wacom->lock); + + err = wacom_cmd_unpair_remote(wacom, selector); + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +static struct kobj_attribute unpair_remote_attr = { + .attr = {.name = "unpair_remote", .mode = 0200}, + .store = wacom_store_unpair_remote, +}; + +static const struct attribute *remote_unpair_attrs[] = { + &unpair_remote_attr.attr, + NULL +}; + +static int wacom_initialize_remote(struct wacom *wacom) +{ + int error = 0; + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + int i; + + if (wacom->wacom_wac.features.type != REMOTE) + return 0; + + wacom->remote_group[0] = remote0_serial_group; + wacom->remote_group[1] = remote1_serial_group; + wacom->remote_group[2] = remote2_serial_group; + wacom->remote_group[3] = remote3_serial_group; + wacom->remote_group[4] = remote4_serial_group; + + wacom->remote_dir = kobject_create_and_add("wacom_remote", + &wacom->hdev->dev.kobj); + if (!wacom->remote_dir) + return -ENOMEM; + + error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs); + + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + return error; + } + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + wacom_wac->serial[i] = 0; + } + + return 0; +} + static struct input_dev *wacom_allocate_input(struct wacom *wacom) { struct input_dev *input_dev; @@ -1164,6 +1351,8 @@ static void wacom_clean_inputs(struct wacom *wacom) else input_free_device(wacom->wacom_wac.pad_input); } + if (wacom->remote_dir) + kobject_put(wacom->remote_dir); wacom->wacom_wac.pen_input = NULL; wacom->wacom_wac.touch_input = NULL; wacom->wacom_wac.pad_input = NULL; @@ -1243,10 +1432,16 @@ static int wacom_register_inputs(struct wacom *wacom) error = wacom_initialize_leds(wacom); if (error) goto fail_leds; + + error = wacom_initialize_remote(wacom); + if (error) + goto fail_remote; } return 0; +fail_remote: + wacom_destroy_leds(wacom); fail_leds: input_unregister_device(pad_input_dev); pad_input_dev = NULL; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ee5d278afa3f..391a68731fe3 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -631,6 +631,130 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 0; } +static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len) +{ + unsigned char *data = wacom_wac->data; + struct input_dev *input = wacom_wac->pad_input; + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + struct wacom_features *features = &wacom_wac->features; + int bat_charging, bat_percent, touch_ring_mode; + __u32 serial; + int i; + + if (data[0] != WACOM_REPORT_REMOTE) { + dev_dbg(input->dev.parent, + "%s: received unknown report #%d", __func__, data[0]); + return 0; + } + + serial = data[3] + (data[4] << 8) + (data[5] << 16); + wacom_wac->id[0] = PAD_DEVICE_ID; + + input_report_key(input, BTN_0, (data[9] & 0x01)); + input_report_key(input, BTN_1, (data[9] & 0x02)); + input_report_key(input, BTN_2, (data[9] & 0x04)); + input_report_key(input, BTN_3, (data[9] & 0x08)); + input_report_key(input, BTN_4, (data[9] & 0x10)); + input_report_key(input, BTN_5, (data[9] & 0x20)); + input_report_key(input, BTN_6, (data[9] & 0x40)); + input_report_key(input, BTN_7, (data[9] & 0x80)); + + input_report_key(input, BTN_8, (data[10] & 0x01)); + input_report_key(input, BTN_9, (data[10] & 0x02)); + input_report_key(input, BTN_A, (data[10] & 0x04)); + input_report_key(input, BTN_B, (data[10] & 0x08)); + input_report_key(input, BTN_C, (data[10] & 0x10)); + input_report_key(input, BTN_X, (data[10] & 0x20)); + input_report_key(input, BTN_Y, (data[10] & 0x40)); + input_report_key(input, BTN_Z, (data[10] & 0x80)); + + input_report_key(input, BTN_BASE, (data[11] & 0x01)); + input_report_key(input, BTN_BASE2, (data[11] & 0x02)); + + if (data[12] & 0x80) + input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f)); + else + input_report_abs(input, ABS_WHEEL, 0); + + bat_percent = data[7] & 0x7f; + bat_charging = !!(data[7] & 0x80); + + if (data[9] | data[10] | (data[11] & 0x03) | data[12]) + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + else + input_report_abs(input, ABS_MISC, 0); + + input_event(input, EV_MSC, MSC_SERIAL, serial); + + /*Which mode select (LED light) is currently on?*/ + touch_ring_mode = (data[11] & 0xC0) >> 6; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) + wacom->led.select[i] = touch_ring_mode; + } + + if (!wacom->battery && + !(features->quirks & WACOM_QUIRK_BATTERY)) { + features->quirks |= WACOM_QUIRK_BATTERY; + INIT_WORK(&wacom->work, wacom_battery_work); + wacom_schedule_work(wacom_wac); + } + + wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, + bat_charging); + + return 1; +} + +static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len) +{ + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + unsigned char *data = wacom_wac->data; + int i; + + if (data[0] != WACOM_REPORT_DEVICE_LIST) + return 0; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + int j = i * 6; + int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4]; + bool connected = data[j+2]; + + if (connected) { + int k; + + if (wacom_wac->serial[i] == serial) + continue; + + if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + + /* A remote can pair more than once with an EKR, + * check to make sure this serial isn't already paired. + */ + for (k = 0; k < WACOM_MAX_REMOTES; k++) { + if (wacom_wac->serial[k] == serial) + break; + } + + if (k < WACOM_MAX_REMOTES) { + wacom_wac->serial[i] = serial; + continue; + } + wacom_remote_create_attr_group(wacom, serial, i); + + } else if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + } + + return 0; +} + static void wacom_intuos_general(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -2191,6 +2315,13 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) sync = wacom_wireless_irq(wacom_wac, len); break; + case REMOTE: + if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST) + sync = wacom_remote_status_irq(wacom_wac, len); + else + sync = wacom_remote_irq(wacom_wac, len); + break; + default: sync = false; break; @@ -2298,6 +2429,9 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type == BAMBOO_PAD) features->device_type = WACOM_DEVICETYPE_TOUCH; + if (features->type == REMOTE) + features->device_type = WACOM_DEVICETYPE_PAD; + if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; @@ -2717,6 +2851,11 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, break; + case REMOTE: + input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); + break; + default: /* no pad supported */ return -ENODEV; @@ -3186,6 +3325,10 @@ static const struct wacom_features wacom_features_0x323 = { "Wacom Intuos P M", 21600, 13500, 1023, 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; +static const struct wacom_features wacom_features_0x331 = + { "Wacom Express Key Remote", 0, 0, 0, 0, + REMOTE, 0, 0, 18, .check_for_hid_type = true, + .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC }; @@ -3341,6 +3484,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x32B) }, { USB_DEVICE_WACOM(0x32C) }, { USB_DEVICE_WACOM(0x32F) }, + { USB_DEVICE_WACOM(0x331) }, { USB_DEVICE_WACOM(0x333) }, { USB_DEVICE_WACOM(0x335) }, { USB_DEVICE_WACOM(0x336) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 4ee5c13b4e75..1e270d401e18 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -16,6 +16,8 @@ #define WACOM_PKGLEN_MAX 192 #define WACOM_NAME_MAX 64 +#define WACOM_MAX_REMOTES 5 +#define WACOM_STATUS_UNKNOWN 255 /* packet length for individual models */ #define WACOM_PKGLEN_BBFUN 9 @@ -65,6 +67,8 @@ #define WACOM_REPORT_USB 192 #define WACOM_REPORT_BPAD_PEN 3 #define WACOM_REPORT_BPAD_TOUCH 16 +#define WACOM_REPORT_DEVICE_LIST 16 +#define WACOM_REPORT_REMOTE 17 /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 @@ -129,6 +133,7 @@ enum { WACOM_24HDT, WACOM_27QHDT, BAMBOO_PAD, + REMOTE, TABLETPC, /* add new TPC below */ TABLETPCE, TABLETPC2FG, @@ -208,7 +213,7 @@ struct wacom_wac { unsigned char data[WACOM_PKGLEN_MAX]; int tool[2]; int id[2]; - __u32 serial[2]; + __u32 serial[5]; bool reporting_data; struct wacom_features features; struct wacom_shared *shared; -- cgit v1.2.3-59-g8ed1b From 472204fe37083aa8f31aaf183b4072d432e7c5ea Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Mon, 31 Aug 2015 11:51:29 +0530 Subject: Documentation: DT: cpsw: document missing compatible CPSW driver has multiple compatibles for errata implementations but not documented, add necessary documentation. Signed-off-by: Mugunthan V N Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/net/cpsw.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt index 33fe8462edf4..a9df21aaa154 100644 --- a/Documentation/devicetree/bindings/net/cpsw.txt +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -2,7 +2,11 @@ TI SoC Ethernet Switch Controller Device Tree Bindings ------------------------------------------------------ Required properties: -- compatible : Should be "ti,cpsw" +- compatible : Should be one of the below:- + "ti,cpsw" for backward compatible + "ti,am335x-cpsw" for AM335x controllers + "ti,am4372-cpsw" for AM437x controllers + "ti,dra7-cpsw" for DRA7x controllers - reg : physical base address and size of the cpsw registers map - interrupts : property with a value describing the interrupt -- cgit v1.2.3-59-g8ed1b From 9d6f85d9fe422aa42f3f337872050fb2a30cd430 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 30 Aug 2015 21:44:12 +0200 Subject: mtd: nand: pxa3xx: add optional dma for pxa architecture The PXA architecture provides a DMA to pump data from the nand controller to memory and the other way around. Add it to the binding description. Signed-off-by: Robert Jarzmik Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index 4f833e3c4f51..d9b655f11048 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -11,6 +11,7 @@ Required properties: Optional properties: + - dmas: dma data channel, see dma.txt binding doc - marvell,nand-enable-arbiter: Set to enable the bus arbiter - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader @@ -32,6 +33,8 @@ Example: compatible = "marvell,pxa3xx-nand"; reg = <0x43100000 90>; interrupts = <45>; + dmas = <&pdma 97 0>; + dma-names = "data"; #address-cells = <1>; marvell,nand-enable-arbiter; -- cgit v1.2.3-59-g8ed1b From c9c96ae2c57d91ea2b73ef447fdd44c760a96d97 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Mon, 17 Aug 2015 17:24:23 +0800 Subject: dt-bindings: mediatek: Add MT8173 CPU DVFS clock bindings This patch adds the clock and regulator consumer properties part of document for CPU DVFS clocks on Mediatek MT8173 SoC. Signed-off-by: Pi-Cheng Chen Acked-by: Michael Turquette Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- .../devicetree/bindings/clock/mt8173-cpu-dvfs.txt | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt b/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt new file mode 100644 index 000000000000..52b457c23eed --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt @@ -0,0 +1,83 @@ +Device Tree Clock bindins for CPU DVFS of Mediatek MT8173 SoC + +Required properties: +- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock names. +- clock-names: Should contain the following: + "cpu" - The multiplexer for clock input of CPU cluster. + "intermediate" - A parent of "cpu" clock which is used as "intermediate" clock + source (usually MAINPLL) when the original CPU PLL is under + transition and not stable yet. + Please refer to Documentation/devicetree/bindings/clk/clock-bindings.txt for + generic clock consumer properties. +- proc-supply: Regulator for Vproc of CPU cluster. + +Optional properties: +- sram-supply: Regulator for Vsram of CPU cluster. When present, the cpufreq driver + needs to do "voltage tracking" to step by step scale up/down Vproc and + Vsram to fit SoC specific needs. When absent, the voltage scaling + flow is handled by hardware, hence no software "voltage tracking" is + needed. + +Example: +-------- + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x000>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x001>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + &cpu0 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu1 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu2 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; + + &cpu3 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; -- cgit v1.2.3-59-g8ed1b From 6bfb7c7434f75d29241413dc7e784295ba56de98 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:14 +0530 Subject: cpufreq: remove redundant CPUFREQ_INCOMPATIBLE notifier event What's being done from CPUFREQ_INCOMPATIBLE, can also be done with CPUFREQ_ADJUST. There is nothing special with CPUFREQ_INCOMPATIBLE notifier. Kill CPUFREQ_INCOMPATIBLE and fix its usage sites. This also updates the numbering of notifier events to remove holes. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/core.txt | 7 ++----- drivers/acpi/processor_perflib.c | 2 +- drivers/cpufreq/cpufreq.c | 4 ---- drivers/cpufreq/ppc_cbe_cpufreq_pmi.c | 4 ++-- drivers/video/fbdev/pxafb.c | 1 - drivers/video/fbdev/sa1100fb.c | 1 - include/linux/cpufreq.h | 9 ++++----- 7 files changed, 9 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt index 70933eadc308..ba78e7c2a069 100644 --- a/Documentation/cpu-freq/core.txt +++ b/Documentation/cpu-freq/core.txt @@ -55,16 +55,13 @@ transition notifiers. ---------------------------- These are notified when a new policy is intended to be set. Each -CPUFreq policy notifier is called three times for a policy transition: +CPUFreq policy notifier is called twice for a policy transition: 1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if they see a need for this - may it be thermal considerations or hardware limitations. -2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid - hardware failure. - -3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy +2.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy - if two hardware drivers failed to agree on a new policy before this stage, the incompatible hardware shall be shut down, and the user informed of this. diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 36b6da2918a6..91941f1cdecb 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -87,7 +87,7 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, if (ignore_ppc) return 0; - if (event != CPUFREQ_INCOMPATIBLE) + if (event != CPUFREQ_ADJUST) return 0; mutex_lock(&performance_mutex); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 76a26609d96b..293f47b814bf 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2206,10 +2206,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, new_policy); - /* adjust if necessary - hardware incompatibility*/ - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_INCOMPATIBLE, new_policy); - /* * verify the cpu speed can be set within this limit, which might be * different to the first one diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index d29e8da396a0..7969f7690498 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -97,8 +97,8 @@ static int pmi_notifier(struct notifier_block *nb, struct cpufreq_frequency_table *cbe_freqs; u8 node; - /* Should this really be called for CPUFREQ_ADJUST, CPUFREQ_INCOMPATIBLE - * and CPUFREQ_NOTIFY policy events?) + /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY + * policy events?) */ if (event == CPUFREQ_START) return 0; diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index 7245611ec963..94813af97f09 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -1668,7 +1668,6 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: pr_debug("min dma period: %d ps, " "new clock %d kHz\n", pxafb_display_dma_period(var), policy->max); diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 89dd7e02197f..dcf774c15889 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -1042,7 +1042,6 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: dev_dbg(fbi->dev, "min dma period: %d ps, " "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), policy->max); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bde1e567b3a9..bedcc90c0757 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -369,11 +369,10 @@ static inline void cpufreq_resume(void) {} /* Policy Notifiers */ #define CPUFREQ_ADJUST (0) -#define CPUFREQ_INCOMPATIBLE (1) -#define CPUFREQ_NOTIFY (2) -#define CPUFREQ_START (3) -#define CPUFREQ_CREATE_POLICY (4) -#define CPUFREQ_REMOVE_POLICY (5) +#define CPUFREQ_NOTIFY (1) +#define CPUFREQ_START (2) +#define CPUFREQ_CREATE_POLICY (3) +#define CPUFREQ_REMOVE_POLICY (4) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -- cgit v1.2.3-59-g8ed1b