Commit 2bd1bea5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'irq-cleanups-2025-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq cleanups from Thomas Gleixner:
 "A set of cleanups for the generic interrupt subsystem:

   - Consolidate on one set of functions for the interrupt domain code
     to get rid of pointlessly duplicated code with only marginal
     different semantics.

   - Update the documentation accordingly and consolidate the coding
     style of the irqdomain header"

* tag 'irq-cleanups-2025-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (46 commits)
  irqdomain: Consolidate coding style
  irqdomain: Fix kernel-doc and add it to Documentation
  Documentation: irqdomain: Update it
  Documentation: irq-domain.rst: Simple improvements
  Documentation: irq/concepts: Minor improvements
  Documentation: irq/concepts: Add commas and reflow
  irqdomain: Improve kernel-docs of functions
  irqdomain: Make struct irq_domain_info variables const
  irqdomain: Use irq_domain_instantiate()'s return value as initializers
  irqdomain: Drop irq_linear_revmap()
  pinctrl: keembay: Switch to irq_find_mapping()
  irqchip/armada-370-xp: Switch to irq_find_mapping()
  gpu: ipu-v3: Switch to irq_find_mapping()
  gpio: idt3243x: Switch to irq_find_mapping()
  sh: Switch to irq_find_mapping()
  powerpc: Switch to irq_find_mapping()
  irqdomain: Drop irq_domain_add_*() functions
  powerpc: Switch irq_domain_add_nomap() to use fwnode
  thermal: Switch to irq_domain_create_linear()
  soc: Switch to irq_domain_create_*()
  ...
parents c0f182c9 38c1e73f
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -410,8 +410,6 @@ which are used in the generic IRQ layer.
.. kernel-doc:: include/linux/interrupt.h
   :internal:

.. kernel-doc:: include/linux/irqdomain.h

Public Functions Provided
=========================

+14 −13
Original line number Diff line number Diff line
@@ -2,21 +2,22 @@
What is an IRQ?
===============

An IRQ is an interrupt request from a device.
Currently they can come in over a pin, or over a packet.
Several devices may be connected to the same pin thus
sharing an IRQ.
An IRQ is an interrupt request from a device. Currently, they can come
in over a pin, or over a packet. Several devices may be connected to
the same pin thus sharing an IRQ. Such as on legacy PCI bus: All devices
typically share 4 lanes/pins. Note that each device can request an
interrupt on each of the lanes.

An IRQ number is a kernel identifier used to talk about a hardware
interrupt source.  Typically this is an index into the global irq_desc
array, but except for what linux/interrupt.h implements the details
are architecture specific.
interrupt source. Typically, this is an index into the global irq_desc
array or sparse_irqs tree. But except for what linux/interrupt.h
implements, the details are architecture specific.

An IRQ number is an enumeration of the possible interrupt sources on a
machine.  Typically what is enumerated is the number of input pins on
all of the interrupt controller in the system.  In the case of ISA
what is enumerated are the 16 input pins on the two i8259 interrupt
controllers.
machine. Typically, what is enumerated is the number of input pins on
all of the interrupt controllers in the system. In the case of ISA,
what is enumerated are the 8 input pins on each of the two i8259
interrupt controllers.

Architectures can assign additional meaning to the IRQ numbers, and
are encouraged to in the case where there is any manual configuration
+113 −90
Original line number Diff line number Diff line
===============================================
The irq_domain interrupt number mapping library
The irq_domain Interrupt Number Mapping Library
===============================================

The current design of the Linux kernel uses a single large number
space where each separate IRQ source is assigned a different number.
This is simple when there is only one interrupt controller, but in
systems with multiple interrupt controllers the kernel must ensure
space where each separate IRQ source is assigned a unique number.
This is simple when there is only one interrupt controller. But in
systems with multiple interrupt controllers, the kernel must ensure
that each one gets assigned non-overlapping allocations of Linux
IRQ numbers.

The number of interrupt controllers registered as unique irqchips
show a rising tendency: for example subdrivers of different kinds
shows a rising tendency. For example, subdrivers of different kinds
such as GPIO controllers avoid reimplementing identical callback
mechanisms as the IRQ core system by modelling their interrupt
handlers as irqchips, i.e. in effect cascading interrupt controllers.
handlers as irqchips. I.e. in effect cascading interrupt controllers.

Here the interrupt number loose all kind of correspondence to
hardware interrupt numbers: whereas in the past, IRQ numbers could
be chosen so they matched the hardware IRQ line into the root
interrupt controller (i.e. the component actually fireing the
interrupt line to the CPU) nowadays this number is just a number.
So in the past, IRQ numbers could be chosen so that they match the
hardware IRQ line into the root interrupt controller (i.e. the
component actually firing the interrupt line to the CPU). Nowadays,
this number is just a number and the number loose all kind of
correspondence to hardware interrupt numbers.

For this reason we need a mechanism to separate controller-local
interrupt numbers, called hardware irq's, from Linux IRQ numbers.
For this reason, we need a mechanism to separate controller-local
interrupt numbers, called hardware IRQs, from Linux IRQ numbers.

The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
irq numbers, but they don't provide any support for reverse mapping of
IRQ numbers, but they don't provide any support for reverse mapping of
the controller-local IRQ (hwirq) number into the Linux IRQ number
space.

The irq_domain library adds mapping between hwirq and IRQ numbers on
top of the irq_alloc_desc*() API.  An irq_domain to manage mapping is
preferred over interrupt controller drivers open coding their own
The irq_domain library adds a mapping between hwirq and IRQ numbers on
top of the irq_alloc_desc*() API. An irq_domain to manage the mapping
is preferred over interrupt controller drivers open coding their own
reverse mapping scheme.

irq_domain also implements translation from an abstract irq_fwspec
structure to hwirq numbers (Device Tree and ACPI GSI so far), and can
be easily extended to support other IRQ topology data sources.
irq_domain also implements a translation from an abstract struct
irq_fwspec to hwirq numbers (Device Tree, non-DT firmware node, ACPI
GSI, and software node so far), and can be easily extended to support
other IRQ topology data sources. The implementation is performed
without any extra platform support code.

irq_domain usage
irq_domain Usage
================

An interrupt controller driver creates and registers an irq_domain by
calling one of the irq_domain_add_*() or irq_domain_create_*() functions
(each mapping method has a different allocator function, more on that later).
The function will return a pointer to the irq_domain on success. The caller
must provide the allocator function with an irq_domain_ops structure.
struct irq_domain could be defined as an irq domain controller. That
is, it handles the mapping between hardware and virtual interrupt
numbers for a given interrupt domain. The domain structure is
generally created by the PIC code for a given PIC instance (though a
domain can cover more than one PIC if they have a flat number model).
It is the domain callbacks that are responsible for setting the
irq_chip on a given irq_desc after it has been mapped.

The host code and data structures use a fwnode_handle pointer to
identify the domain. In some cases, and in order to preserve source
code compatibility, this fwnode pointer is "upgraded" to a DT
device_node. For those firmware infrastructures that do not provide a
unique identifier for an interrupt controller, the irq_domain code
offers a fwnode allocator.

An interrupt controller driver creates and registers a struct irq_domain
by calling one of the irq_domain_create_*() functions (each mapping
method has a different allocator function, more on that later). The
function will return a pointer to the struct irq_domain on success. The
caller must provide the allocator function with a struct irq_domain_ops
pointer.

In most cases, the irq_domain will begin empty without any mappings
between hwirq and IRQ numbers.  Mappings are added to the irq_domain
by calling irq_create_mapping() which accepts the irq_domain and a
hwirq number as arguments. If a mapping for the hwirq doesn't already
exist then it will allocate a new Linux irq_desc, associate it with
the hwirq, and call the .map() callback so the driver can perform any
required hardware setup.
exist, irq_create_mapping() allocates a new Linux irq_desc, associates
it with the hwirq, and calls the :c:member:`irq_domain_ops.map()`
callback. In there, the driver can perform any required hardware
setup.

Once a mapping has been established, it can be retrieved or used via a
variety of methods:
@@ -63,8 +81,6 @@ variety of methods:
  mapping.
- irq_find_mapping() returns a Linux IRQ number for a given domain and
  hwirq number, and 0 if there was no mapping
- irq_linear_revmap() is now identical to irq_find_mapping(), and is
  deprecated
- generic_handle_domain_irq() handles an interrupt described by a
  domain and a hwirq number

@@ -77,9 +93,10 @@ be allocated.

If the driver has the Linux IRQ number or the irq_data pointer, and
needs to know the associated hwirq number (such as in the irq_chip
callbacks) then it can be directly obtained from irq_data->hwirq.
callbacks) then it can be directly obtained from
:c:member:`irq_data.hwirq`.

Types of irq_domain mappings
Types of irq_domain Mappings
============================

There are several mechanisms available for reverse mapping from hwirq
@@ -92,7 +109,6 @@ Linear

::

	irq_domain_add_linear()
	irq_domain_create_linear()

The linear reverse map maintains a fixed size table indexed by the
@@ -105,19 +121,13 @@ map are fixed time lookup for IRQ numbers, and irq_descs are only
allocated for in-use IRQs.  The disadvantage is that the table must be
as large as the largest possible hwirq number.

irq_domain_add_linear() and irq_domain_create_linear() are functionally
equivalent, except for the first argument is different - the former
accepts an Open Firmware specific 'struct device_node', while the latter
accepts a more general abstraction 'struct fwnode_handle'.

The majority of drivers should use the linear map.
The majority of drivers should use the Linear map.

Tree
----

::

	irq_domain_add_tree()
	irq_domain_create_tree()

The irq_domain maintains a radix tree map from hwirq numbers to Linux
@@ -129,11 +139,6 @@ since it doesn't need to allocate a table as large as the largest
hwirq number.  The disadvantage is that hwirq to IRQ number lookup is
dependent on how many entries are in the table.

irq_domain_add_tree() and irq_domain_create_tree() are functionally
equivalent, except for the first argument is different - the former
accepts an Open Firmware specific 'struct device_node', while the latter
accepts a more general abstraction 'struct fwnode_handle'.

Very few drivers should need this mapping.

No Map
@@ -141,7 +146,7 @@ No Map

::

	irq_domain_add_nomap()
	irq_domain_create_nomap()

The No Map mapping is to be used when the hwirq number is
programmable in the hardware.  In this case it is best to program the
@@ -159,8 +164,6 @@ Legacy

::

	irq_domain_add_simple()
	irq_domain_add_legacy()
	irq_domain_create_simple()
	irq_domain_create_legacy()

@@ -189,13 +192,13 @@ supported. For example, ISA controllers would use the legacy map for
mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
numbers.

Most users of legacy mappings should use irq_domain_add_simple() or
irq_domain_create_simple() which will use a legacy domain only if an IRQ range
is supplied by the system and will otherwise use a linear domain mapping.
The semantics of this call are such that if an IRQ range is specified then
descriptors will be allocated on-the-fly for it, and if no range is
specified it will fall through to irq_domain_add_linear() or
irq_domain_create_linear() which means *no* irq descriptors will be allocated.
Most users of legacy mappings should use irq_domain_create_simple()
which will use a legacy domain only if an IRQ range is supplied by the
system and will otherwise use a linear domain mapping. The semantics of
this call are such that if an IRQ range is specified then descriptors
will be allocated on-the-fly for it, and if no range is specified it
will fall through to irq_domain_create_linear() which means *no* irq
descriptors will be allocated.

A typical use case for simple domains is where an irqchip provider
is supporting both dynamic and static IRQ assignments.
@@ -206,13 +209,7 @@ that the driver using the simple domain call irq_create_mapping()
before any irq_find_mapping() since the latter will actually work
for the static IRQ assignment case.

irq_domain_add_simple() and irq_domain_create_simple() as well as
irq_domain_add_legacy() and irq_domain_create_legacy() are functionally
equivalent, except for the first argument is different - the former
accepts an Open Firmware specific 'struct device_node', while the latter
accepts a more general abstraction 'struct fwnode_handle'.

Hierarchy IRQ domain
Hierarchy IRQ Domain
--------------------

On some architectures, there may be multiple interrupt controllers
@@ -253,20 +250,40 @@ There are four major interfaces to use hierarchy irq_domain:
4) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
   to stop delivering the interrupt.

Following changes are needed to support hierarchy irq_domain:
The following is needed to support hierarchy irq_domain:

1) a new field 'parent' is added to struct irq_domain; it's used to
1) The :c:member:`parent` field in struct irq_domain is used to
   maintain irq_domain hierarchy information.
2) a new field 'parent_data' is added to struct irq_data; it's used to
   build hierarchy irq_data to match hierarchy irq_domains. The irq_data
   is used to store irq_domain pointer and hardware irq number.
3) new callbacks are added to struct irq_domain_ops to support hierarchy
   irq_domain operations.

With support of hierarchy irq_domain and hierarchy irq_data ready, an
irq_domain structure is built for each interrupt controller, and an
2) The :c:member:`parent_data` field in struct irq_data is used to
   build hierarchy irq_data to match hierarchy irq_domains. The
   irq_data is used to store irq_domain pointer and hardware irq
   number.
3) The :c:member:`alloc()`, :c:member:`free()`, and other callbacks in
   struct irq_domain_ops to support hierarchy irq_domain operations.

With the support of hierarchy irq_domain and hierarchy irq_data ready,
an irq_domain structure is built for each interrupt controller, and an
irq_data structure is allocated for each irq_domain associated with an
IRQ. Now we could go one step further to support stacked(hierarchy)
IRQ.

For an interrupt controller driver to support hierarchy irq_domain, it
needs to:

1) Implement irq_domain_ops.alloc() and irq_domain_ops.free()
2) Optionally, implement irq_domain_ops.activate() and
   irq_domain_ops.deactivate().
3) Optionally, implement an irq_chip to manage the interrupt controller
   hardware.
4) There is no need to implement irq_domain_ops.map() and
   irq_domain_ops.unmap(). They are unused with hierarchy irq_domain.

Note the hierarchy irq_domain is in no way x86-specific, and is
heavily used to support other architectures, such as ARM, ARM64 etc.

Stacked irq_chip
~~~~~~~~~~~~~~~~

Now, we could go one step further to support stacked (hierarchy)
irq_chip. That is, an irq_chip is associated with each irq_data along
the hierarchy. A child irq_chip may implement a required action by
itself or by cooperating with its parent irq_chip.
@@ -276,22 +293,28 @@ with the hardware managed by itself and may ask for services from its
parent irq_chip when needed. So we could achieve a much cleaner
software architecture.

For an interrupt controller driver to support hierarchy irq_domain, it
needs to:

1) Implement irq_domain_ops.alloc and irq_domain_ops.free
2) Optionally implement irq_domain_ops.activate and
   irq_domain_ops.deactivate.
3) Optionally implement an irq_chip to manage the interrupt controller
   hardware.
4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap,
   they are unused with hierarchy irq_domain.

Hierarchy irq_domain is in no way x86 specific, and is heavily used to
support other architectures, such as ARM, ARM64 etc.

Debugging
=========

Most of the internals of the IRQ subsystem are exposed in debugfs by
turning CONFIG_GENERIC_IRQ_DEBUGFS on.

Structures and Public Functions Provided
========================================

This chapter contains the autogenerated documentation of the structures
and exported kernel API functions which are used for IRQ domains.

.. kernel-doc:: include/linux/irqdomain.h

.. kernel-doc:: kernel/irq/irqdomain.c
   :export:

Internal Functions Provided
===========================

This chapter contains the autogenerated documentation of the internal
functions.

.. kernel-doc:: kernel/irq/irqdomain.c
   :internal:
+1 −7
Original line number Diff line number Diff line
@@ -60,8 +60,6 @@ irq_domain和一个hwirq号作为参数。 如果hwirq的映射还不存在,

- irq_find_mapping()返回给定域和hwirq的Linux IRQ号,如果没有映射则返回0。

- irq_linear_revmap()现与irq_find_mapping()相同,已被废弃。

- generic_handle_domain_irq()处理一个由域和hwirq号描述的中断。

请注意,irq域的查找必须发生在与RCU读临界区兼容的上下文中。
@@ -83,7 +81,6 @@ irq_domain映射的类型

::

	irq_domain_add_linear()
	irq_domain_create_linear()

线性反向映射维护了一个固定大小的表,该表以hwirq号为索引。 当一个hwirq被映射
@@ -104,7 +101,6 @@ irq_domain_add_linear()和irq_domain_create_linear()在功能上是等价的,

::

	irq_domain_add_tree()
	irq_domain_create_tree()

irq_domain维护着从hwirq号到Linux IRQ的radix的树状映射。 当一个hwirq被映射时,
@@ -124,7 +120,7 @@ irq_domain_add_tree()和irq_domain_create_tree()在功能上是等价的,除

::

	irq_domain_add_nomap()
	irq_domain_create_nomap()

当硬件中的hwirq号是可编程的时候,就可以采用无映射类型。 在这种情况下,最好将
Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create_direct_mapping()
@@ -138,8 +134,6 @@ Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create

::

	irq_domain_add_simple()
	irq_domain_add_legacy()
	irq_domain_create_simple()
	irq_domain_create_legacy()

+1 −1
Original line number Diff line number Diff line
@@ -170,7 +170,7 @@ init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
	if (parent)
		panic("DeviceTree incore intc not a root irq controller\n");

	root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, &arcv2_irq_ops, NULL);
	root_domain = irq_domain_create_linear(of_fwnode_handle(intc), nr_cpu_irqs, &arcv2_irq_ops, NULL);
	if (!root_domain)
		panic("root irq domain not avail\n");

Loading