gpio updates for v6.19-rc1
- fix spinlock op type after conversion to lock guards - fix a memory leak in error path in gpio-regmap - Kconfig fixes in GPIO drivers - add a GPIO ACPI quirk for Dell Precision 7780 - set of fixes for shared GPIO management -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmk7a9QACgkQBZ0uy/82 hMMPORAAnZ1I1j6NqZTnx+6Jhe2BeIqodXHT+iJLvyvYvfDguMqC4v+JZ4eOStY3 UN17bQv/UeKkfGHpD8oe5cJZkF+088Dy2+f7nBpsBw7sj+nty+PZy6QcGEqnmdGb lhmjBv8UQ6jNz7Kg7pzY/Rp4p2Vt1m6Br/7XwwlOAoVEreofGfrtQIZg72xtT6rg yacr37z7PAxlHDh9/oMWU0/p+E/deN7Vi/UVaiP+C23PmcyyUtTC+gML7BMMM6cr +3mrX4ae3HOfWLZinxF4Ike2J7TacqPmub7imHRFCgz+RQ8ZCmlucHs5L8C+jPXf HRykRIssTC3n9WvXrmlatv5xhJI5wUisMFjgxFeb57UZZG0oJPHEaN/SNU4KvPQS ea2mdiA1hb6EjaU7fAgdLvy6KNmxOew3PjSuMB0cnEpsVUqaKwTIRLuUYzXLBkwE M0K3zJoZLvzlfy1uaKw6PR2TAjF7BhZGT/KnQOvICVopFEW7EhYTYtprfVNnkt8D U2chdPLFCBVrKdkg5hV9UAH9r7TTe2eG3BjX2TazWnOZLpPSelYGrKzoWorQOS83 3B78tn7Tx62NXYXlkTbwGvVs6cUQC+JGdaEoLmKK7LhAW1u/g2DO10JQJLgZePwi czfUdKE29wfQy/piwn9+O+pbe15Iqbx54DmIZ80EgZOOLVya9TA= =oxk1 -----END PGP SIGNATURE----- Merge tag 'gpio-fixes-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: - fix spinlock op type after conversion to lock guards - fix a memory leak in error path in gpio-regmap - Kconfig fixes in GPIO drivers - add a GPIO ACPI quirk for Dell Precision 7780 - set of fixes for shared GPIO management * tag 'gpio-fixes-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: gpio: shared: make locking more fine-grained gpio: shared: fix auxiliary device cleanup order gpio: shared: check if a reference is populated before cleaning its resources gpio: shared: fix NULL-pointer dereference in teardown path gpio: shared: ignore disabled nodes when traversing the device-tree gpiolib: acpi: Add quirk for Dell Precision 7780 gpio: tb10x: fix OF_GPIO dependency gpio: qixis: select CONFIG_REGMAP_MMIO gpio: regmap: Fix memleak in error path in gpio_regmap_register() gpio: mmio: fix bad guard conversionpull/1354/merge
commit
a6bb419c1c
|
|
@ -737,7 +737,6 @@ config GPIO_TB10X
|
||||||
depends on ARC_PLAT_TB10X || COMPILE_TEST
|
depends on ARC_PLAT_TB10X || COMPILE_TEST
|
||||||
select GPIO_GENERIC
|
select GPIO_GENERIC
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select OF_GPIO
|
|
||||||
|
|
||||||
config GPIO_TEGRA
|
config GPIO_TEGRA
|
||||||
tristate "NVIDIA Tegra GPIO support"
|
tristate "NVIDIA Tegra GPIO support"
|
||||||
|
|
@ -1568,6 +1567,7 @@ config GPIO_QIXIS_FPGA
|
||||||
tristate "NXP QIXIS FPGA GPIO support"
|
tristate "NXP QIXIS FPGA GPIO support"
|
||||||
depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST
|
depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST
|
||||||
select GPIO_REGMAP
|
select GPIO_REGMAP
|
||||||
|
select REGMAP_MMIO
|
||||||
help
|
help
|
||||||
This enables support for the GPIOs found in the QIXIS FPGA which is
|
This enables support for the GPIOs found in the QIXIS FPGA which is
|
||||||
integrated on some NXP Layerscape boards such as LX2160ARDB and
|
integrated on some NXP Layerscape boards such as LX2160ARDB and
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||||
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
||||||
|
|
||||||
guard(raw_spinlock)(&chip->lock);
|
guard(raw_spinlock_irqsave)(&chip->lock);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
chip->sdata |= mask;
|
chip->sdata |= mask;
|
||||||
|
|
@ -262,7 +262,7 @@ static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||||
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
||||||
|
|
||||||
guard(raw_spinlock)(&chip->lock);
|
guard(raw_spinlock_irqsave)(&chip->lock);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
chip->sdata |= mask;
|
chip->sdata |= mask;
|
||||||
|
|
@ -302,7 +302,7 @@ static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc,
|
||||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||||
unsigned long set_mask, clear_mask;
|
unsigned long set_mask, clear_mask;
|
||||||
|
|
||||||
guard(raw_spinlock)(&chip->lock);
|
guard(raw_spinlock_irqsave)(&chip->lock);
|
||||||
|
|
||||||
gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||||
|
|
||||||
|
|
@ -391,7 +391,7 @@ static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||||
{
|
{
|
||||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||||
|
|
||||||
scoped_guard(raw_spinlock, &chip->lock) {
|
scoped_guard(raw_spinlock_irqsave, &chip->lock) {
|
||||||
chip->sdir &= ~gpio_mmio_line2mask(gc, gpio);
|
chip->sdir &= ~gpio_mmio_line2mask(gc, gpio);
|
||||||
|
|
||||||
if (chip->reg_dir_in)
|
if (chip->reg_dir_in)
|
||||||
|
|
@ -431,7 +431,7 @@ static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
{
|
{
|
||||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||||
|
|
||||||
guard(raw_spinlock)(&chip->lock);
|
guard(raw_spinlock_irqsave)(&chip->lock);
|
||||||
|
|
||||||
chip->sdir |= gpio_mmio_line2mask(gc, gpio);
|
chip->sdir |= gpio_mmio_line2mask(gc, gpio);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
||||||
config->regmap_irq_line, config->regmap_irq_flags,
|
config->regmap_irq_line, config->regmap_irq_flags,
|
||||||
0, config->regmap_irq_chip, &gpio->irq_chip_data);
|
0, config->regmap_irq_chip, &gpio->irq_chip_data);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_bitmap;
|
goto err_remove_gpiochip;
|
||||||
|
|
||||||
irq_domain = regmap_irq_get_domain(gpio->irq_chip_data);
|
irq_domain = regmap_irq_get_domain(gpio->irq_chip_data);
|
||||||
} else
|
} else
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,28 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
||||||
.ignore_wake = "ASCP1A00:00@8",
|
.ignore_wake = "ASCP1A00:00@8",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Spurious wakeups, likely from touchpad controller
|
||||||
|
* Dell Precision 7780
|
||||||
|
* Found in BIOS 1.24.1
|
||||||
|
*
|
||||||
|
* Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01
|
||||||
|
* ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ),
|
||||||
|
* released on 11 Jul 2024
|
||||||
|
*
|
||||||
|
* https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/
|
||||||
|
*/
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"),
|
||||||
|
},
|
||||||
|
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||||
|
.ignore_wake = "VEN_0488:00@355",
|
||||||
|
},
|
||||||
|
},
|
||||||
{} /* Terminating entry */
|
{} /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ struct gpio_shared_ref {
|
||||||
enum gpiod_flags flags;
|
enum gpiod_flags flags;
|
||||||
char *con_id;
|
char *con_id;
|
||||||
int dev_id;
|
int dev_id;
|
||||||
|
/* Protects the auxiliary device struct and the lookup table. */
|
||||||
|
struct mutex lock;
|
||||||
struct auxiliary_device adev;
|
struct auxiliary_device adev;
|
||||||
struct gpiod_lookup_table *lookup;
|
struct gpiod_lookup_table *lookup;
|
||||||
};
|
};
|
||||||
|
|
@ -49,6 +51,7 @@ struct gpio_shared_entry {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
/* Index in the property value array. */
|
/* Index in the property value array. */
|
||||||
size_t index;
|
size_t index;
|
||||||
|
/* Synchronizes the modification of shared_desc. */
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct gpio_shared_desc *shared_desc;
|
struct gpio_shared_desc *shared_desc;
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
|
|
@ -56,7 +59,6 @@ struct gpio_shared_entry {
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(gpio_shared_list);
|
static LIST_HEAD(gpio_shared_list);
|
||||||
static DEFINE_MUTEX(gpio_shared_lock);
|
|
||||||
static DEFINE_IDA(gpio_shared_ida);
|
static DEFINE_IDA(gpio_shared_ida);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_OF)
|
#if IS_ENABLED(CONFIG_OF)
|
||||||
|
|
@ -77,6 +79,10 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node,
|
||||||
/* Handle all special nodes that we should ignore. */
|
/* Handle all special nodes that we should ignore. */
|
||||||
static bool gpio_shared_of_node_ignore(struct device_node *node)
|
static bool gpio_shared_of_node_ignore(struct device_node *node)
|
||||||
{
|
{
|
||||||
|
/* Ignore disabled devices. */
|
||||||
|
if (!of_device_is_available(node))
|
||||||
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* __symbols__ is a special, internal node and should not be considered
|
* __symbols__ is a special, internal node and should not be considered
|
||||||
* when scanning for shared GPIOs.
|
* when scanning for shared GPIOs.
|
||||||
|
|
@ -183,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
|
||||||
|
|
||||||
ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
|
ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
|
||||||
ref->flags = args.args[1];
|
ref->flags = args.args[1];
|
||||||
|
mutex_init(&ref->lock);
|
||||||
|
|
||||||
if (strends(prop->name, "gpios"))
|
if (strends(prop->name, "gpios"))
|
||||||
suffix = "-gpios";
|
suffix = "-gpios";
|
||||||
|
|
@ -254,7 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev,
|
||||||
struct auxiliary_device *adev = &ref->adev;
|
struct auxiliary_device *adev = &ref->adev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lockdep_assert_held(&gpio_shared_lock);
|
guard(mutex)(&ref->lock);
|
||||||
|
|
||||||
memset(adev, 0, sizeof(*adev));
|
memset(adev, 0, sizeof(*adev));
|
||||||
|
|
||||||
|
|
@ -369,14 +376,14 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
||||||
if (!lookup)
|
if (!lookup)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
guard(mutex)(&gpio_shared_lock);
|
|
||||||
|
|
||||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||||
list_for_each_entry(ref, &entry->refs, list) {
|
list_for_each_entry(ref, &entry->refs, list) {
|
||||||
if (!device_match_fwnode(consumer, ref->fwnode) &&
|
if (!device_match_fwnode(consumer, ref->fwnode) &&
|
||||||
!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
|
!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
guard(mutex)(&ref->lock);
|
||||||
|
|
||||||
/* We've already done that on a previous request. */
|
/* We've already done that on a previous request. */
|
||||||
if (ref->lookup)
|
if (ref->lookup)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -395,7 +402,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
||||||
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0,
|
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0,
|
||||||
ref->con_id, lflags);
|
ref->con_id, lflags);
|
||||||
|
|
||||||
gpiod_add_lookup_table(no_free_ptr(lookup));
|
ref->lookup = no_free_ptr(lookup);
|
||||||
|
gpiod_add_lookup_table(ref->lookup);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -408,10 +416,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
||||||
|
|
||||||
static void gpio_shared_remove_adev(struct auxiliary_device *adev)
|
static void gpio_shared_remove_adev(struct auxiliary_device *adev)
|
||||||
{
|
{
|
||||||
lockdep_assert_held(&gpio_shared_lock);
|
|
||||||
|
|
||||||
auxiliary_device_uninit(adev);
|
|
||||||
auxiliary_device_delete(adev);
|
auxiliary_device_delete(adev);
|
||||||
|
auxiliary_device_uninit(adev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_device_setup_shared(struct gpio_device *gdev)
|
int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||||
|
|
@ -421,8 +427,6 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||||
unsigned long *flags;
|
unsigned long *flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
guard(mutex)(&gpio_shared_lock);
|
|
||||||
|
|
||||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||||
list_for_each_entry(ref, &entry->refs, list) {
|
list_for_each_entry(ref, &entry->refs, list) {
|
||||||
if (gdev->dev.parent == &ref->adev.dev) {
|
if (gdev->dev.parent == &ref->adev.dev) {
|
||||||
|
|
@ -479,19 +483,32 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
|
||||||
struct gpio_shared_entry *entry;
|
struct gpio_shared_entry *entry;
|
||||||
struct gpio_shared_ref *ref;
|
struct gpio_shared_ref *ref;
|
||||||
|
|
||||||
guard(mutex)(&gpio_shared_lock);
|
|
||||||
|
|
||||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some reason if we call synchronize_srcu() in GPIO core,
|
||||||
|
* descent here and take this mutex and then recursively call
|
||||||
|
* synchronize_srcu() again from gpiochip_remove() (which is
|
||||||
|
* totally fine) called after gpio_shared_remove_adev(),
|
||||||
|
* lockdep prints a false positive deadlock splat. Disable
|
||||||
|
* lockdep here.
|
||||||
|
*/
|
||||||
|
lockdep_off();
|
||||||
list_for_each_entry(ref, &entry->refs, list) {
|
list_for_each_entry(ref, &entry->refs, list) {
|
||||||
|
guard(mutex)(&ref->lock);
|
||||||
|
|
||||||
|
if (ref->lookup) {
|
||||||
gpiod_remove_lookup_table(ref->lookup);
|
gpiod_remove_lookup_table(ref->lookup);
|
||||||
kfree(ref->lookup->table[0].key);
|
kfree(ref->lookup->table[0].key);
|
||||||
kfree(ref->lookup);
|
kfree(ref->lookup);
|
||||||
ref->lookup = NULL;
|
ref->lookup = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
gpio_shared_remove_adev(&ref->adev);
|
gpio_shared_remove_adev(&ref->adev);
|
||||||
}
|
}
|
||||||
|
lockdep_on();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -515,8 +532,6 @@ static void gpiod_shared_put(void *data)
|
||||||
{
|
{
|
||||||
struct gpio_shared_entry *entry = data;
|
struct gpio_shared_entry *entry = data;
|
||||||
|
|
||||||
lockdep_assert_not_held(&gpio_shared_lock);
|
|
||||||
|
|
||||||
kref_put(&entry->ref, gpio_shared_release);
|
kref_put(&entry->ref, gpio_shared_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,8 +569,6 @@ struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
|
||||||
struct gpio_shared_entry *entry;
|
struct gpio_shared_entry *entry;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lockdep_assert_not_held(&gpio_shared_lock);
|
|
||||||
|
|
||||||
entry = dev_get_platdata(dev);
|
entry = dev_get_platdata(dev);
|
||||||
if (WARN_ON(!entry))
|
if (WARN_ON(!entry))
|
||||||
/* Programmer bug */
|
/* Programmer bug */
|
||||||
|
|
@ -590,6 +603,7 @@ EXPORT_SYMBOL_GPL(devm_gpiod_shared_get);
|
||||||
static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
|
static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
|
||||||
{
|
{
|
||||||
list_del(&ref->list);
|
list_del(&ref->list);
|
||||||
|
mutex_destroy(&ref->lock);
|
||||||
kfree(ref->con_id);
|
kfree(ref->con_id);
|
||||||
ida_free(&gpio_shared_ida, ref->dev_id);
|
ida_free(&gpio_shared_ida, ref->dev_id);
|
||||||
fwnode_handle_put(ref->fwnode);
|
fwnode_handle_put(ref->fwnode);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue