On Sat, Sep 08, 2018 at 08:08:13PM +0200, Hans de Goede wrote: > lpss_iosf_enter_d3_state() checks if all hw-blocks using the DMA > controllers are in d3 before powering down the DMA controllers. > > But on devices, where the I2C bus connected to the PMIC is shared by > the PUNIT, the controller for that bus will never reach d3 since it has > an effectively empty _PS3 method. Instead it appears to automatically > power-down during S0i3 and we never see it as being in d3. > > This causes the DMA controllers to never be powered-down on these devices, > causing them to never reach S0i3. This commit uses the ACPI _SEM method > to detect if an I2C bus is shared with the PUNIT and if it is, it removes > it from the mask of devices which lpss_iosf_enter_d3_state() checks for. > > This fixes these devices never reaching any S0ix states. > > Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> > --- > drivers/acpi/acpi_lpss.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c > index 969bf8d515c0..83875305b1d4 100644 > --- a/drivers/acpi/acpi_lpss.c > +++ b/drivers/acpi/acpi_lpss.c > @@ -99,6 +99,9 @@ struct lpss_private_data { > u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; > }; > > +/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */ > +static u32 pmc_atom_d3_mask = 0xfe000ffe; > + > /* LPSS run time quirks */ > static unsigned int lpss_quirks; > > @@ -175,6 +178,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) > > static void byt_i2c_setup(struct lpss_private_data *pdata) > { > + const char *uid_str = acpi_device_uid(pdata->adev); > + acpi_handle handle = pdata->adev->handle; > + unsigned long long shared_host = 0; > + acpi_status status; > + long uid = 0; Hmm, I wonder if uid=0 is actually valid? IIRC they start from 0 and go forward from that. > + > + /* Expected to always be true, but better safe then sorry */ > + if (uid_str) > + uid = simple_strtol(uid_str, NULL, 10); > + > + /* Detect I2C bus shared with PUNIT and ignore its d3 status */ > + status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); > + if (ACPI_SUCCESS(status) && shared_host && uid) > + pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));