This is an old revision of the document!


This describes the mechanism used on a variety of platforms (ARM, MIPS, PowerPC) for handling “complicated” interrupt topologies involving multiple interrupt controllers attached at random throughout the device tree. This is targeted in particular at systems using either flattened device trees or CHRP-style Open Firmware (from which FDT is derived), but is generally applicable. Linux uses a similar mechanism on at least PowerPC.

Overview of mechanism

The core part of this system is a registry in machine-dependent code that maps some description of an interrupt to an IRQ number used by the rest of the kernel. This number is arbitrary; on systems in which a useful human-readable number can be extracted in a general way from the description, it is helpful for users for the IRQ number to be related to something about the system (e.g. the interrupt pin on single-controller systems) but it can be just a monotonically increasing integer.

API

Currently one interrupt mapping strategy is implemented: Open Firmware (or FDT) interrupt-parent / interrupt specifier tuples to IRQ. Bus code maps the Open Firmware interrupt specifier using the ofw_bus_map_intr() function, which is cascaded through the bus hierarchy and is usually resolved by nexus.

int ofw_bus_map_intr(device_t dev, phandle_t iparent, int icells, pcell_t *intr);

This takes the requesting device, the xref phandle of the interrupt parent (e.g. from the “interrupt-parent” property, or the equivalent entry in an interrupt-map) and the byte string describing the interrupt (e.g. the contents of the “interrupts” property, or the equivalent entry in an interrupt-map) and returns a unique IRQ number that can be added to a resource list and used with bus_alloc_resource(), bus_setup_intr(), etc.

Under the hood, this calls into machine-dependent code. The most general implementation (e.g. on PowerPC) has a mapping table that records the assigned IRQ and the interrupt specifier data. As PICs attach themselves during newbus discovery, they register their interest in a particular iparent value with the machine-dependent interrupt layer and eventually – potentially at attach time but at latest by configure_final() – are passed the section of the table corresponding to the registered iparent value and asked to configure them as specified by the PIC-dependent byte string and send interrupts corresponding to that descriptor to the IRQ assigned.

Rationale

This system is designed to support, without conflicts, systems with multiple interrupt controllers that have overlapping ranges of interrupt pins and that attach in an order unrelated to the need for the interrupts in the bus hierarchy. Because the interrupt hierarchy is unrelated to the bus hierarchy – it can involve lateral traverses , can flow the wrong way on branches (i.e. bus parents can depend on interrupts provided by children), and devices can have multiple interrupt parents – this cannot be done purely with bus methods.

Here are some examples of the kinds of things that drove the current API.

Apple PowerMac G5s have two PICs, one cascaded from the other. PIC 1 lives in the northbridge, and PIC 2 lives on a device on the PCI bus behind a couple of PCI↔PCI and HyperTransport bridges. Depending on the era of the hardware, these are cascaded in different directions.

This presents two puzzles:

A. How do I represent interrupts on the PCI bus parent of PIC 2 that are handled by PIC 2? PIC 2 obviously can't attach before its bus parent, but the bus parent can't complete initialization without the ability to setup its interrupts.

B. Devices on the PCI bus have interrupts handled by a mixture of PIC 1 and PIC 2, sometimes on the same device and not always expressable through the bus hierarchy. For example, one of the two storage controllers has an interrupt on PIC 2 run through a wire that doesn't go through the PCI connection and so isn't in the interrupt-map of the PCI bus, which is wired (mostly) to PIC 1, and about which the parent bus can and should know nothing.

These are solved by allowing bus_setup_intr() etc. to succeed before the PIC(s) has(have) attached, which breaks what would otherwise be a circular dependency loop.

The /ibm,opal device on IBM PowerNV systems has a non-standard interrupts property (“opal-interrupts”) that contains the list of IRQs that should be forwarded to the firmware. These are not interrupts belonging to a single physical device at /ibm,opal (which is a virtual device anyway) and so are not in the interrupts property; nor do they necessarily share an interrupt parent. How do I represent this?

This is solved by making the interrupt tree independent of the bus tree: since the parent doesn't know anything after assignment time, the child can call ofw_bus_map_intr() and add its special interrupts directly to its resource list using the appropriate newbus methods. After this, it behaves normally.

On virtualized (and most non-virtualized) IBM hardware, the interrupts are one cell and that single cell encodes the interrupt parent, the line sense, and the IRQ. It is not possible to disentangle in a generic way the interrupt parameters from pin number or handling IC since that depends on firmware behavior.

This is solved by treating the interrupt specifier as fully opaque: with no required inference about contents, an inability to infer contents doesn't matter. This would break systems that expect to be able to disentangle a “true” IRQ number and config flags.

MSIs are assigned purely by the PCI bus and the PCI bus parent can't know about them from the device tree. How does the bus parent sensibly decorate resources like this? The PCI MSI API assumes that these all exist purely as 32-bit integers and they are not assigned through resource lists in the conventional fashion.

These are solved by allowing the IRQ to be a single scalar number and making knowledge of the routing independent of the newbus hierarchy after assignment time. The PCI layer gets a number like it wants and handles it appropriately after assignment by the device-tree-aware PCI host bridge driver.

  • complicated_interrupts.1469416376.txt.gz
  • Last modified: 2016/07/25 03:12
  • by NathanWhitehorn