mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
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:
commit
b4f5144d37
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user