mirror of
https://github.com/torvalds/linux.git
synced 2026-09-27 11:02:03 +02:00
gpio fixes for v7.4-rc5
- fix a regression introduced by moving GPIO hog handling into GPIOLIB core where of_node_name was used if line name property was missing on DT systems - fix kernel stack leak to user-space in error path in GPIO character device code - fix runtime PM leaks in gpio-xilinx and gpio-arizona - fix several register programming bugs in gpio-tps65219 - fix interrupt storm on resume in gpio-mvebu -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmq2KYwACgkQBZ0uy/82 hMOkFhAAjIaH6nUhhUBykRyIbBVAbxYFWrps/qLw9Wlg1wDteUwwMWpdHWivsi2M Ch0zCR1/op812cu47dTsnNteHuK9oGoL0IHXGweylNJVU7IXTiUx6sUu+kLlT2wK /yIH6Zk78rULodV/80S9aNbFNNHOu7Pu/AEAPPJjGIKK6UVxT7o2o04jG1xORVbr X11hLjzKe1RpVKo3fhBFglzW1T4YVpulorsgkMNabTG4hbf5pArtkaQGPHVvH3Hk LNpTFJ3Jmoczo4UgsKAaUso2LoC19hoIUMRBVoOwscTLlPoIE6MTH0bLj+U9npId TUhGpVYIvfy4B6V2+FU+9YnWTkDE7efmnmm0l+GnNp7FmDTxTO0aVJoouPNEeUgu Zu1CJxaKYTWuTm5mdk2Tgw5G+3YtzcGS6iW3dCFvshyYSdHHkvPQ6ys2blJJyeEd 2MRoZQZdSzMDmCfw5Y+RxF1jp1BRjIID2NH1p/cxUokFvMDgFJU+MFxdOo6ySnC/ +1EEeA7Gak4StJUDa2Y4+uI0PMokWAEXs3ixlQUmgIpgGVtBIzI17psj4RDumdGD 6HIG/31Pedg3LtUkkzC8P6vfdREzzquWUPBr9F7dApur4/MMJZyeu3pUwFtx0AKs +T5qgUwwsoKxLmg2EAdg5pThzLVgqgtrSYuw8esqfG8tNRzoRgc= =Mp0f -----END PGP SIGNATURE----- Merge tag 'gpio-fixes-for-v7.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio fixes from Bartosz Golaszewski: - fix a regression introduced by moving GPIO hog handling into GPIOLIB core where of_node_name was used if line name property was missing on DT systems - fix kernel stack leak to user-space in error path in GPIO character device code - fix runtime PM leaks in gpio-xilinx and gpio-arizona - fix several register programming bugs in gpio-tps65219 - fix interrupt storm on resume in gpio-mvebu * tag 'gpio-fixes-for-v7.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: gpio: tps65219: Fix TPS65214 GPIO direction programming gpio: tps65219: Use the variant-specific direction callback gpio: tps65219: Fix GPIO input value reads gpio: zynq: fix runtime PM leak on request error path gpio: cdev: fix kernel stack leak to user-space in error path gpiolib: use of_node_name if line-name is missing gpio: mvebu: keep resume masks within the irqchip cache gpio: arizona: Fix runtime PM leak in arizona_gpio_direction_out()
This commit is contained in:
commit
80e466f0c8
|
|
@ -115,8 +115,12 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip,
|
|||
if (value)
|
||||
value = ARIZONA_GPN_LVL;
|
||||
|
||||
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
|
||||
ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
|
||||
ret = regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
|
||||
ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
|
||||
if (ret < 0 && (val & ARIZONA_GPN_DIR) && persistent)
|
||||
pm_runtime_put_autosuspend(chip->parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arizona_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
|
|
|
|||
|
|
@ -1034,6 +1034,8 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
static int mvebu_gpio_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
|
||||
u32 edge_cache = ~0U, level_cache = ~0U;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
|
||||
|
|
@ -1045,32 +1047,51 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
|
||||
mvchip->in_pol_reg);
|
||||
|
||||
/*
|
||||
* genirq skips mask_irq() for a line it already considers masked, so
|
||||
* unmasking one behind its back leaves an asserted level line that
|
||||
* nobody masks. Restore only bits the irqchip cache still has set.
|
||||
*
|
||||
* Snapshot the caches under the raw spinlock, but release it before
|
||||
* the regmap writes below: regmap_write() takes a sleepable lock on
|
||||
* PREEMPT_RT.
|
||||
*/
|
||||
if (mvchip->domain) {
|
||||
struct irq_chip_generic *gc;
|
||||
|
||||
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
|
||||
raw_spin_lock_irqsave(&gc->lock, flags);
|
||||
level_cache = gc->chip_types[0].mask_cache_priv;
|
||||
edge_cache = gc->chip_types[1].mask_cache_priv;
|
||||
raw_spin_unlock_irqrestore(&gc->lock, flags);
|
||||
}
|
||||
|
||||
switch (mvchip->soc_variant) {
|
||||
case MVEBU_GPIO_SOC_VARIANT_ORION:
|
||||
case MVEBU_GPIO_SOC_VARIANT_A8K:
|
||||
regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
|
||||
mvchip->edge_mask_regs[0]);
|
||||
mvchip->edge_mask_regs[0] & edge_cache);
|
||||
regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
|
||||
mvchip->level_mask_regs[0]);
|
||||
mvchip->level_mask_regs[0] & level_cache);
|
||||
break;
|
||||
case MVEBU_GPIO_SOC_VARIANT_MV78200:
|
||||
for (i = 0; i < 2; i++) {
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_EDGE_MASK_MV78200_OFF(i),
|
||||
mvchip->edge_mask_regs[i]);
|
||||
mvchip->edge_mask_regs[i] & edge_cache);
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_LEVEL_MASK_MV78200_OFF(i),
|
||||
mvchip->level_mask_regs[i]);
|
||||
mvchip->level_mask_regs[i] & level_cache);
|
||||
}
|
||||
break;
|
||||
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
|
||||
for (i = 0; i < 4; i++) {
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_EDGE_MASK_ARMADAXP_OFF(i),
|
||||
mvchip->edge_mask_regs[i]);
|
||||
mvchip->edge_mask_regs[i] & edge_cache);
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
|
||||
mvchip->level_mask_regs[i]);
|
||||
mvchip->level_mask_regs[i] & level_cache);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK));
|
||||
ret = !!(val & TPS65219_MFP_GPIO_STATUS_MASK);
|
||||
dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);
|
||||
|
||||
/*
|
||||
|
|
@ -87,7 +87,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
* status bit.
|
||||
*/
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
|
|
@ -158,8 +158,10 @@ static int tps65214_gpio_change_direction(struct gpio_chip *gc, unsigned int off
|
|||
if (ret)
|
||||
dev_err(dev, "GPIO%d configured as VSEL, not GPIO\n", offset);
|
||||
|
||||
val = direction == GPIO_LINE_DIRECTION_OUT ?
|
||||
TPS65214_GPIO0_DIR_MASK : 0;
|
||||
ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG,
|
||||
TPS65214_GPIO0_DIR_MASK, direction);
|
||||
TPS65214_GPIO0_DIR_MASK, val);
|
||||
if (ret)
|
||||
dev_err(dev, "Fail to change direction to %u for GPIO%d.\n", direction, offset);
|
||||
|
||||
|
|
@ -176,7 +178,7 @@ static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offs
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
|
||||
if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
|
||||
return 0;
|
||||
|
||||
return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_IN);
|
||||
|
|
@ -190,7 +192,7 @@ static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int off
|
|||
if (offset != TPS6521X_GPIO0_IDX)
|
||||
return 0;
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
return 0;
|
||||
|
||||
return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_OUT);
|
||||
|
|
|
|||
|
|
@ -798,15 +798,7 @@ static int zynq_gpio_runtime_resume(struct device *dev)
|
|||
|
||||
static int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(chip->parent);
|
||||
|
||||
/*
|
||||
* If the device is already active pm_runtime_get() will return 1 on
|
||||
* success, but gpio_request still needs to return 0.
|
||||
*/
|
||||
return ret < 0 ? ret : 0;
|
||||
return pm_runtime_resume_and_get(chip->parent);
|
||||
}
|
||||
|
||||
static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
|
|
|
|||
|
|
@ -2172,18 +2172,19 @@ static void gpio_v2_line_info_changed_to_v1(
|
|||
|
||||
#endif /* CONFIG_GPIO_CDEV_V1 */
|
||||
|
||||
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
||||
struct gpio_v2_line_info *info, bool atomic)
|
||||
static int gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
||||
struct gpio_v2_line_info *info, bool atomic)
|
||||
{
|
||||
u32 debounce_period_us;
|
||||
unsigned long dflags;
|
||||
const char *label;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
CLASS(gpio_chip_guard, guard)(desc);
|
||||
if (!guard.gc)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->offset = gpiod_hwgpio(desc);
|
||||
|
||||
if (desc->name)
|
||||
|
|
@ -2258,6 +2259,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
debounce_period_us;
|
||||
info->num_attrs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gpio_chardev_data {
|
||||
|
|
@ -2309,6 +2312,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
|
|||
struct gpio_desc *desc;
|
||||
struct gpioline_info lineinfo;
|
||||
struct gpio_v2_line_info lineinfo_v2;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
|
||||
return -EFAULT;
|
||||
|
|
@ -2326,7 +2330,10 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpio_desc_to_lineinfo(desc, &lineinfo_v2, false);
|
||||
ret = gpio_desc_to_lineinfo(desc, &lineinfo_v2, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
|
||||
|
||||
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
|
||||
|
|
@ -2344,6 +2351,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
|
|||
{
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_v2_line_info lineinfo;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
|
||||
return -EFAULT;
|
||||
|
|
@ -2363,7 +2371,10 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
|
|||
if (test_and_set_bit(lineinfo.offset, cdev->watched_lines))
|
||||
return -EBUSY;
|
||||
}
|
||||
gpio_desc_to_lineinfo(desc, &lineinfo, false);
|
||||
|
||||
ret = gpio_desc_to_lineinfo(desc, &lineinfo, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
|
||||
if (watch)
|
||||
|
|
@ -2489,6 +2500,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
|
|||
struct lineinfo_changed_ctx *ctx;
|
||||
struct gpio_desc *desc = data;
|
||||
struct file *fp;
|
||||
int ret;
|
||||
|
||||
if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines))
|
||||
return NOTIFY_DONE;
|
||||
|
|
@ -2519,7 +2531,13 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
|
|||
|
||||
ctx->chg.event_type = action;
|
||||
ctx->chg.timestamp_ns = ktime_get_ns();
|
||||
gpio_desc_to_lineinfo(desc, &ctx->chg.info, true);
|
||||
|
||||
ret = gpio_desc_to_lineinfo(desc, &ctx->chg.info, true);
|
||||
if (ret) {
|
||||
fput(fp);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/* Keep the GPIO device alive until we emit the event. */
|
||||
ctx->gdev = gpio_device_get(desc->gdev);
|
||||
ctx->cdev = cdev;
|
||||
|
|
|
|||
|
|
@ -1029,6 +1029,13 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode)
|
|||
ret = of_gpiochip_get_lflags(gc, &gpiospec, &lflags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If no line-name property is present, fall back to the OF
|
||||
* node name as in the previous implementation.
|
||||
*/
|
||||
if (!name)
|
||||
name = to_of_node(fwnode)->name;
|
||||
} else {
|
||||
/*
|
||||
* GPIO_ACTIVE_LOW is currently the only lookup flag
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user