Skip to content

Commit 91a29af

Browse files
author
Marc Zyngier
committed
gpio: Remove dynamic allocation from populate_parent_alloc_arg()
The gpiolib is unique in the way it uses intermediate fwspecs when feeding an interrupt specifier to the parent domain, as it relies on the populate_parent_alloc_arg() callback to perform a dynamic allocation. This is pretty inefficient (we free the structure almost immediately), and the only reason this isn't a stack allocation is that our ThunderX friend uses MSIs rather than a FW-constructed structure. Let's solve it by providing a new type composed of the union of a struct irq_fwspec and a msi_info_t, which satisfies both requirements. This allows us to use a stack allocation, and we can move the handful of users to this new scheme. Also perform some additional cleanup, such as getting rid of the stub versions of the irq_domain_translate_*cell helpers, which are never used when CONFIG_IRQ_DOMAIN_HIERARCHY isn't selected. Tested on a Tegra186. Reviewed-by: Linus Walleij <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Cc: Daniel Palmer <[email protected]> Cc: Romain Perier <[email protected]> Cc: Bartosz Golaszewski <[email protected]> Cc: Thierry Reding <[email protected]> Cc: Jonathan Hunter <[email protected]> Cc: Robert Richter <[email protected]> Cc: Nobuhiro Iwamatsu <[email protected]> Cc: Andy Gross <[email protected]> Cc: Bjorn Andersson <[email protected]> Acked-by: Bartosz Golaszewski <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a111daf commit 91a29af

File tree

8 files changed

+73
-101
lines changed

8 files changed

+73
-101
lines changed

drivers/gpio/gpio-msc313.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -550,23 +550,20 @@ static struct irq_chip msc313_gpio_irqchip = {
550550
* so we need to provide the fwspec. Essentially gpiochip_populate_parent_fwspec_twocell
551551
* that puts GIC_SPI into the first cell.
552552
*/
553-
static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
554-
unsigned int parent_hwirq,
555-
unsigned int parent_type)
553+
static int msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
554+
union gpio_irq_fwspec *gfwspec,
555+
unsigned int parent_hwirq,
556+
unsigned int parent_type)
556557
{
557-
struct irq_fwspec *fwspec;
558-
559-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
560-
if (!fwspec)
561-
return NULL;
558+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
562559

563560
fwspec->fwnode = gc->irq.parent_domain->fwnode;
564561
fwspec->param_count = 3;
565562
fwspec->param[0] = GIC_SPI;
566563
fwspec->param[1] = parent_hwirq;
567564
fwspec->param[2] = parent_type;
568565

569-
return fwspec;
566+
return 0;
570567
}
571568

572569
static int msc313e_gpio_child_to_parent_hwirq(struct gpio_chip *chip,

drivers/gpio/gpio-tegra.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -443,23 +443,20 @@ static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
443443
return 0;
444444
}
445445

446-
static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
447-
unsigned int parent_hwirq,
448-
unsigned int parent_type)
446+
static int tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
447+
union gpio_irq_fwspec *gfwspec,
448+
unsigned int parent_hwirq,
449+
unsigned int parent_type)
449450
{
450-
struct irq_fwspec *fwspec;
451-
452-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
453-
if (!fwspec)
454-
return NULL;
451+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
455452

456453
fwspec->fwnode = chip->irq.parent_domain->fwnode;
457454
fwspec->param_count = 3;
458455
fwspec->param[0] = 0;
459456
fwspec->param[1] = parent_hwirq;
460457
fwspec->param[2] = parent_type;
461458

462-
return fwspec;
459+
return 0;
463460
}
464461

465462
#ifdef CONFIG_PM_SLEEP

drivers/gpio/gpio-tegra186.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -621,24 +621,21 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
621621
return 0;
622622
}
623623

624-
static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
625-
unsigned int parent_hwirq,
626-
unsigned int parent_type)
624+
static int tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
625+
union gpio_irq_fwspec *gfwspec,
626+
unsigned int parent_hwirq,
627+
unsigned int parent_type)
627628
{
628629
struct tegra_gpio *gpio = gpiochip_get_data(chip);
629-
struct irq_fwspec *fwspec;
630-
631-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
632-
if (!fwspec)
633-
return NULL;
630+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
634631

635632
fwspec->fwnode = chip->irq.parent_domain->fwnode;
636633
fwspec->param_count = 3;
637634
fwspec->param[0] = gpio->soc->instance;
638635
fwspec->param[1] = parent_hwirq;
639636
fwspec->param[2] = parent_type;
640637

641-
return fwspec;
638+
return 0;
642639
}
643640

644641
static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip,

drivers/gpio/gpio-thunderx.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -408,18 +408,15 @@ static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
408408
return 0;
409409
}
410410

411-
static void *thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
412-
unsigned int parent_hwirq,
413-
unsigned int parent_type)
411+
static int thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
412+
union gpio_irq_fwspec *gfwspec,
413+
unsigned int parent_hwirq,
414+
unsigned int parent_type)
414415
{
415-
msi_alloc_info_t *info;
416-
417-
info = kmalloc(sizeof(*info), GFP_KERNEL);
418-
if (!info)
419-
return NULL;
416+
msi_alloc_info_t *info = &gfwspec->msiinfo;
420417

421418
info->hwirq = parent_hwirq;
422-
return info;
419+
return 0;
423420
}
424421

425422
static int thunderx_gpio_probe(struct pci_dev *pdev,

drivers/gpio/gpio-visconti.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,20 @@ static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
103103
return -EINVAL;
104104
}
105105

106-
static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
107-
unsigned int parent_hwirq,
108-
unsigned int parent_type)
106+
static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
107+
union gpio_irq_fwspec *gfwspec,
108+
unsigned int parent_hwirq,
109+
unsigned int parent_type)
109110
{
110-
struct irq_fwspec *fwspec;
111-
112-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
113-
if (!fwspec)
114-
return NULL;
111+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
115112

116113
fwspec->fwnode = chip->irq.parent_domain->fwnode;
117114
fwspec->param_count = 3;
118115
fwspec->param[0] = 0;
119116
fwspec->param[1] = parent_hwirq;
120117
fwspec->param[2] = parent_type;
121118

122-
return fwspec;
119+
return 0;
123120
}
124121

125122
static int visconti_gpio_probe(struct platform_device *pdev)

drivers/gpio/gpiolib.c

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
11071107
irq_hw_number_t hwirq;
11081108
unsigned int type = IRQ_TYPE_NONE;
11091109
struct irq_fwspec *fwspec = data;
1110-
void *parent_arg;
1110+
union gpio_irq_fwspec gpio_parent_fwspec = {};
11111111
unsigned int parent_hwirq;
11121112
unsigned int parent_type;
11131113
struct gpio_irq_chip *girq = &gc->irq;
@@ -1147,14 +1147,15 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
11471147
irq_set_probe(irq);
11481148

11491149
/* This parent only handles asserted level IRQs */
1150-
parent_arg = girq->populate_parent_alloc_arg(gc, parent_hwirq, parent_type);
1151-
if (!parent_arg)
1152-
return -ENOMEM;
1150+
ret = girq->populate_parent_alloc_arg(gc, &gpio_parent_fwspec,
1151+
parent_hwirq, parent_type);
1152+
if (ret)
1153+
return ret;
11531154

11541155
chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
11551156
irq, parent_hwirq);
11561157
irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
1157-
ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg);
1158+
ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec);
11581159
/*
11591160
* If the parent irqdomain is msi, the interrupts have already
11601161
* been allocated, so the EEXIST is good.
@@ -1166,7 +1167,6 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
11661167
"failed to allocate parent hwirq %d for hwirq %lu\n",
11671168
parent_hwirq, hwirq);
11681169

1169-
kfree(parent_arg);
11701170
return ret;
11711171
}
11721172

@@ -1230,34 +1230,28 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
12301230
return !!gc->irq.parent_domain;
12311231
}
12321232

1233-
void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
1234-
unsigned int parent_hwirq,
1235-
unsigned int parent_type)
1233+
int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
1234+
union gpio_irq_fwspec *gfwspec,
1235+
unsigned int parent_hwirq,
1236+
unsigned int parent_type)
12361237
{
1237-
struct irq_fwspec *fwspec;
1238-
1239-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
1240-
if (!fwspec)
1241-
return NULL;
1238+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
12421239

12431240
fwspec->fwnode = gc->irq.parent_domain->fwnode;
12441241
fwspec->param_count = 2;
12451242
fwspec->param[0] = parent_hwirq;
12461243
fwspec->param[1] = parent_type;
12471244

1248-
return fwspec;
1245+
return 0;
12491246
}
12501247
EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
12511248

1252-
void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
1253-
unsigned int parent_hwirq,
1254-
unsigned int parent_type)
1249+
int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
1250+
union gpio_irq_fwspec *gfwspec,
1251+
unsigned int parent_hwirq,
1252+
unsigned int parent_type)
12551253
{
1256-
struct irq_fwspec *fwspec;
1257-
1258-
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
1259-
if (!fwspec)
1260-
return NULL;
1254+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
12611255

12621256
fwspec->fwnode = gc->irq.parent_domain->fwnode;
12631257
fwspec->param_count = 4;
@@ -1266,7 +1260,7 @@ void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
12661260
fwspec->param[2] = 0;
12671261
fwspec->param[3] = parent_type;
12681262

1269-
return fwspec;
1263+
return 0;
12701264
}
12711265
EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
12721266

drivers/pinctrl/qcom/pinctrl-spmi-gpio.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -966,16 +966,13 @@ static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
966966
return 0;
967967
}
968968

969-
static void *pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
970-
unsigned int parent_hwirq,
971-
unsigned int parent_type)
969+
static int pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
970+
union gpio_irq_fwspec *gfwspec,
971+
unsigned int parent_hwirq,
972+
unsigned int parent_type)
972973
{
973974
struct pmic_gpio_state *state = gpiochip_get_data(chip);
974-
struct irq_fwspec *fwspec;
975-
976-
fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
977-
if (!fwspec)
978-
return NULL;
975+
struct irq_fwspec *fwspec = &gfwspec->fwspec;
979976

980977
fwspec->fwnode = chip->irq.parent_domain->fwnode;
981978

@@ -985,7 +982,7 @@ static void *pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
985982
/* param[2] must be left as 0 */
986983
fwspec->param[3] = parent_type;
987984

988-
return fwspec;
985+
return 0;
989986
}
990987

991988
static int pmic_gpio_probe(struct platform_device *pdev)

include/linux/gpio/driver.h

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <linux/property.h>
1313
#include <linux/types.h>
1414

15+
#include <asm/msi.h>
16+
1517
struct gpio_desc;
1618
struct of_phandle_args;
1719
struct device_node;
@@ -23,6 +25,13 @@ enum gpio_lookup_flags;
2325

2426
struct gpio_chip;
2527

28+
union gpio_irq_fwspec {
29+
struct irq_fwspec fwspec;
30+
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
31+
msi_alloc_info_t msiinfo;
32+
#endif
33+
};
34+
2635
#define GPIO_LINE_DIRECTION_IN 1
2736
#define GPIO_LINE_DIRECTION_OUT 0
2837

@@ -103,9 +112,10 @@ struct gpio_irq_chip {
103112
* variant named &gpiochip_populate_parent_fwspec_fourcell is also
104113
* available.
105114
*/
106-
void *(*populate_parent_alloc_arg)(struct gpio_chip *gc,
107-
unsigned int parent_hwirq,
108-
unsigned int parent_type);
115+
int (*populate_parent_alloc_arg)(struct gpio_chip *gc,
116+
union gpio_irq_fwspec *fwspec,
117+
unsigned int parent_hwirq,
118+
unsigned int parent_type);
109119

110120
/**
111121
* @child_offset_to_irq:
@@ -646,28 +656,14 @@ struct bgpio_pdata {
646656

647657
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
648658

649-
void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
659+
int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
660+
union gpio_irq_fwspec *gfwspec,
661+
unsigned int parent_hwirq,
662+
unsigned int parent_type);
663+
int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
664+
union gpio_irq_fwspec *gfwspec,
650665
unsigned int parent_hwirq,
651666
unsigned int parent_type);
652-
void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
653-
unsigned int parent_hwirq,
654-
unsigned int parent_type);
655-
656-
#else
657-
658-
static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
659-
unsigned int parent_hwirq,
660-
unsigned int parent_type)
661-
{
662-
return NULL;
663-
}
664-
665-
static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
666-
unsigned int parent_hwirq,
667-
unsigned int parent_type)
668-
{
669-
return NULL;
670-
}
671667

672668
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
673669

0 commit comments

Comments
 (0)