Commit b62a9c20 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v3.19-4' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO fixes from Linus Walleij:
 "Here is a set of fixes that mainly appeared when Johan Hovold started
  exercising the removal path of the GPIO library, dealing with
  hotplugging of GPIO controllers. Details from tag:

  A slew of fixes dealing with some irritating bugs (non-regressions)
  that have been around forever in the GPIO subsystem, most of them also
  tagged for stable:

   - A large slew of fixes from Johan Hovold who is finally testing and
     reviewing the removal path of the GPIO drivers.

   - Fix of_get_named_gpiod_flags() so it works as expected.

   - Fix an IRQ handling bug in the crystalcove driver"

* tag 'gpio-v3.19-4' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpiolib: of: Correct error handling in of_get_named_gpiod_flags
  gpio: sysfs: fix gpio attribute-creation race
  gpio: sysfs: fix gpio device-attribute leak
  gpio: sysfs: fix gpio-chip device-attribute leak
  gpio: unregister gpiochip device before removing it
  gpio: fix sleep-while-atomic in gpiochip_remove
  gpio: fix memory leak and sleep-while-atomic
  gpio: clean up gpiochip_add error handling
  gpio: fix gpio-chip list corruption
  gpio: fix memory and reference leaks in gpiochip_add error path
  gpio: crystalcove: use handle_nested_irq
parents 66893885 7b8792bb
...@@ -272,7 +272,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data) ...@@ -272,7 +272,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) { for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
if (pending & BIT(gpio)) { if (pending & BIT(gpio)) {
virq = irq_find_mapping(cg->chip.irqdomain, gpio); virq = irq_find_mapping(cg->chip.irqdomain, gpio);
generic_handle_irq(virq); handle_nested_irq(virq);
} }
} }
......
...@@ -45,8 +45,14 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) ...@@ -45,8 +45,14 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
return false; return false;
ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
if (ret < 0) if (ret < 0) {
return false; /* We've found the gpio chip, but the translation failed.
* Return true to stop looking and return the translation
* error via out_gpio
*/
gg_data->out_gpio = ERR_PTR(ret);
return true;
}
gg_data->out_gpio = gpiochip_get_desc(gc, ret); gg_data->out_gpio = gpiochip_get_desc(gc, ret);
return true; return true;
......
...@@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev, ...@@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev,
return status; return status;
} }
static const DEVICE_ATTR(value, 0644, static DEVICE_ATTR(value, 0644,
gpio_value_show, gpio_value_store); gpio_value_show, gpio_value_store);
static irqreturn_t gpio_sysfs_irq(int irq, void *priv) static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
...@@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev, ...@@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev,
return status ? : size; return status ? : size;
} }
static const DEVICE_ATTR(active_low, 0644, static DEVICE_ATTR(active_low, 0644,
gpio_active_low_show, gpio_active_low_store); gpio_active_low_show, gpio_active_low_store);
static const struct attribute *gpio_attrs[] = { static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct gpio_desc *desc = dev_get_drvdata(dev);
umode_t mode = attr->mode;
bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
if (attr == &dev_attr_direction.attr) {
if (!show_direction)
mode = 0;
} else if (attr == &dev_attr_edge.attr) {
if (gpiod_to_irq(desc) < 0)
mode = 0;
if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
mode = 0;
}
return mode;
}
static struct attribute *gpio_attrs[] = {
&dev_attr_direction.attr,
&dev_attr_edge.attr,
&dev_attr_value.attr, &dev_attr_value.attr,
&dev_attr_active_low.attr, &dev_attr_active_low.attr,
NULL, NULL,
}; };
static const struct attribute_group gpio_attr_group = { static const struct attribute_group gpio_group = {
.attrs = (struct attribute **) gpio_attrs, .attrs = gpio_attrs,
.is_visible = gpio_is_visible,
};
static const struct attribute_group *gpio_groups[] = {
&gpio_group,
NULL
}; };
/* /*
...@@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev, ...@@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev,
} }
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
static const struct attribute *gpiochip_attrs[] = { static struct attribute *gpiochip_attrs[] = {
&dev_attr_base.attr, &dev_attr_base.attr,
&dev_attr_label.attr, &dev_attr_label.attr,
&dev_attr_ngpio.attr, &dev_attr_ngpio.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(gpiochip);
static const struct attribute_group gpiochip_attr_group = {
.attrs = (struct attribute **) gpiochip_attrs,
};
/* /*
* /sys/class/gpio/export ... write-only * /sys/class/gpio/export ... write-only
...@@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
goto fail_unlock; goto fail_unlock;
} }
if (!desc->chip->direction_input || !desc->chip->direction_output) if (desc->chip->direction_input && desc->chip->direction_output &&
direction_may_change = false; direction_may_change) {
set_bit(FLAG_SYSFS_DIR, &desc->flags);
}
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
if (desc->chip->names && desc->chip->names[offset]) if (desc->chip->names && desc->chip->names[offset])
ioname = desc->chip->names[offset]; ioname = desc->chip->names[offset];
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), dev = device_create_with_groups(&gpio_class, desc->chip->dev,
desc, ioname ? ioname : "gpio%u", MKDEV(0, 0), desc, gpio_groups,
desc_to_gpio(desc)); ioname ? ioname : "gpio%u",
desc_to_gpio(desc));
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
status = PTR_ERR(dev); status = PTR_ERR(dev);
goto fail_unlock; goto fail_unlock;
} }
status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
if (status)
goto fail_unregister_device;
if (direction_may_change) {
status = device_create_file(dev, &dev_attr_direction);
if (status)
goto fail_unregister_device;
}
if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
!test_bit(FLAG_IS_OUT, &desc->flags))) {
status = device_create_file(dev, &dev_attr_edge);
if (status)
goto fail_unregister_device;
}
set_bit(FLAG_EXPORT, &desc->flags); set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
return 0; return 0;
fail_unregister_device:
device_unregister(dev);
fail_unlock: fail_unlock:
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
gpiod_dbg(desc, "%s: status %d\n", __func__, status); gpiod_dbg(desc, "%s: status %d\n", __func__, status);
...@@ -718,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc) ...@@ -718,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc)
dev = class_find_device(&gpio_class, NULL, desc, match_export); dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev) { if (dev) {
gpio_setup_irq(desc, dev, 0); gpio_setup_irq(desc, dev, 0);
clear_bit(FLAG_SYSFS_DIR, &desc->flags);
clear_bit(FLAG_EXPORT, &desc->flags); clear_bit(FLAG_EXPORT, &desc->flags);
} else } else
status = -ENODEV; status = -ENODEV;
...@@ -750,13 +762,13 @@ int gpiochip_export(struct gpio_chip *chip) ...@@ -750,13 +762,13 @@ int gpiochip_export(struct gpio_chip *chip)
/* use chip->base for the ID; it's already known to be unique */ /* use chip->base for the ID; it's already known to be unique */
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
"gpiochip%d", chip->base); chip, gpiochip_groups,
if (!IS_ERR(dev)) { "gpiochip%d", chip->base);
status = sysfs_create_group(&dev->kobj, if (IS_ERR(dev))
&gpiochip_attr_group);
} else
status = PTR_ERR(dev); status = PTR_ERR(dev);
else
status = 0;
chip->exported = (status == 0); chip->exported = (status == 0);
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
......
...@@ -248,29 +248,30 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -248,29 +248,30 @@ int gpiochip_add(struct gpio_chip *chip)
base = gpiochip_find_base(chip->ngpio); base = gpiochip_find_base(chip->ngpio);
if (base < 0) { if (base < 0) {
status = base; status = base;
goto unlock; spin_unlock_irqrestore(&gpio_lock, flags);
goto err_free_descs;
} }
chip->base = base; chip->base = base;
} }
status = gpiochip_add_to_list(chip); status = gpiochip_add_to_list(chip);
if (status) {
spin_unlock_irqrestore(&gpio_lock, flags);
goto err_free_descs;
}
if (status == 0) { for (id = 0; id < chip->ngpio; id++) {
for (id = 0; id < chip->ngpio; id++) { struct gpio_desc *desc = &descs[id];
struct gpio_desc *desc = &descs[id];
desc->chip = chip; desc->chip = chip;
/* REVISIT: most hardware initializes GPIOs as /* REVISIT: most hardware initializes GPIOs as inputs (often
* inputs (often with pullups enabled) so power * with pullups enabled) so power usage is minimized. Linux
* usage is minimized. Linux code should set the * code should set the gpio direction first thing; but until
* gpio direction first thing; but until it does, * it does, and in case chip->get_direction is not set, we may
* and in case chip->get_direction is not set, * expose the wrong direction in sysfs.
* we may expose the wrong direction in sysfs. */
*/ desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
desc->flags = !chip->direction_input
? (1 << FLAG_IS_OUT)
: 0;
}
} }
chip->desc = descs; chip->desc = descs;
...@@ -284,12 +285,9 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -284,12 +285,9 @@ int gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add(chip); of_gpiochip_add(chip);
acpi_gpiochip_add(chip); acpi_gpiochip_add(chip);
if (status)
goto fail;
status = gpiochip_export(chip); status = gpiochip_export(chip);
if (status) if (status)
goto fail; goto err_remove_chip;
pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
chip->base, chip->base + chip->ngpio - 1, chip->base, chip->base + chip->ngpio - 1,
...@@ -297,11 +295,15 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -297,11 +295,15 @@ int gpiochip_add(struct gpio_chip *chip)
return 0; return 0;
unlock: err_remove_chip:
acpi_gpiochip_remove(chip);
of_gpiochip_remove(chip);
spin_lock_irqsave(&gpio_lock, flags);
list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
fail:
kfree(descs);
chip->desc = NULL; chip->desc = NULL;
err_free_descs:
kfree(descs);
/* failures here can mean systems won't boot... */ /* failures here can mean systems won't boot... */
pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
...@@ -325,14 +327,15 @@ void gpiochip_remove(struct gpio_chip *chip) ...@@ -325,14 +327,15 @@ void gpiochip_remove(struct gpio_chip *chip)
unsigned long flags; unsigned long flags;
unsigned id; unsigned id;
acpi_gpiochip_remove(chip); gpiochip_unexport(chip);
spin_lock_irqsave(&gpio_lock, flags);
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(chip);
acpi_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip); gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
spin_lock_irqsave(&gpio_lock, flags);
for (id = 0; id < chip->ngpio; id++) { for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
...@@ -342,7 +345,6 @@ void gpiochip_remove(struct gpio_chip *chip) ...@@ -342,7 +345,6 @@ void gpiochip_remove(struct gpio_chip *chip)
list_del(&chip->list); list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
gpiochip_unexport(chip);
kfree(chip->desc); kfree(chip->desc);
chip->desc = NULL; chip->desc = NULL;
......
...@@ -77,6 +77,7 @@ struct gpio_desc { ...@@ -77,6 +77,7 @@ struct gpio_desc {
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
#define ID_SHIFT 16 /* add new flags before this one */ #define ID_SHIFT 16 /* add new flags before this one */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment