Originally, INTRNG has been designed for FDT like systems only. And while the current implementation was done more general, it turned out that it's not enough.
Thus, INTRNG must be reworked to answer needs of not FDT systems, on demand interrupt setups (e.g., not described in FDT dtb), MSI and MSI-X interrupts and others.
It's not sure now how some delicate things will be solved, however, the main result of this step should be a stable PIC interface which allows to start reworking of other PICs for use with INTRNG without dread of next steps.
(A) INTRNG works only with global interrupt numbers. Each of them is associated with some interrupt source (ISRC) on some interrupt controller (PIC). And only a PIC can know which global interrupt numbers are associated with its ISRCs. So, if someone wants to know a global interrupt number of some specific interrupt, the query must always end in some PIC.
Basically, a query should be done thru INTRNG framework. However, in some special cases when a PIC is an integral part of another device, it could be done within that device (not thru INTRNG framework). For example, someone could ask a GPIO framework for an interrupt for pin 20 on gpio1. If a PIC is a part of that gpio1 device, the query may be resolved internally.
(B) On modern SOCs, a description of an interrupt may be quite complex and may differ from PIC to PIC. It identifies an interrupt itself as well as its configuration. A description is not only associated with an interrupt, but also and mainly with a device. An interrupt may be utilized by more devices either at the same time or separately on user demand.
Thus, an interrupt may be configured repeatedly according to a device which just uses it at the moment. Therefore an interrupt description for a device must be stored somewhere to be found when needed. There is an idea to use struct resource. The r_virtual field could store a pointer to it. It's the simplest (perfect) solution as struct resource is already owned by a device and passed as an argument to interrupt related bus methods.
A struct intr_map_data is defined to represent various interrupt descriptions. The struct definition should be opaque for INTRNG framework for two reasons. First, only associated PIC could know the semantics of an interrupt description. Second, only creator (e.g. FDT bus driver) and recepient (e.g. FDT knowing PIC) of this struct must know its definition.
To get a global interrupt number thru INTRNG framework, one general mapping function and correspondig PIC method are implemented:
intr_map_irq() => pic_map_intr()
which take PIC identification and struct intr_map_data as arguments.
For general use, four INTRNG functions and corresponding PIC methods are implemented to be used for BUS resource methods implementation.
bus_alloc_resource(): intr_alloc_irq() => pic_alloc_intr()
bus_setup_intr(): intr_setup_irq() => pic_setup_intr()
bus_teardown_intr(): intr_teardown_irq => pic_teardown_intr()
bus_release_intr(): intr_release_irq() => pic_release_intr()
A struct resource and struct intr_map_data are passed to these functions and methods as arguments to be general enough. In these structs, data needed for PIC to configure an interrupt may be stored. A struct intr_map_data argument may be NULL, meaning that there is no configuration.
A bus_config_intr() method is not standard as struct resource is not passed as an argument to it. It's not supported by INTRNG framework. An interrupt configuration should be passed to PIC thru struct intr_map_data.
Only global interrupt numbers must be held in struct resource which is passed as an argument to INTRNG functions!
IN THIS STEP
The main result of this step should be a stable PIC interface.
(1) The idea above is implemented.
(2) ISRC allocations was moved from INTRNG framework to PICs. They are allocated at the beginning and global interrupt numbers are assigned to them at the same time. There is no more a need for calling a mapping function to start using any global interrupt number (the number still must be correct).
(3) Temporarily, struct intr_map_data is stored in a table in INTRNG framework to not hold back reworking of other PICs before real solution will be implemeted. Such solution is not expected to change PIC interface.
However, this temporary solution creates two global interrupt number spaces at this moment. The first space associated with ISRCs is the real one. The second space associated with table keeping struct intr_map_data for devices is artificial one. Each interrupt number from second space duplicates some number from first space. An interrupt number from first space can be duplicated even multiple times in second space.
Two (ACPI and FDT) types for struct intr_map_data are defined for now and two corresponding map functions are implemented.
Almost nothing is changed with regard to previous behaviour of INTRNG framework. However, as these functions still may be called before corresponding PIC is attached, a situation is better now as the issue that two ISRCs are allocated for same interrupt cannot happen. The issue that two global interrupt numbers are associated with same ISRCs will be resolved in next step.
(4) A struct intr_irqsrc is cleaned up now as fdt data is no more a part of it.
(5) A struct resource is also passed to the following INTRNG framework functions to keep line with other ones:
(6) Some other PIC methods are renamed to reflect new naming and a demand done before.
STABLE PIC interface
Each PIC should define own ISRC struct with struct intr_irqsrc on top of it, allocate all its ISRCs and register them to INTRNG by calling intr_isrc_register().
Minimal PIC implementation must provide the following methods:
pic_disable_intr() ... called to disable an interrupt when there is no handler for it
pic_enable_intr() ... called to enable an interrupt when first handler is added for it
pic_post_filter() ... for MI interrupt framework
pic_post_ithread() ... for MI interrupt framework
pic_pre_ithread() ... for MI interrupt framework
If a PIC supports some interrupt mapping method(s), it must provide
pic_map_intr() ... to map data in struct intr_map_data into global interrupt number
If a PIC needs to setup (or teardown) an interrupt, it must provide
pic_setup_intr() ... to setup an interrupt
pic_teardown_intr() ... to teardown an interrupt
Both methods are called with every handler added for an interrupt, so a PIC could check that configurations associated with handlers do match.
There are two more methods, however, not used now
pic_alloc_intr() ... called to be noticed that someone allocate a resource for an interrupt
pic_release_intr() ... called to be noticed that someone release a resource for an interrupt
Finally, there are four methods for SMP case
pic_bind_intr() ... to bind an interrupt to some CPU
pic_init_secondary() ... to init PIC on AP
pic_ipi_send() ... to send an IPI
pic_ipi_setup() ... to setup an IPI
Only pic_post_filter() and pic_pre_ithread() are called in an interrupt context. They could have a local scope. I.e., their actions should or may be limited to current cpu only. However, as a matter of fact of pic_pre_ithread() local scope, pic_post_ithread() is called from an ithread context which may run on another cpu.