mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
gpio: ml-ioh: use raw_spinlock_t for the register lock
ioh_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid. ioh_irq_enable() and ioh_irq_disable() take the same lock from the .irq_enable/.irq_disable callbacks, which are likewise invoked with desc->lock held. Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, and those critical sections only perform short sequences of MMIO register accesses (ioread32()/iowrite32()); the .irq_set_type callback additionally emits a dev_warn() on an unsupported type. None of these are sleepable operations, so keeping this register lock non-sleeping is appropriate for the irqchip callbacks and does not change the GPIO-side locking contract. This is the same fix as commita02b8950d6("gpio: pch: use raw_spinlock_t for the register lock"); this driver shares the same structure as gpio-pch. Fixes:54be566317("gpio-ml-ioh: Support interrupt function") Cc: stable@vger.kernel.org Reviewed-by: Linus Walleij <linusw@kernel.org> Link: https://patch.msgid.link/20260731032747.2987292-1-junjie.cao@intel.com Signed-off-by: Junjie Cao <junjie.cao@intel.com>
This commit is contained in:
parent
c6e94cd60b
commit
600411ea1f
|
|
@ -84,7 +84,7 @@ struct ioh_gpio {
|
|||
u32 gpio_use_sel;
|
||||
int ch;
|
||||
int irq_base;
|
||||
spinlock_t spinlock;
|
||||
raw_spinlock_t spinlock;
|
||||
};
|
||||
|
||||
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
|
||||
|
|
@ -95,7 +95,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
|
|||
struct ioh_gpio *chip = gpiochip_get_data(gpio);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
|
||||
if (val)
|
||||
reg_val |= BIT(nr);
|
||||
|
|
@ -103,7 +103,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
|
|||
reg_val &= ~BIT(nr);
|
||||
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
pm &= BIT(num_ports[chip->ch]) - 1;
|
||||
pm |= BIT(nr);
|
||||
|
|
@ -136,7 +136,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
reg_val &= ~BIT(nr);
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -147,12 +147,12 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
u32 pm;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
pm &= BIT(num_ports[chip->ch]) - 1;
|
||||
pm &= ~BIT(nr);
|
||||
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
|
|||
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
|
||||
__func__, irq, type, ch, im_pos, type);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
|
|
@ -296,7 +296,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
|
|||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
|
||||
end:
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -326,11 +326,11 @@ static void ioh_irq_disable(struct irq_data *d)
|
|||
unsigned long flags;
|
||||
u32 ien;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
ien &= ~BIT(d->irq - chip->irq_base);
|
||||
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static void ioh_irq_enable(struct irq_data *d)
|
||||
|
|
@ -340,11 +340,11 @@ static void ioh_irq_enable(struct irq_data *d)
|
|||
unsigned long flags;
|
||||
u32 ien;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
ien |= BIT(d->irq - chip->irq_base);
|
||||
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
|
||||
|
|
@ -440,7 +440,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
|||
chip->base = base;
|
||||
chip->reg = chip->base;
|
||||
chip->ch = i;
|
||||
spin_lock_init(&chip->spinlock);
|
||||
raw_spin_lock_init(&chip->spinlock);
|
||||
ioh_gpio_setup(chip, num_ports[i]);
|
||||
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
|
||||
if (ret) {
|
||||
|
|
@ -484,9 +484,9 @@ static int ioh_gpio_suspend(struct device *dev)
|
|||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
ioh_gpio_save_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -496,11 +496,11 @@ static int ioh_gpio_resume(struct device *dev)
|
|||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&chip->spinlock, flags);
|
||||
iowrite32(0x01, &chip->reg->srst);
|
||||
iowrite32(0x00, &chip->reg->srst);
|
||||
ioh_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user