Skip to content

Commit 9d64558

Browse files
committed
Merge tag 'gpio-fixes-for-v6.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio fixes from Bartosz Golaszewski: "There's one small fix for real HW - gpio-loongson. The rest concern two virtual testing drivers in which some issues were recently found and addressed: - fix resource leaks in error path in gpio-virtuser (and one consistent memory leak triggered on every device removal)) - fix the use-case of having multiple con_ids in a lookup table in gpio-virtuser which has never worked (despite being advertised) - don't allow rmdir() on configfs directories when they are in use in gpio-sim and gpio-virtuser - fix register offsets in gpio-loongson-64" * tag 'gpio-fixes-for-v6.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: gpio: loongson: Fix Loongson-2K2000 ACPI GPIO register offset gpio: sim: lock up configfs that an instantiated device depends on gpio: virtuser: lock up configfs that an instantiated device depends on gpio: virtuser: fix handling of multiple conn_ids in lookup table gpio: virtuser: fix missing lookup table cleanups
2 parents 2144da2 + e59f4c9 commit 9d64558

File tree

3 files changed

+113
-32
lines changed

3 files changed

+113
-32
lines changed

drivers/gpio/gpio-loongson-64bit.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,9 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = {
237237
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = {
238238
.label = "ls2k2000_gpio",
239239
.mode = BIT_CTRL_MODE,
240-
.conf_offset = 0x84,
241-
.in_offset = 0x88,
242-
.out_offset = 0x80,
240+
.conf_offset = 0x4,
241+
.in_offset = 0x8,
242+
.out_offset = 0x0,
243243
};
244244

245245
static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = {

drivers/gpio/gpio-sim.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,30 @@ static void gpio_sim_device_deactivate(struct gpio_sim_device *dev)
10271027
dev->pdev = NULL;
10281028
}
10291029

1030+
static void
1031+
gpio_sim_device_lockup_configfs(struct gpio_sim_device *dev, bool lock)
1032+
{
1033+
struct configfs_subsystem *subsys = dev->group.cg_subsys;
1034+
struct gpio_sim_bank *bank;
1035+
struct gpio_sim_line *line;
1036+
1037+
/*
1038+
* The device only needs to depend on leaf line entries. This is
1039+
* sufficient to lock up all the configfs entries that the
1040+
* instantiated, alive device depends on.
1041+
*/
1042+
list_for_each_entry(bank, &dev->bank_list, siblings) {
1043+
list_for_each_entry(line, &bank->line_list, siblings) {
1044+
if (lock)
1045+
WARN_ON(configfs_depend_item_unlocked(
1046+
subsys, &line->group.cg_item));
1047+
else
1048+
configfs_undepend_item_unlocked(
1049+
&line->group.cg_item);
1050+
}
1051+
}
1052+
}
1053+
10301054
static ssize_t
10311055
gpio_sim_device_config_live_store(struct config_item *item,
10321056
const char *page, size_t count)
@@ -1039,14 +1063,24 @@ gpio_sim_device_config_live_store(struct config_item *item,
10391063
if (ret)
10401064
return ret;
10411065

1042-
guard(mutex)(&dev->lock);
1066+
if (live)
1067+
gpio_sim_device_lockup_configfs(dev, true);
10431068

1044-
if (live == gpio_sim_device_is_live(dev))
1045-
ret = -EPERM;
1046-
else if (live)
1047-
ret = gpio_sim_device_activate(dev);
1048-
else
1049-
gpio_sim_device_deactivate(dev);
1069+
scoped_guard(mutex, &dev->lock) {
1070+
if (live == gpio_sim_device_is_live(dev))
1071+
ret = -EPERM;
1072+
else if (live)
1073+
ret = gpio_sim_device_activate(dev);
1074+
else
1075+
gpio_sim_device_deactivate(dev);
1076+
}
1077+
1078+
/*
1079+
* Undepend is required only if device disablement (live == 0)
1080+
* succeeds or if device enablement (live == 1) fails.
1081+
*/
1082+
if (live == !!ret)
1083+
gpio_sim_device_lockup_configfs(dev, false);
10501084

10511085
return ret ?: count;
10521086
}

drivers/gpio/gpio-virtuser.c

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,7 +1410,7 @@ gpio_virtuser_make_lookup_table(struct gpio_virtuser_device *dev)
14101410
size_t num_entries = gpio_virtuser_get_lookup_count(dev);
14111411
struct gpio_virtuser_lookup_entry *entry;
14121412
struct gpio_virtuser_lookup *lookup;
1413-
unsigned int i = 0;
1413+
unsigned int i = 0, idx;
14141414

14151415
lockdep_assert_held(&dev->lock);
14161416

@@ -1424,12 +1424,12 @@ gpio_virtuser_make_lookup_table(struct gpio_virtuser_device *dev)
14241424
return -ENOMEM;
14251425

14261426
list_for_each_entry(lookup, &dev->lookup_list, siblings) {
1427+
idx = 0;
14271428
list_for_each_entry(entry, &lookup->entry_list, siblings) {
1428-
table->table[i] =
1429+
table->table[i++] =
14291430
GPIO_LOOKUP_IDX(entry->key,
14301431
entry->offset < 0 ? U16_MAX : entry->offset,
1431-
lookup->con_id, i, entry->flags);
1432-
i++;
1432+
lookup->con_id, idx++, entry->flags);
14331433
}
14341434
}
14351435

@@ -1439,6 +1439,15 @@ gpio_virtuser_make_lookup_table(struct gpio_virtuser_device *dev)
14391439
return 0;
14401440
}
14411441

1442+
static void
1443+
gpio_virtuser_remove_lookup_table(struct gpio_virtuser_device *dev)
1444+
{
1445+
gpiod_remove_lookup_table(dev->lookup_table);
1446+
kfree(dev->lookup_table->dev_id);
1447+
kfree(dev->lookup_table);
1448+
dev->lookup_table = NULL;
1449+
}
1450+
14421451
static struct fwnode_handle *
14431452
gpio_virtuser_make_device_swnode(struct gpio_virtuser_device *dev)
14441453
{
@@ -1487,34 +1496,40 @@ gpio_virtuser_device_activate(struct gpio_virtuser_device *dev)
14871496
pdevinfo.fwnode = swnode;
14881497

14891498
ret = gpio_virtuser_make_lookup_table(dev);
1490-
if (ret) {
1491-
fwnode_remove_software_node(swnode);
1492-
return ret;
1493-
}
1499+
if (ret)
1500+
goto err_remove_swnode;
14941501

14951502
reinit_completion(&dev->probe_completion);
14961503
dev->driver_bound = false;
14971504
bus_register_notifier(&platform_bus_type, &dev->bus_notifier);
14981505

14991506
pdev = platform_device_register_full(&pdevinfo);
15001507
if (IS_ERR(pdev)) {
1508+
ret = PTR_ERR(pdev);
15011509
bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier);
1502-
fwnode_remove_software_node(swnode);
1503-
return PTR_ERR(pdev);
1510+
goto err_remove_lookup_table;
15041511
}
15051512

15061513
wait_for_completion(&dev->probe_completion);
15071514
bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier);
15081515

15091516
if (!dev->driver_bound) {
1510-
platform_device_unregister(pdev);
1511-
fwnode_remove_software_node(swnode);
1512-
return -ENXIO;
1517+
ret = -ENXIO;
1518+
goto err_unregister_pdev;
15131519
}
15141520

15151521
dev->pdev = pdev;
15161522

15171523
return 0;
1524+
1525+
err_unregister_pdev:
1526+
platform_device_unregister(pdev);
1527+
err_remove_lookup_table:
1528+
gpio_virtuser_remove_lookup_table(dev);
1529+
err_remove_swnode:
1530+
fwnode_remove_software_node(swnode);
1531+
1532+
return ret;
15181533
}
15191534

15201535
static void
@@ -1526,10 +1541,33 @@ gpio_virtuser_device_deactivate(struct gpio_virtuser_device *dev)
15261541

15271542
swnode = dev_fwnode(&dev->pdev->dev);
15281543
platform_device_unregister(dev->pdev);
1544+
gpio_virtuser_remove_lookup_table(dev);
15291545
fwnode_remove_software_node(swnode);
15301546
dev->pdev = NULL;
1531-
gpiod_remove_lookup_table(dev->lookup_table);
1532-
kfree(dev->lookup_table);
1547+
}
1548+
1549+
static void
1550+
gpio_virtuser_device_lockup_configfs(struct gpio_virtuser_device *dev, bool lock)
1551+
{
1552+
struct configfs_subsystem *subsys = dev->group.cg_subsys;
1553+
struct gpio_virtuser_lookup_entry *entry;
1554+
struct gpio_virtuser_lookup *lookup;
1555+
1556+
/*
1557+
* The device only needs to depend on leaf lookup entries. This is
1558+
* sufficient to lock up all the configfs entries that the
1559+
* instantiated, alive device depends on.
1560+
*/
1561+
list_for_each_entry(lookup, &dev->lookup_list, siblings) {
1562+
list_for_each_entry(entry, &lookup->entry_list, siblings) {
1563+
if (lock)
1564+
WARN_ON(configfs_depend_item_unlocked(
1565+
subsys, &entry->group.cg_item));
1566+
else
1567+
configfs_undepend_item_unlocked(
1568+
&entry->group.cg_item);
1569+
}
1570+
}
15331571
}
15341572

15351573
static ssize_t
@@ -1544,15 +1582,24 @@ gpio_virtuser_device_config_live_store(struct config_item *item,
15441582
if (ret)
15451583
return ret;
15461584

1547-
guard(mutex)(&dev->lock);
1585+
if (live)
1586+
gpio_virtuser_device_lockup_configfs(dev, true);
15481587

1549-
if (live == gpio_virtuser_device_is_live(dev))
1550-
return -EPERM;
1588+
scoped_guard(mutex, &dev->lock) {
1589+
if (live == gpio_virtuser_device_is_live(dev))
1590+
ret = -EPERM;
1591+
else if (live)
1592+
ret = gpio_virtuser_device_activate(dev);
1593+
else
1594+
gpio_virtuser_device_deactivate(dev);
1595+
}
15511596

1552-
if (live)
1553-
ret = gpio_virtuser_device_activate(dev);
1554-
else
1555-
gpio_virtuser_device_deactivate(dev);
1597+
/*
1598+
* Undepend is required only if device disablement (live == 0)
1599+
* succeeds or if device enablement (live == 1) fails.
1600+
*/
1601+
if (live == !!ret)
1602+
gpio_virtuser_device_lockup_configfs(dev, false);
15561603

15571604
return ret ?: count;
15581605
}

0 commit comments

Comments
 (0)