Re: i2c i801 Host Notify breaks HP G3 850 booting while plugged in

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

 



On Mon, 9 Apr 2018 18:20:14 +0200, Jean Delvare wrote:
> What is pretty interesting in your previous post, and I failed to
> notice before, is that bit 0 of register 0xefb1 was still set after the
> module was unloaded. The original register value is supposed to be
> restored in i801_disable_host_notify(), and the dump you just provided
> indicates that Host Notify is not enabled by the BIOS on your machine,
> so the value of this bit should have been saved, and then restored, to
> 0. This is not happening.
> 
> I think it would be worth instrumenting the i2c-i801 driver to check
> what exactly is going on. Something like:
> 
> ---
>  drivers/i2c/busses/i2c-i801.c |    9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> --- linux-4.16.orig/drivers/i2c/busses/i2c-i801.c	2018-04-09 14:54:05.179509697 +0200
> +++ linux-4.16/drivers/i2c/busses/i2c-i801.c	2018-04-09 18:09:28.843867439 +0200
> @@ -967,6 +967,8 @@ static void i801_enable_host_notify(stru
>  		return;
>  
>  	priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
> +	dev_info(&adapter->dev, "Original SMBSLVCMD value: %02X\n",
> +		 (unsigned int)priv->original_slvcmd);
>  
>  	if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd))
>  		outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd,
> @@ -974,6 +976,9 @@ static void i801_enable_host_notify(stru
>  
>  	/* clear Host Notify bit to allow a new notification */
>  	outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
> +
> +	dev_info(&adapter->dev, "SMBSLVCMD value after initialization: %02X\n",
> +		 (unsigned int)inb_p(SMBSLVCMD(priv)));
>  }
>  
>  static void i801_disable_host_notify(struct i801_priv *priv)
> @@ -981,7 +986,11 @@ static void i801_disable_host_notify(str
>  	if (!(priv->features & FEATURE_HOST_NOTIFY))
>  		return;
>  
> +	dev_info(&priv->adapter.dev, "SMBSLVCMD value at removal time: %02X\n",
> +		 (unsigned int)inb_p(SMBSLVCMD(priv)));
>  	outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
> +	dev_info(&priv->adapter.dev, "SMBSLVCMD reset to: %02X\n",
> +		 (unsigned int)inb_p(SMBSLVCMD(priv)));
>  }
>  
>  static const struct i2c_algorithm smbus_algorithm = {
> 
> Could you try this with the Host Notify feature enabled, and report the
> values that are logged?

OK, I think I nailed it. I applied the patch above, and it turns out
that i801_enable_host_notify() is being called *twice* when I load
i2c-i801: once from i801_probe(), as expected, and once from
i801_resume(), which I did not expect. My kernel config has
CONFIG_PM_TEST_SUSPEND=n, so I'm not sure what this happens.

Anyway, looking at the code, it is clear that saving
priv->original_slvcmd in i801_enable_host_notify() is wrong. This
function is called at resume time and we have no idea what will be the
value of the SMBSLVCMD register at that point: it could be the hardware
default value, or a value set by the BIOS, or our own value from
suspend time.

So the register value needs to be saved once and only once, at probe
time. I'll send a patch in a minute.

-- 
Jean Delvare
SUSE L3 Support



[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