From 9ac6cb5fbb1781d120ca0ad29d014d35c9c3f0c4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:17 +0100 Subject: i2c: add suspended flag and accessors for i2c adapters A few drivers open code the handling of suspended adapters. It could be handled by the core, though, to ensure generic handling. This patch adds the flag and accessor functions. The usage of these helpers is optional, though. See the kerneldoc in this patch. Using the new flag, we now reject further transfers if the adapter is already marked suspended. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/fault-codes | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/i2c/fault-codes b/Documentation/i2c/fault-codes index 47c25abb7d52..0cee0fc545b4 100644 --- a/Documentation/i2c/fault-codes +++ b/Documentation/i2c/fault-codes @@ -112,6 +112,10 @@ EPROTO case is when the length of an SMBus block data response (from the SMBus slave) is outside the range 1-32 bytes. +ESHUTDOWN + Returned when a transfer was requested using an adapter + which is already suspended. + ETIMEDOUT This is returned by drivers when an operation took too much time, and was aborted before it completed. -- cgit v1.2.3 From 9f21ef41a5c55c8d6f3c2f8a8773126f698f2a7d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 28 Jan 2019 23:25:33 +0100 Subject: i2c: Add DT bindings for Xscale I2C masters This adds a device tree binding for Intel XScale I2C masters. We define compatible strings for the iop3xx and ixp4xx chip families. Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-xscale.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-xscale.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-xscale.txt b/Documentation/devicetree/bindings/i2c/i2c-xscale.txt new file mode 100644 index 000000000000..dcc8390e0d24 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-xscale.txt @@ -0,0 +1,20 @@ +i2c Controller on XScale platforms such as IOP3xx and IXP4xx + +Required properties: +- compatible : Must be one of + "intel,iop3xx-i2c" + "intel,ixp4xx-i2c"; +- reg +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding + +Example: + +i2c@c8011000 { + compatible = "intel,ixp4xx-i2c"; + reg = <0xc8011000 0x18>; + interrupts = <33 IRQ_TYPE_LEVEL_LOW>; +}; -- cgit v1.2.3 From 70ae5669b5b3f357a5c1d64152508506624a5c5d Mon Sep 17 00:00:00 2001 From: qii wang Date: Mon, 21 Jan 2019 15:59:29 +0800 Subject: dt-bindings: i2c: Add Mediatek MT7629 i2c binding Add MT7629 i2c binding to binding file. Signed-off-by: qii wang Reviewed-by: Rob Herring Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mtk.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt index e199695b1c96..ee4c32454198 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt @@ -10,6 +10,7 @@ Required properties: "mediatek,mt6589-i2c": for MediaTek MT6589 "mediatek,mt7622-i2c": for MediaTek MT7622 "mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623 + "mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629 "mediatek,mt8173-i2c": for MediaTek MT8173 - reg: physical base address of the controller and dma base, length of memory mapped region. -- cgit v1.2.3 From 05bd07280d5f70920c3619998b3a79742e4cde30 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 21 Jan 2019 15:16:57 +0100 Subject: i2c: gpio: fault-injector: better SPHINX style in docs We don't use SPHINX currently in I2C documentation; but preparing the I2C fault injector docs already is a good idea since it makes it easier to read. Especially as new stuff is going to be added soon. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/gpio-fault-injection | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection index a4ce62090fd5..1a44e3edc0c4 100644 --- a/Documentation/i2c/gpio-fault-injection +++ b/Documentation/i2c/gpio-fault-injection @@ -1,3 +1,4 @@ +========================= Linux I2C fault injection ========================= @@ -13,6 +14,9 @@ mounted at /sys/kernel/debug. There will be a separate subdirectory per GPIO driven I2C bus. Each subdirectory will contain files to trigger the fault injection. They will be described now along with their intended use-cases. +Wire states +=========== + "scl" ----- @@ -34,10 +38,10 @@ I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C core (see 'struct bus_recovery_info'). However, the bus recovery will not succeed because SDA is still pinned low until you manually release it again with "echo 1 > sda". A test with an automatic release can be done with the -following class of fault injectors. +"incomplete transfers" class of fault injectors. -Introduction to incomplete transfers ------------------------------------- +Incomplete transfers +==================== The following fault injectors create situations where SDA will be held low by a device. Bus recovery should be able to fix these situations. But please note: -- cgit v1.2.3 From e7224a116f0dac593233143849f25bc095f8d2cc Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 5 Feb 2019 14:03:44 +0100 Subject: dt-bindings: at24: add the 'num-addresses' property Currently the at24 driver only creates additional i2c dummies for atmel,24c00 and it's hard-coded. Some other chips (like for example Microchip's 24AA02T) also take more slave addresses despite being otherwise compatible with already supported variants. Add a new property to the device tree binding document that defines the total number of i2c slave addresses taken by the device. The addresses are counted starting from the one in the reg property. Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/eeprom/at24.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt index f9a7c984274c..0e456bbc1213 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.txt +++ b/Documentation/devicetree/bindings/eeprom/at24.txt @@ -75,6 +75,8 @@ Optional properties: - address-width: number of address bits (one of 8, 16). + - num-addresses: total number of i2c slave addresses this device takes + Example: eeprom@52 { @@ -82,4 +84,5 @@ eeprom@52 { reg = <0x52>; pagesize = <32>; wp-gpios = <&gpio1 3 0>; + num-addresses = <8>; }; -- cgit v1.2.3 From 63e57b6f191db99ffdd0dc6c7b9ee6b2cf7abb04 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Feb 2019 17:39:45 +0100 Subject: i2c: gpio: fault-injector: add 'lose_arbitration' injector Add a fault injector simulating 'arbitration lost' from multi-master setups. Read the docs for its usage. A helper function for future fault injectors using SCL interrupts is created to achieve this. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/gpio-fault-injection | 25 ++++++++++++ drivers/i2c/busses/i2c-gpio.c | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) (limited to 'Documentation') diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection index 1a44e3edc0c4..1f1bb96a64bd 100644 --- a/Documentation/i2c/gpio-fault-injection +++ b/Documentation/i2c/gpio-fault-injection @@ -83,3 +83,28 @@ This is why bus recovery (up to 9 clock pulses) must either check SDA or send additional STOP conditions to ensure the bus has been released. Otherwise random data will be written to a device! +Lost arbitration +================ + +Here, we want to simulate the condition where the master under test loses the +bus arbitration against another master in a multi-master setup. + +"lose_arbitration" +------------------ + +This file is write only and you need to write the duration of the arbitration +intereference (in µs, maximum is 100ms). The calling process will then sleep +and wait for the next bus clock. The process is interruptible, though. + +Arbitration lost is achieved by waiting for SCL going down by the master under +test and then pulling SDA low for some time. So, the I2C address sent out +should be corrupted and that should be detected properly. That means that the +address sent out should have a lot of '1' bits to be able to detect corruption. +There doesn't need to be a device at this address because arbitration lost +should be detected beforehand. Also note, that SCL going down is monitored +using interrupts, so the interrupt latency might cause the first bits to be not +corrupted. A good starting point for using this fault injector on an otherwise +idle bus is: + +# echo 200 > lose_arbitration & +# i2cget -y 0x3f diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 2d532cc042f5..76e43783f50f 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -7,12 +7,14 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -27,6 +29,9 @@ struct i2c_gpio_private_data { struct i2c_gpio_platform_data pdata; #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR struct dentry *debug_dir; + /* these must be protected by bus lock */ + struct completion scl_irq_completion; + u64 scl_irq_data; #endif }; @@ -162,6 +167,70 @@ static int fops_incomplete_write_byte_set(void *data, u64 addr) } DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); +static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv, + irqreturn_t handler(int, void*)) +{ + int ret, irq = gpiod_to_irq(priv->scl); + + if (irq < 0) + return irq; + + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + ret = gpiod_direction_input(priv->scl); + if (ret) + goto unlock; + + reinit_completion(&priv->scl_irq_completion); + + ret = request_irq(irq, handler, IRQF_TRIGGER_FALLING, + "i2c_gpio_fault_injector_scl_irq", priv); + if (ret) + goto output; + + wait_for_completion_interruptible(&priv->scl_irq_completion); + + free_irq(irq, priv); + output: + ret = gpiod_direction_output(priv->scl, 1) ?: ret; + unlock: + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + return ret; +} + +static irqreturn_t lose_arbitration_irq(int irq, void *dev_id) +{ + struct i2c_gpio_private_data *priv = dev_id; + + setsda(&priv->bit_data, 0); + udelay(priv->scl_irq_data); + setsda(&priv->bit_data, 1); + + complete(&priv->scl_irq_completion); + + return IRQ_HANDLED; +} + +static int fops_lose_arbitration_set(void *data, u64 duration) +{ + struct i2c_gpio_private_data *priv = data; + + if (duration > 100 * 1000) + return -EINVAL; + + priv->scl_irq_data = duration; + /* + * Interrupt on falling SCL. This ensures that the master under test has + * really started the transfer. Interrupt on falling SDA did only + * exercise 'bus busy' detection on some HW but not 'arbitration lost'. + * Note that the interrupt latency may cause the first bits to be + * transmitted correctly. + */ + return i2c_gpio_fi_act_on_scl_irq(priv, lose_arbitration_irq); +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_lose_arbitration, NULL, fops_lose_arbitration_set, "%llu\n"); + static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); @@ -181,10 +250,15 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) if (!priv->debug_dir) return; + init_completion(&priv->scl_irq_completion); + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, priv, &fops_incomplete_addr_phase); debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, priv, &fops_incomplete_write_byte); + if (priv->bit_data.getscl) + debugfs_create_file_unsafe("lose_arbitration", 0200, priv->debug_dir, + priv, &fops_lose_arbitration); debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); } -- cgit v1.2.3 From bb6bdd51c838e8d046a84502f12619de4fd58d69 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Feb 2019 17:39:46 +0100 Subject: i2c: gpio: fault-injector: add 'inject_panic' injector Add a fault injector simulating a Kernel panic happening after starting a transfer. Read the docs for its usage. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/gpio-fault-injection | 26 ++++++++++++++++++++++++++ drivers/i2c/busses/i2c-gpio.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection index 1f1bb96a64bd..c87f416d53dd 100644 --- a/Documentation/i2c/gpio-fault-injection +++ b/Documentation/i2c/gpio-fault-injection @@ -108,3 +108,29 @@ idle bus is: # echo 200 > lose_arbitration & # i2cget -y 0x3f + +Panic during transfer +===================== + +This fault injector will create a Kernel panic once the master under test +started a transfer. This usually means that the state machine of the bus master +driver will be ungracefully interrupted and the bus may end up in an unusual +state. Use this to check if your shutdown/reboot/boot code can handle this +scenario. + +"inject_panic" +-------------- + +This file is write only and you need to write the delay between the detected +start of a transmission and the induced Kernel panic (in µs, maximum is 100ms). +The calling process will then sleep and wait for the next bus clock. The +process is interruptible, though. + +Start of a transfer is detected by waiting for SCL going down by the master +under test. A good starting point for using this fault injector is: + +# echo 0 > inject_panic & +# i2cget -y + +Note that there doesn't need to be a device listening to the address you are +using. Results may vary depending on that, though. diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 76e43783f50f..bba5c4627de3 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -231,6 +231,32 @@ static int fops_lose_arbitration_set(void *data, u64 duration) } DEFINE_DEBUGFS_ATTRIBUTE(fops_lose_arbitration, NULL, fops_lose_arbitration_set, "%llu\n"); +static irqreturn_t inject_panic_irq(int irq, void *dev_id) +{ + struct i2c_gpio_private_data *priv = dev_id; + + udelay(priv->scl_irq_data); + panic("I2C fault injector induced panic"); + + return IRQ_HANDLED; +} + +static int fops_inject_panic_set(void *data, u64 duration) +{ + struct i2c_gpio_private_data *priv = data; + + if (duration > 100 * 1000) + return -EINVAL; + + priv->scl_irq_data = duration; + /* + * Interrupt on falling SCL. This ensures that the master under test has + * really started the transfer. + */ + return i2c_gpio_fi_act_on_scl_irq(priv, inject_panic_irq); +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_inject_panic, NULL, fops_inject_panic_set, "%llu\n"); + static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); @@ -256,9 +282,12 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) priv, &fops_incomplete_addr_phase); debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, priv, &fops_incomplete_write_byte); - if (priv->bit_data.getscl) + if (priv->bit_data.getscl) { + debugfs_create_file_unsafe("inject_panic", 0200, priv->debug_dir, + priv, &fops_inject_panic); debugfs_create_file_unsafe("lose_arbitration", 0200, priv->debug_dir, priv, &fops_lose_arbitration); + } debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); } -- cgit v1.2.3