Message ID | 1534168664-13034-1-git-send-email-michael.hennerich@analog.com |
---|---|
State | New |
Headers | show |
Series | drivers: gpio: gpio-adp5588: Fix sleep-in-atomic-context bug | expand |
On Mon, Aug 13, 2018 at 3:53 PM <michael.hennerich@analog.com> wrote: > From: Michael Hennerich <michael.hennerich@analog.com> > > This fixes: > [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug > in adp5588_gpio_write() > [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug > in adp5588_gpio_direction_input() > > Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com> > Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Thanks Michael, excellent and prompt fix. Patch applied for fixes (v4.19-rcs). Should we even tag it for stable? Yours, Linus Walleij
On 29.08.2018 10:55, Linus Walleij wrote: > On Mon, Aug 13, 2018 at 3:53 PM <michael.hennerich@analog.com> wrote: > >> From: Michael Hennerich <michael.hennerich@analog.com> >> >> This fixes: >> [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug >> in adp5588_gpio_write() >> [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug >> in adp5588_gpio_direction_input() >> >> Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com> >> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> > > Thanks Michael, excellent and prompt fix. Patch applied > for fixes (v4.19-rcs). > > Should we even tag it for stable? Thanks, Linus - Yes that would make sense.
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index e717f8d..202d367 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -41,6 +41,8 @@ struct adp5588_gpio { uint8_t int_en[3]; uint8_t irq_mask[3]; uint8_t irq_stat[3]; + uint8_t int_input_en[3]; + uint8_t int_lvl_cached[3]; }; static int adp5588_gpio_read(struct i2c_client *client, u8 reg) @@ -173,12 +175,28 @@ static void adp5588_irq_bus_sync_unlock(struct irq_data *d) struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); int i; - for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) + for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { + if (dev->int_input_en[i]) { + mutex_lock(&dev->lock); + dev->dir[i] &= ~dev->int_input_en[i]; + dev->int_input_en[i] = 0; + adp5588_gpio_write(dev->client, GPIO_DIR1 + i, + dev->dir[i]); + mutex_unlock(&dev->lock); + } + + if (dev->int_lvl_cached[i] != dev->int_lvl[i]) { + dev->int_lvl_cached[i] = dev->int_lvl[i]; + adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i, + dev->int_lvl[i]); + } + if (dev->int_en[i] ^ dev->irq_mask[i]) { dev->int_en[i] = dev->irq_mask[i]; adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, dev->int_en[i]); } + } mutex_unlock(&dev->irq_lock); } @@ -221,9 +239,7 @@ static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) else return -EINVAL; - adp5588_gpio_direction_input(&dev->gpio_chip, gpio); - adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank, - dev->int_lvl[bank]); + dev->int_input_en[bank] |= bit; return 0; }