Skip to content

Commit

Permalink
irqchip: Add IRQCHIP_PLATFORM_DRIVER_BEGIN/END and IRQCHIP_MATCH help…
Browse files Browse the repository at this point in the history
…er macros

Compiling an irqchip driver as a platform driver needs to bunch of
things to be done right:
- Making sure the parent domain is initialized first
- Making sure the device can't be unbound from sysfs
- Disallowing module unload if it's built as a module
- Finding the parent node
- Etc.

Instead of trying to make sure all future irqchip platform drivers get
this right, provide boilerplate macros that take care of all of this.

An example use would look something like this. Where acme_foo_init and
acme_bar_init are similar to what would be passed to IRQCHIP_DECLARE.

IRQCHIP_PLATFORM_DRIVER_BEGIN(acme_irq)
IRQCHIP_MATCH("acme,foo", acme_foo_init)
IRQCHIP_MATCH("acme,bar", acme_bar_init)
IRQCHIP_PLATFORM_DRIVER_END(acme_irq)

Signed-off-by: Saravana Kannan <saravanak@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Cc: John Stultz <john.stultz@linaro.org>
Link: https://lore.kernel.org/r/20200718000637.3632841-2-saravanak@google.com
  • Loading branch information
Saravana Kannan authored and Marc Zyngier committed Jul 27, 2020
1 parent b7640d7 commit f8410e6
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
29 changes: 29 additions & 0 deletions drivers/irqchip/irqchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/platform_device.h>

/*
* This special of_device_id is the sentinel at the end of the
Expand All @@ -29,3 +31,30 @@ void __init irqchip_init(void)
of_irq_init(__irqchip_of_table);
acpi_probe_device_table(irqchip);
}

int platform_irqchip_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *par_np = of_irq_find_parent(np);
of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev);

if (!irq_init_cb)
return -EINVAL;

if (par_np == np)
par_np = NULL;

/*
* If there's a parent interrupt controller and none of the parent irq
* domains have been registered, that means the parent interrupt
* controller has not been initialized yet. it's not time for this
* interrupt controller to initialize. So, defer probe of this
* interrupt controller. The actual initialization callback of this
* interrupt controller can check for specific domains as necessary.
*/
if (par_np && !irq_find_matching_host(np, DOMAIN_BUS_ANY))
return -EPROBE_DEFER;

return irq_init_cb(np, par_np);
}
EXPORT_SYMBOL_GPL(platform_irqchip_probe);
23 changes: 23 additions & 0 deletions include/linux/irqchip.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/platform_device.h>

/*
* This macro must be used by the different irqchip drivers to declare
Expand All @@ -26,6 +27,28 @@
*/
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)

extern int platform_irqchip_probe(struct platform_device *pdev);

#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \
static const struct of_device_id drv_name##_irqchip_match_table[] = {

#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, .data = fn },

#define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \
{}, \
}; \
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \
static struct platform_driver drv_name##_driver = { \
.probe = platform_irqchip_probe, \
.driver = { \
.name = #drv_name, \
.owner = THIS_MODULE, \
.of_match_table = drv_name##_irqchip_match_table, \
.suppress_bind_attrs = true, \
}, \
}; \
builtin_platform_driver(drv_name##_driver)

/*
* This macro must be used by the different irqchip drivers to declare
* the association between their version and their initialization function.
Expand Down

0 comments on commit f8410e6

Please sign in to comment.