diff mbox series

i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus

Message ID 20180823084553.65461-1-mika.westerberg@linux.intel.com
State Superseded
Headers show
Series i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus | expand

Commit Message

Mika Westerberg Aug. 23, 2018, 8:45 a.m. UTC
Commit 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict
with PCI BAR") made it possible for AML code to access SMBus I/O ports
by installing custom SystemIO OpRegion handler and blocking i80i driver
access upon first AML read/write to this OpRegion.

However, while ThinkPad T560 does have SystemIO OpRegion declared under
the SMBus device, it does not access any of the SMBus registers:

    Device (SMBU)
    {
        ...

        OperationRegion (SMBP, PCI_Config, 0x50, 0x04)
        Field (SMBP, DWordAcc, NoLock, Preserve)
        {
            ,   5,
            TCOB,   11,
            Offset (0x04)
        }

        Name (TCBV, 0x00)
        Method (TCBS, 0, NotSerialized)
        {
            If ((TCBV == 0x00))
            {
            TCBV = (\_SB.PCI0.SMBU.TCOB << 0x05)
            }

            Return (TCBV) /* \_SB_.PCI0.SMBU.TCBV */
        }

        OperationRegion (TCBA, SystemIO, TCBS (), 0x10)
        Field (TCBA, ByteAcc, NoLock, Preserve)
        {
            Offset (0x04),
            ,   9,
            CPSC,   1
        }
    }

Problem with the current approach is that it blocks all I/O port access
and because this system has touchpad connected to the SMBus controller
after first AML access (happens during suspend/resume cycle) the
touchpad fails to work anymore.

Fix this so that we allow ACPI AML I/O port access if it does not touch
the region reserved for the SMBus.

Fixes: 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=200737
Reported-by: Yussuf Khalil <dev@pp3345.net>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/i2c/busses/i2c-i801.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Comments

Wolfram Sang Aug. 24, 2018, 1:08 p.m. UTC | #1
On Thu, Aug 23, 2018 at 11:45:53AM +0300, Mika Westerberg wrote:
> Commit 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict
> with PCI BAR") made it possible for AML code to access SMBus I/O ports
> by installing custom SystemIO OpRegion handler and blocking i80i driver
> access upon first AML read/write to this OpRegion.
> 
> However, while ThinkPad T560 does have SystemIO OpRegion declared under
> the SMBus device, it does not access any of the SMBus registers:
> 
>     Device (SMBU)
>     {
>         ...
> 
>         OperationRegion (SMBP, PCI_Config, 0x50, 0x04)
>         Field (SMBP, DWordAcc, NoLock, Preserve)
>         {
>             ,   5,
>             TCOB,   11,
>             Offset (0x04)
>         }
> 
>         Name (TCBV, 0x00)
>         Method (TCBS, 0, NotSerialized)
>         {
>             If ((TCBV == 0x00))
>             {
>             TCBV = (\_SB.PCI0.SMBU.TCOB << 0x05)
>             }
> 
>             Return (TCBV) /* \_SB_.PCI0.SMBU.TCBV */
>         }
> 
>         OperationRegion (TCBA, SystemIO, TCBS (), 0x10)
>         Field (TCBA, ByteAcc, NoLock, Preserve)
>         {
>             Offset (0x04),
>             ,   9,
>             CPSC,   1
>         }
>     }
> 
> Problem with the current approach is that it blocks all I/O port access
> and because this system has touchpad connected to the SMBus controller
> after first AML access (happens during suspend/resume cycle) the
> touchpad fails to work anymore.
> 
> Fix this so that we allow ACPI AML I/O port access if it does not touch
> the region reserved for the SMBus.
> 
> Fixes: 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR")
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=200737
> Reported-by: Yussuf Khalil <dev@pp3345.net>
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

I'll give Jean a few more days to comment but will apply it for -rc2
latest.
Jean Delvare Aug. 29, 2018, 11:52 a.m. UTC | #2
Hi Wolfram, Mika,

On Fri, 24 Aug 2018 15:08:01 +0200, Wolfram Sang wrote:
> On Thu, Aug 23, 2018 at 11:45:53AM +0300, Mika Westerberg wrote:
> > Commit 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict
> > with PCI BAR") made it possible for AML code to access SMBus I/O ports
> > by installing custom SystemIO OpRegion handler and blocking i80i driver
> > access upon first AML read/write to this OpRegion.
> > 
> > However, while ThinkPad T560 does have SystemIO OpRegion declared under
> > the SMBus device, it does not access any of the SMBus registers:
> > 
> >     Device (SMBU)
> >     {
> >         ...
> > 
> >         OperationRegion (SMBP, PCI_Config, 0x50, 0x04)
> >         Field (SMBP, DWordAcc, NoLock, Preserve)
> >         {
> >             ,   5,
> >             TCOB,   11,
> >             Offset (0x04)
> >         }
> > 
> >         Name (TCBV, 0x00)
> >         Method (TCBS, 0, NotSerialized)
> >         {
> >             If ((TCBV == 0x00))
> >             {
> >             TCBV = (\_SB.PCI0.SMBU.TCOB << 0x05)
> >             }
> > 
> >             Return (TCBV) /* \_SB_.PCI0.SMBU.TCBV */
> >         }
> > 
> >         OperationRegion (TCBA, SystemIO, TCBS (), 0x10)
> >         Field (TCBA, ByteAcc, NoLock, Preserve)
> >         {
> >             Offset (0x04),
> >             ,   9,
> >             CPSC,   1
> >         }
> >     }
> > 
> > Problem with the current approach is that it blocks all I/O port access
> > and because this system has touchpad connected to the SMBus controller
> > after first AML access (happens during suspend/resume cycle) the
> > touchpad fails to work anymore.
> > 
> > Fix this so that we allow ACPI AML I/O port access if it does not touch
> > the region reserved for the SMBus.
> > 
> > Fixes: 7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR")
> > Link: https://bugzilla.kernel.org/show_bug.cgi?id=200737
> > Reported-by: Yussuf Khalil <dev@pp3345.net>
> > Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>  
> 
> I'll give Jean a few more days to comment but will apply it for -rc2
> latest.

Sorry for the late answer, I'm back from vacation.

On the principle, the change looks sane to me. However I suspect
there's an off-by-one bug:

> +{
> +	return address >= priv->smba &&
> +	       address < pci_resource_end(priv->pci_dev, SMBBAR);
> +}

Shouldn't the second test use "<=" instead of "<"?

Other than that, looks good to me, so you can add my:

Reviewed-by: Jean Delvare <jdelvare@suse.de>

Thanks,
Mika Westerberg Aug. 29, 2018, 1:04 p.m. UTC | #3
On Wed, Aug 29, 2018 at 01:52:43PM +0200, Jean Delvare wrote:
> Sorry for the late answer, I'm back from vacation.
> 
> On the principle, the change looks sane to me. However I suspect
> there's an off-by-one bug:
> 
> > +{
> > +	return address >= priv->smba &&
> > +	       address < pci_resource_end(priv->pci_dev, SMBBAR);
> > +}
> 
> Shouldn't the second test use "<=" instead of "<"?

You are right. I'll fix that and send v2.

> Other than that, looks good to me, so you can add my:
> 
> Reviewed-by: Jean Delvare <jdelvare@suse.de>

Thanks!
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index aa726607645e..c75872a93d03 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1412,6 +1412,13 @@  static void i801_add_tco(struct i801_priv *priv)
 }
 
 #ifdef CONFIG_ACPI
+static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
+				      acpi_physical_address address)
+{
+	return address >= priv->smba &&
+	       address < pci_resource_end(priv->pci_dev, SMBBAR);
+}
+
 static acpi_status
 i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
 		     u64 *value, void *handler_context, void *region_context)
@@ -1427,7 +1434,7 @@  i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
 	 */
 	mutex_lock(&priv->acpi_lock);
 
-	if (!priv->acpi_reserved) {
+	if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
 		priv->acpi_reserved = true;
 
 		dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");