gpio fixes for v7.2

- use raw_spinlock_t in gpio-ml-ioh to avoid locking context issues
 - fix a race condition in gpio-ml-ioh by sharing the register locks
   across channels
 - fix a use-after-free bug in unbind path in gpio-sloppy-logic-analyzer
 -----BEGIN PGP SIGNATURE-----
 
 iQIyBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmp9fVYACgkQBZ0uy/82
 hMM2bg/4lIfsWQF7GiSs7cgOa/J0DNIo1PZuf2h9cSJYuR10gMBszCVrBrM/qFT0
 05MbJGQcaPSW8Zq8QwR+BoaZ20d64iXuipWOkqg53lN5whU28Tm2z2/YFdC/UHAO
 niXbIstc4d26mm1hc6AwjGV4p6lgzTR2W+IcbkImUAAUQDJX+YE6iasclL2EViz5
 fufRQ2VaF159AD5zeNjMxoYRwGlZGAU+qeXwbYDhkt0CBOhAZ0eUhnyQi8zYcnpN
 OsKmqRplq/tm6jdUjGBoHOFWoXnp4QdukvyEHP/M56WfxyYPOcc9ABCMK45MqpvX
 b+9eAy0LjQg+38D6geQIP53ZzVKUrbg4NnLItGV8ad6WR9e0t8+xm0c01hKQ9fdw
 n5R12KMr2OdYjSjq1MAuBbUSRrwBjwdgZuxcE5fo3w0aLYfaVAX9LoFkpuv8WP/U
 hSUuO9cMxLRnb2ckDVCoazI4lBNuBG2E7si3eodPkFfU6UoiAN8+TQFW3O1AeOnz
 LDFMnRb3EADMC4LFdnYSUiQRRm0mHnjhLj1BNZ4Rjgd3ZEgfsHv7ez2JNtIyJs5F
 r7H4XBMH1cthyaIkdXWPoKPyE2AJiEg9g0KyvNTHqp2+ORDtz7o3m11AsXDAjGZm
 y22YVJUPKUwqVzAabOuoJY872fPQ1N9Zkf9aLrGWNL9MvI+bAw==
 =Mmpx
 -----END PGP SIGNATURE-----

Merge tag 'gpio-fixes-for-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:

 - use raw_spinlock_t in gpio-ml-ioh to avoid locking context issues

 - fix a race condition in gpio-ml-ioh by sharing the register locks
   across channels

 - fix a use-after-free bug in unbind path in gpio-sloppy-logic-analyzer

* tag 'gpio-fixes-for-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: sloppy-logic-analyzer: fix use-after-free via debugfs trigger on unbind
  gpio: ml-ioh: share the register lock across channels
  gpio: ml-ioh: use raw_spinlock_t for the register lock
  gpiolib: Check gc->get_direction() before calling gpiod_get_direction()
This commit is contained in:
Linus Torvalds 2026-08-13 07:16:58 -07:00
commit b4f5144d37
3 changed files with 41 additions and 35 deletions

View File

@ -73,7 +73,7 @@ struct ioh_gpio_reg_data {
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
* @ch: Indicate GPIO channel
* @irq_base: Save base of IRQ number for interrupt
* @spinlock: Used for register access protection
* @spinlock: Shared register access lock
*/
struct ioh_gpio {
void __iomem *base;
@ -84,7 +84,12 @@ struct ioh_gpio {
u32 gpio_use_sel;
int ch;
int irq_base;
spinlock_t spinlock;
raw_spinlock_t *spinlock;
};
struct ioh_gpio_device {
raw_spinlock_t spinlock;
struct ioh_gpio chip[8];
};
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@ -95,7 +100,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 +108,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 +128,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 +141,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 +152,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 +261,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 +301,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 +331,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 +345,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)
@ -407,8 +412,8 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
int ret;
int i, j;
struct ioh_gpio *chip;
struct ioh_gpio_device *priv;
void __iomem *base;
void *chip_save;
int irq_base;
ret = pcim_enable_device(pdev);
@ -429,18 +434,18 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return -ENOMEM;
}
chip_save = devm_kcalloc(dev, 8, sizeof(*chip), GFP_KERNEL);
if (chip_save == NULL) {
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
}
chip = chip_save;
raw_spin_lock_init(&priv->spinlock);
chip = priv->chip;
for (i = 0; i < 8; i++, chip++) {
chip->dev = dev;
chip->base = base;
chip->reg = chip->base;
chip->ch = i;
spin_lock_init(&chip->spinlock);
chip->spinlock = &priv->spinlock;
ioh_gpio_setup(chip, num_ports[i]);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
@ -449,7 +454,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
}
}
chip = chip_save;
chip = priv->chip;
for (j = 0; j < 8; j++, chip++) {
irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE,
num_ports[j], NUMA_NO_NODE);
@ -466,7 +471,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}
chip = chip_save;
chip = priv->chip;
ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret != 0) {
@ -474,33 +479,33 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}
pci_set_drvdata(pdev, chip);
pci_set_drvdata(pdev, priv);
return 0;
}
static int ioh_gpio_suspend(struct device *dev)
{
struct ioh_gpio *chip = dev_get_drvdata(dev);
struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
ioh_gpio_save_reg_conf(chip);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_lock_irqsave(&priv->spinlock, flags);
ioh_gpio_save_reg_conf(priv->chip);
raw_spin_unlock_irqrestore(&priv->spinlock, flags);
return 0;
}
static int ioh_gpio_resume(struct device *dev)
{
struct ioh_gpio *chip = dev_get_drvdata(dev);
struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;
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_lock_irqsave(&priv->spinlock, flags);
iowrite32(0x01, &priv->chip->reg->srst);
iowrite32(0x00, &priv->chip->reg->srst);
ioh_gpio_restore_reg_conf(priv->chip);
raw_spin_unlock_irqrestore(&priv->spinlock, flags);
return 0;
}

View File

@ -300,7 +300,7 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);
debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);
debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);
debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
debugfs_create_file("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
return 0;
}

View File

@ -5420,7 +5420,8 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *gc)
flags = READ_ONCE(desc->flags);
is_irq = test_bit(GPIOD_FLAG_USED_AS_IRQ, &flags);
if (is_irq || test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
gpiod_get_direction(desc);
if (gc->get_direction)
gpiod_get_direction(desc);
is_out = test_bit(GPIOD_FLAG_IS_OUT, &flags);
value = gpio_chip_get_value(gc, desc);
active_low = test_bit(GPIOD_FLAG_ACTIVE_LOW, &flags);