Message ID | 20220919095504.v4.7.I8af4282adc72eb9f247adcd03676a43893a020a6@changeid (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | acpi: i2c: Use SharedAndWake and ExclusiveAndWake to enable wake irq | expand |
On Mon, Sep 19, 2022 at 09:59:09AM -0600, Raul E Rangel wrote: > Device tree already has a mechanism to pass the wake_irq. It does this > by looking for the wakeup-source property and setting the > I2C_CLIENT_WAKE flag. This CL adds the ACPI equivalent. It uses the > ACPI interrupt wake flag to determine if the interrupt can be used to > wake the system. Previously the i2c drivers had to make assumptions and > blindly enable the wake IRQ. This can cause spurious wake events. e.g., > If there is a device with an Active Low interrupt and the device gets > powered off while suspending, the interrupt line will go low since it's > no longer powered and wakes the system. For this reason we should > respect the board designers wishes and honor the wake bit defined on the > interrupt. ... > + if (irq_ctx.irq == -ENOENT) > + irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); I just realized, that there is an inconsistency on how we fill the wake_capable parameter. In some cases we check for IRQ for an error condition (IRQ not found) and in some the wake_capable still be filled. Here the best approach I believe is to add if (irq_ctx.irq < 0) return irq_ctx.irq; I.o.w. we apply the rule "do not fill the output parameters when it's known to be an error condition". > + if (wake_capable) > + *wake_capable = irq_ctx.wake_capable; > + return irq_ctx.irq;
On Tue, Sep 20, 2022 at 6:32 AM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote: > > On Mon, Sep 19, 2022 at 09:59:09AM -0600, Raul E Rangel wrote: > > Device tree already has a mechanism to pass the wake_irq. It does this > > by looking for the wakeup-source property and setting the > > I2C_CLIENT_WAKE flag. This CL adds the ACPI equivalent. It uses the > > ACPI interrupt wake flag to determine if the interrupt can be used to > > wake the system. Previously the i2c drivers had to make assumptions and > > blindly enable the wake IRQ. This can cause spurious wake events. e.g., > > If there is a device with an Active Low interrupt and the device gets > > powered off while suspending, the interrupt line will go low since it's > > no longer powered and wakes the system. For this reason we should > > respect the board designers wishes and honor the wake bit defined on the > > interrupt. > > ... > > > + if (irq_ctx.irq == -ENOENT) > > + irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); > > I just realized, that there is an inconsistency on how we fill the wake_capable > parameter. In some cases we check for IRQ for an error condition (IRQ not found) > and in some the wake_capable still be filled. > > Here the best approach I believe is to add > > if (irq_ctx.irq < 0) > return irq_ctx.irq; > > I.o.w. we apply the rule "do not fill the output parameters when it's known > to be an error condition". > > > + if (wake_capable) > > + *wake_capable = irq_ctx.wake_capable; > > > + return irq_ctx.irq; > I applied the following: diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index ba64e505183595..1618f5619d5ed9 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -220,7 +220,7 @@ int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) if (irq_ctx.irq == -ENOENT) irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); - if (wake_capable) + if (irq_ctx.irq > 0 && wake_capable) *wake_capable = irq_ctx.wake_capable; return irq_ctx.irq; Thanks!
On Wed, Sep 21, 2022 at 09:18:34AM -0600, Raul Rangel wrote: > On Tue, Sep 20, 2022 at 6:32 AM Andy Shevchenko > <andriy.shevchenko@linux.intel.com> wrote: > > On Mon, Sep 19, 2022 at 09:59:09AM -0600, Raul E Rangel wrote: ... > > > + if (irq_ctx.irq == -ENOENT) > > > + irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); > > > > I just realized, that there is an inconsistency on how we fill the wake_capable > > parameter. In some cases we check for IRQ for an error condition (IRQ not found) > > and in some the wake_capable still be filled. > > > > Here the best approach I believe is to add > > > > if (irq_ctx.irq < 0) > > return irq_ctx.irq; > > > > I.o.w. we apply the rule "do not fill the output parameters when it's known > > to be an error condition". > > > > > + if (wake_capable) > > > + *wake_capable = irq_ctx.wake_capable; > > > > > + return irq_ctx.irq; > > > > I applied the following: > diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c > index ba64e505183595..1618f5619d5ed9 100644 > --- a/drivers/i2c/i2c-core-acpi.c > +++ b/drivers/i2c/i2c-core-acpi.c > @@ -220,7 +220,7 @@ int i2c_acpi_get_irq(struct i2c_client *client, > bool *wake_capable) > if (irq_ctx.irq == -ENOENT) > irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, > &irq_ctx.wake_capable); > > - if (wake_capable) > + if (irq_ctx.irq > 0 && wake_capable) > *wake_capable = irq_ctx.wake_capable; > > return irq_ctx.irq; While it's working solution it is not so flexible since basically any addition of a new code will require if (irq > 0), that's why I'm in favour of my proposal rather than yours approach.
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index c762a879c4cc6b..ba64e505183595 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -137,6 +137,11 @@ static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = { {} }; +struct i2c_acpi_irq_context { + int irq; + bool wake_capable; +}; + static int i2c_acpi_do_lookup(struct acpi_device *adev, struct i2c_acpi_lookup *lookup) { @@ -168,13 +173,19 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, return 0; } -static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) +static int i2c_acpi_add_irq_resource(struct acpi_resource *ares, void *data) { - int *irq = data; + struct i2c_acpi_irq_context *irq_ctx = data; struct resource r; - if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) - *irq = i2c_dev_irq_from_resources(&r, 1); + if (irq_ctx->irq > 0) + return 1; + + if (!acpi_dev_resource_interrupt(ares, 0, &r)) + return 1; + + irq_ctx->irq = i2c_dev_irq_from_resources(&r, 1); + irq_ctx->wake_capable = r.flags & IORESOURCE_IRQ_WAKECAPABLE; return 1; /* No need to add resource to the list */ } @@ -182,31 +193,37 @@ static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) /** * i2c_acpi_get_irq - get device IRQ number from ACPI * @client: Pointer to the I2C client device + * @wake_capable: Set to true if the IRQ is wake capable * * Find the IRQ number used by a specific client device. * * Return: The IRQ number or an error code. */ -int i2c_acpi_get_irq(struct i2c_client *client) +int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); struct list_head resource_list; - int irq = -ENOENT; + struct i2c_acpi_irq_context irq_ctx = { + .irq = -ENOENT, + }; int ret; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_add_resource, &irq); + i2c_acpi_add_irq_resource, &irq_ctx); if (ret < 0) return ret; acpi_dev_free_resource_list(&resource_list); - if (irq == -ENOENT) - irq = acpi_dev_gpio_irq_get(adev, 0); + if (irq_ctx.irq == -ENOENT) + irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); + + if (wake_capable) + *wake_capable = irq_ctx.wake_capable; - return irq; + return irq_ctx.irq; } static int i2c_acpi_get_info(struct acpi_device *adev, diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 91007558bcb260..fc4b85fb90b1b7 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -487,7 +487,11 @@ static int i2c_device_probe(struct device *dev) if (irq == -EINVAL || irq == -ENODATA) irq = of_irq_get(dev->of_node, 0); } else if (ACPI_COMPANION(dev)) { - irq = i2c_acpi_get_irq(client); + bool wake_capable; + + irq = i2c_acpi_get_irq(client, &wake_capable); + if (irq > 0 && wake_capable) + client->flags |= I2C_CLIENT_WAKE; } if (irq == -EPROBE_DEFER) { status = irq; diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 87e2c914f1c57b..1247e6e6e97517 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -61,11 +61,11 @@ static inline int __i2c_check_suspended(struct i2c_adapter *adap) #ifdef CONFIG_ACPI void i2c_acpi_register_devices(struct i2c_adapter *adap); -int i2c_acpi_get_irq(struct i2c_client *client); +int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable); #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } -static inline int i2c_acpi_get_irq(struct i2c_client *client) +static inline int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) { return 0; }