Re: [RFC PATCH] i2c: gpio: fault-injector: add 'lose_arbitration' injector

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jan 21, 2019 at 03:28:39PM +0100, Wolfram Sang wrote:
> Here is a fault injector simulating 'arbitration lost' from multi-master
> setups. Read the docs for its usage.
> 
> Signed-off-by: Wolfram Sang <wsa+renesas@xxxxxxxxxxxxxxxxxxxx>

Geert, if you would have time for a high-level review, I'd appreciate
this very much!

> ---
> 
> This is the most reliable result I came up with so far for simulating lost
> arbitration (after playing a lot with falling SDA as trigger first, but SCL
> seems the way to go). Works fine with the i2c-sh_mobile driver on a Renesas
> Lager board. I am not super-happy with the interrupt latency causing some bits
> to be non-disturbed, but for now, I don't see a way around it except for
> busy-polling which I think is too excessive. RFC for now because someone still
> might have a better idea :)
> 
> Needs my previous fault-injector cleanup patches, a branch for consuming is here:
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git renesas/iic-arbitration-lost
> 
> Now let's see how to fix the sh_mobile driver...
> 
>  Documentation/i2c/gpio-fault-injection | 26 +++++++++++++++
>  drivers/i2c/busses/i2c-gpio.c          | 61 ++++++++++++++++++++++++++++++++++
>  2 files changed, 87 insertions(+)
> 
> diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection
> index 1a44e3edc0c4..b6f36ffe55e1 100644
> --- a/Documentation/i2c/gpio-fault-injection
> +++ b/Documentation/i2c/gpio-fault-injection
> @@ -83,3 +83,29 @@ 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 tests 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 number of desired lost
> +arbitrations in a row. The calling process will then sleep and interfere with
> +transfers from the master under test when they appear until that number is
> +reached. 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 script for using this fault injector:
> +
> +# echo 1 > lose_arbitration &
> +# i2cget -y <bus_to_test> 0x3f
> +
> diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
> index ca04fa25a141..c630172b4787 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 <linux/completion.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/i2c-algo-bit.h>
>  #include <linux/i2c.h>
>  #include <linux/init.h>
> +#include <linux/interrupt.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/platform_data/i2c-gpio.h>
> @@ -27,6 +29,7 @@ struct i2c_gpio_private_data {
>  	struct i2c_gpio_platform_data pdata;
>  #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
>  	struct dentry *debug_dir;
> +	struct completion irq_happened;
>  #endif
>  };
>  
> @@ -162,6 +165,59 @@ 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 irqreturn_t lose_arbitration_irq(int irq, void *dev_id)
> +{
> +	struct i2c_gpio_private_data *priv = dev_id;
> +
> +	setsda(&priv->bit_data, 0);
> +	udelay(200);
> +	setsda(&priv->bit_data, 1);
> +
> +	complete(&priv->irq_happened);
> +	return IRQ_HANDLED;
> +}
> +
> +static int fops_lose_arbitration_set(void *data, u64 num_faults)
> +{
> +	struct i2c_gpio_private_data *priv = data;
> +	int irq = gpiod_to_irq(priv->scl);
> +	int ret, i;
> +
> +	i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
> +
> +	/*
> +	 * 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.
> +	 */
> +	ret = gpiod_direction_input(priv->scl);
> +	if (ret)
> +		goto unlock;
> +
> +	ret = request_irq(irq, lose_arbitration_irq, IRQF_TRIGGER_FALLING,
> +			  "i2c-gpio-fi", priv);
> +	if (ret)
> +		goto output;
> +
> +	for (i = 0; i < num_faults; i++) {
> +		ret = wait_for_completion_interruptible(&priv->irq_happened);
> +		if (ret)
> +			break;
> +		reinit_completion(&priv->irq_happened);
> +	}
> +
> +	free_irq(irq, priv);
> + output:
> +	ret = gpiod_direction_output(priv->scl, 1);
> + unlock:
> +	i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
> +
> +	return ret;
> +}
> +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 +237,15 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
>  	if (!priv->debug_dir)
>  		return;
>  
> +	init_completion(&priv->irq_happened);
> +
>  	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);
>  }
> -- 
> 2.11.0
> 

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux