Commit fcfde8a7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'irq-core-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull interrupt handling updates from Thomas Gleixner:
 "Core code:

   - Make the managed interrupts more robust by shutting them down in
     the core code when the assigned affinity mask does not contain
     online CPUs.

   - Make the irq simulator chip work on RT

   - A small set of cpumask and power manageent cleanups

  Drivers:

   - A set of changes which mark GPIO interrupt chips immutable to
     prevent the GPIO subsystem from modifying it under the hood. This
     provides the necessary infrastructure and converts a set of GPIO
     and pinctrl drivers over.

   - A set of changes to make the pseudo-NMI handling for GICv3 more
     robust: a missing barrier and consistent handling of the priority
     mask.

   - Another set of GICv3 improvements and fixes, but nothing
     outstanding

   - The usual set of improvements and cleanups all over the place

   - No new irqchip drivers and not even a new device tree binding!
     100+ interrupt chips are truly enough"

* tag 'irq-core-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (39 commits)
  irqchip: Add Kconfig symbols for sunxi drivers
  irqchip/gic-v3: Fix priority mask handling
  irqchip/gic-v3: Refactor ISB + EOIR at ack time
  irqchip/gic-v3: Ensure pseudo-NMIs have an ISB between ack and handling
  genirq/irq_sim: Make the irq_work always run in hard irq context
  irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375, A38x, A39x
  irqchip/gic: Improved warning about incorrect type
  irqchip/csky: Return true/false (not 1/0) from bool functions
  irqchip/imx-irqsteer: Add runtime PM support
  irqchip/imx-irqsteer: Constify irq_chip struct
  irqchip/armada-370-xp: Enable MSI affinity configuration
  irqchip/aspeed-scu-ic: Fix irq_of_parse_and_map() return value
  irqchip/aspeed-i2c-ic: Fix irq_of_parse_and_map() return value
  irqchip/sun6i-r: Use NULL for chip_data
  irqchip/xtensa-mx: Fix initial IRQ affinity in non-SMP setup
  irqchip/exiu: Fix acknowledgment of edge triggered interrupts
  irqchip/gic-v3: Claim iomem resources
  dt-bindings: interrupt-controller: arm,gic-v3: Make the v2 compat requirements explicit
  irqchip/gic-v3: Relax polling of GIC{R,D}_CTLR.RWP
  irqchip/gic-v3: Detect LPI invalidation MMIO registers
  ...
parents 28c8f9fe cdb49132
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM Generic Interrupt Controller, version 3

maintainers:
  - Marc Zyngier <marc.zyngier@arm.com>
  - Marc Zyngier <maz@kernel.org>

description: |
  AArch64 SMP cores are often associated with a GICv3, providing Private
@@ -78,7 +78,11 @@ properties:
      - GIC Hypervisor interface (GICH)
      - GIC Virtual CPU interface (GICV)

      GICC, GICH and GICV are optional.
      GICC, GICH and GICV are optional, but must be described if the CPUs
      support them. Examples of such CPUs are ARM's implementations of the
      ARMv8.0 architecture such as Cortex-A32, A34, A35, A53, A57, A72 and
      A73 (this list is not exhaustive).

    minItems: 2
    maxItems: 4096   # Should be enough?

+142 −33
Original line number Diff line number Diff line
@@ -417,30 +417,66 @@ struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
If you do this, the additional irq_chip will be set up by gpiolib at the
same time as setting up the rest of the GPIO functionality. The following
is a typical example of a chained cascaded interrupt handler using
the gpio_irq_chip:
the gpio_irq_chip. Note how the mask/unmask (or disable/enable) functions
call into the core gpiolib code:

.. code-block:: c

  /* Typical state container with dynamic irqchip */
  /* Typical state container */
  struct my_gpio {
      struct gpio_chip gc;
      struct irq_chip irq;
  };

  static void my_gpio_mask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      /*
       * Perform any necessary action to mask the interrupt,
       * and then call into the core code to synchronise the
       * state.
       */

      gpiochip_disable_irq(gc, d->hwirq);
  }

  static void my_gpio_unmask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      gpiochip_enable_irq(gc, d->hwirq);

      /*
       * Perform any necessary action to unmask the interrupt,
       * after having called into the core code to synchronise
       * the state.
       */
  }

  /*
   * Statically populate the irqchip. Note that it is made const
   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
   * callbacks to the structure.
   */
  static const struct irq_chip my_gpio_irq_chip = {
      .name		= "my_gpio_irq",
      .irq_ack		= my_gpio_ack_irq,
      .irq_mask		= my_gpio_mask_irq,
      .irq_unmask	= my_gpio_unmask_irq,
      .irq_set_type	= my_gpio_set_irq_type,
      .flags		= IRQCHIP_IMMUTABLE,
      /* Provide the gpio resource callbacks */
      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };

  int irq; /* from platform etc */
  struct my_gpio *g;
  struct gpio_irq_chip *girq;

  /* Set up the irqchip dynamically */
  g->irq.name = "my_gpio_irq";
  g->irq.irq_ack = my_gpio_ack_irq;
  g->irq.irq_mask = my_gpio_mask_irq;
  g->irq.irq_unmask = my_gpio_unmask_irq;
  g->irq.irq_set_type = my_gpio_set_irq_type;

  /* Get a pointer to the gpio_irq_chip */
  girq = &g->gc.irq;
  girq->chip = &g->irq;
  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
  girq->parent_handler = ftgpio_gpio_irq_handler;
  girq->num_parents = 1;
  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
@@ -458,23 +494,58 @@ the interrupt separately and go with it:

.. code-block:: c

  /* Typical state container with dynamic irqchip */
  /* Typical state container */
  struct my_gpio {
      struct gpio_chip gc;
      struct irq_chip irq;
  };

  static void my_gpio_mask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      /*
       * Perform any necessary action to mask the interrupt,
       * and then call into the core code to synchronise the
       * state.
       */

      gpiochip_disable_irq(gc, d->hwirq);
  }

  static void my_gpio_unmask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      gpiochip_enable_irq(gc, d->hwirq);

      /*
       * Perform any necessary action to unmask the interrupt,
       * after having called into the core code to synchronise
       * the state.
       */
  }

  /*
   * Statically populate the irqchip. Note that it is made const
   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
   * callbacks to the structure.
   */
  static const struct irq_chip my_gpio_irq_chip = {
      .name		= "my_gpio_irq",
      .irq_ack		= my_gpio_ack_irq,
      .irq_mask		= my_gpio_mask_irq,
      .irq_unmask	= my_gpio_unmask_irq,
      .irq_set_type	= my_gpio_set_irq_type,
      .flags		= IRQCHIP_IMMUTABLE,
      /* Provide the gpio resource callbacks */
      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };

  int irq; /* from platform etc */
  struct my_gpio *g;
  struct gpio_irq_chip *girq;

  /* Set up the irqchip dynamically */
  g->irq.name = "my_gpio_irq";
  g->irq.irq_ack = my_gpio_ack_irq;
  g->irq.irq_mask = my_gpio_mask_irq;
  g->irq.irq_unmask = my_gpio_unmask_irq;
  g->irq.irq_set_type = my_gpio_set_irq_type;

  ret = devm_request_threaded_irq(dev, irq, NULL,
		irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
  if (ret < 0)
@@ -482,7 +553,7 @@ the interrupt separately and go with it:

  /* Get a pointer to the gpio_irq_chip */
  girq = &g->gc.irq;
  girq->chip = &g->irq;
  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
  /* This will let us handle the parent IRQ in the driver */
  girq->parent_handler = NULL;
  girq->num_parents = 0;
@@ -500,24 +571,61 @@ In this case the typical set-up will look like this:
  /* Typical state container with dynamic irqchip */
  struct my_gpio {
      struct gpio_chip gc;
      struct irq_chip irq;
      struct fwnode_handle *fwnode;
  };

  int irq; /* from platform etc */
  static void my_gpio_mask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      /*
       * Perform any necessary action to mask the interrupt,
       * and then call into the core code to synchronise the
       * state.
       */

      gpiochip_disable_irq(gc, d->hwirq);
      irq_mask_mask_parent(d);
  }

  static void my_gpio_unmask_irq(struct irq_data *d)
  {
      struct gpio_chip *gc = irq_desc_get_handler_data(d);

      gpiochip_enable_irq(gc, d->hwirq);

      /*
       * Perform any necessary action to unmask the interrupt,
       * after having called into the core code to synchronise
       * the state.
       */

      irq_mask_unmask_parent(d);
  }

  /*
   * Statically populate the irqchip. Note that it is made const
   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
   * callbacks to the structure.
   */
  static const struct irq_chip my_gpio_irq_chip = {
      .name		= "my_gpio_irq",
      .irq_ack		= my_gpio_ack_irq,
      .irq_mask		= my_gpio_mask_irq,
      .irq_unmask	= my_gpio_unmask_irq,
      .irq_set_type	= my_gpio_set_irq_type,
      .flags		= IRQCHIP_IMMUTABLE,
      /* Provide the gpio resource callbacks */
      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };

  struct my_gpio *g;
  struct gpio_irq_chip *girq;

  /* Set up the irqchip dynamically */
  g->irq.name = "my_gpio_irq";
  g->irq.irq_ack = my_gpio_ack_irq;
  g->irq.irq_mask = my_gpio_mask_irq;
  g->irq.irq_unmask = my_gpio_unmask_irq;
  g->irq.irq_set_type = my_gpio_set_irq_type;

  /* Get a pointer to the gpio_irq_chip */
  girq = &g->gc.irq;
  girq->chip = &g->irq;
  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
  girq->default_type = IRQ_TYPE_NONE;
  girq->handler = handle_bad_irq;
  girq->fwnode = g->fwnode;
@@ -605,8 +713,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .irq_disable() and .irq_enable() callbacks from the
irqchip.

When using the gpiolib irqchip helpers, these callbacks are automatically
assigned.
When IRQCHIP_IMMUTABLE is not advertised by the irqchip, these callbacks
are automatically assigned. This behaviour is deprecated and on its way
to be removed from the kernel.


Real-Time compliance for GPIO IRQ chips
+1 −6
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ static inline u32 read_ ## a64(void) \
	return read_sysreg(a32); 		\
}						\

CPUIF_MAP(ICC_EOIR1, ICC_EOIR1_EL1)
CPUIF_MAP(ICC_PMR, ICC_PMR_EL1)
CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1)
CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1)
@@ -63,12 +64,6 @@ CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1)

/* Low-level accessors */

static inline void gic_write_eoir(u32 irq)
{
	write_sysreg(irq, ICC_EOIR1);
	isb();
}

static inline void gic_write_dir(u32 val)
{
	write_sysreg(val, ICC_DIR);
+9 −3
Original line number Diff line number Diff line
@@ -4,10 +4,7 @@ menuconfig ARCH_SUNXI
	depends on ARCH_MULTI_V5 || ARCH_MULTI_V7
	select ARCH_HAS_RESET_CONTROLLER
	select CLKSRC_MMIO
	select GENERIC_IRQ_CHIP
	select GPIOLIB
	select IRQ_DOMAIN_HIERARCHY
	select IRQ_FASTEOI_HIERARCHY_HANDLERS
	select PINCTRL
	select PM_OPP
	select SUN4I_TIMER
@@ -22,10 +19,12 @@ if ARCH_MULTI_V7
config MACH_SUN4I
	bool "Allwinner A10 (sun4i) SoCs support"
	default ARCH_SUNXI
	select SUN4I_INTC

config MACH_SUN5I
	bool "Allwinner A10s / A13 (sun5i) SoCs support"
	default ARCH_SUNXI
	select SUN4I_INTC
	select SUN5I_HSTIMER

config MACH_SUN6I
@@ -34,6 +33,8 @@ config MACH_SUN6I
	select ARM_GIC
	select MFD_SUN6I_PRCM
	select SUN5I_HSTIMER
	select SUN6I_R_INTC
	select SUNXI_NMI_INTC

config MACH_SUN7I
	bool "Allwinner A20 (sun7i) SoCs support"
@@ -43,17 +44,21 @@ config MACH_SUN7I
	select ARCH_SUPPORTS_BIG_ENDIAN
	select HAVE_ARM_ARCH_TIMER
	select SUN5I_HSTIMER
	select SUNXI_NMI_INTC

config MACH_SUN8I
	bool "Allwinner sun8i Family SoCs support"
	default ARCH_SUNXI
	select ARM_GIC
	select MFD_SUN6I_PRCM
	select SUN6I_R_INTC
	select SUNXI_NMI_INTC

config MACH_SUN9I
	bool "Allwinner (sun9i) SoCs support"
	default ARCH_SUNXI
	select ARM_GIC
	select SUNXI_NMI_INTC

config ARCH_SUNXI_MC_SMP
	bool
@@ -69,6 +74,7 @@ if ARCH_MULTI_V5
config MACH_SUNIV
	bool "Allwinner ARMv5 F-series (suniv) SoCs support"
	default ARCH_SUNXI
	select SUN4I_INTC
	help
	  Support for Allwinner suniv ARMv5 SoCs.
	  (F1C100A, F1C100s, F1C200s, F1C500, F1C600)
+3 −3
Original line number Diff line number Diff line
@@ -11,12 +11,11 @@ config ARCH_ACTIONS
config ARCH_SUNXI
	bool "Allwinner sunxi 64-bit SoC Family"
	select ARCH_HAS_RESET_CONTROLLER
	select GENERIC_IRQ_CHIP
	select IRQ_DOMAIN_HIERARCHY
	select IRQ_FASTEOI_HIERARCHY_HANDLERS
	select PINCTRL
	select RESET_CONTROLLER
	select SUN4I_TIMER
	select SUN6I_R_INTC
	select SUNXI_NMI_INTC
	help
	  This enables support for Allwinner sunxi based SoCs like the A64.

@@ -253,6 +252,7 @@ config ARCH_INTEL_SOCFPGA

config ARCH_SYNQUACER
	bool "Socionext SynQuacer SoC Family"
	select IRQ_FASTEOI_HIERARCHY_HANDLERS

config ARCH_TEGRA
	bool "NVIDIA Tegra SoC Family"
Loading