Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1b8d45d authored by Kyle Moffett's avatar Kyle Moffett Committed by Benjamin Herrenschmidt
Browse files

powerpc/mpic: Add "last-interrupt-source" property to override hardware



The FreeScale PowerQUICC-III-compatible (mpc85xx/mpc86xx) MPICs do not
correctly report the number of hardware interrupt sources, so software
needs to override the detected value with "256".

To avoid needing to write custom board-specific code to detect that
scenario, allow it to be easily overridden in the device-tree.

Signed-off-by: default avatarKyle Moffett <Kyle.D.Moffett@boeing.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 5019609f
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,13 @@ PROPERTIES
          If present the MPIC will be assumed to only be able to route
          If present the MPIC will be assumed to only be able to route
          non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC).
          non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC).


  - last-interrupt-source
      Usage: optional
      Value type: <u32>
          Some MPICs do not correctly report the number of hardware sources
          in the global feature registers.  If specified, this field will
          override the value read from MPIC_GREG_FEATURE_LAST_SRC.

INTERRUPT SPECIFIER DEFINITION
INTERRUPT SPECIFIER DEFINITION


  Interrupt specifiers consists of 4 cells encoded as
  Interrupt specifiers consists of 4 cells encoded as
+1 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ mpic: pic@40000 {
	device_type = "open-pic";
	device_type = "open-pic";
	big-endian;
	big-endian;
	single-cpu-affinity;
	single-cpu-affinity;
	last-interrupt-source = <255>;
};
};


timer@41100 {
timer@41100 {
+26 −20
Original line number Original line Diff line number Diff line
@@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
	u32 greg_feature;
	u32 greg_feature;
	const char *vers;
	const char *vers;
	const u32 *psrc;
	const u32 *psrc;
	u32 last_irq;


	/* Default MPIC search parameters */
	/* Default MPIC search parameters */
	static const struct of_device_id __initconst mpic_device_id[] = {
	static const struct of_device_id __initconst mpic_device_id[] = {
@@ -1220,7 +1221,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
	mpic->hc_tm = mpic_tm_chip;
	mpic->hc_tm = mpic_tm_chip;
	mpic->hc_tm.name = name;
	mpic->hc_tm.name = name;


	mpic->isu_size = isu_size;
	mpic->num_sources = 0; /* so far */
	mpic->num_sources = 0; /* so far */


	if (mpic->flags & MPIC_LARGE_VECTORS)
	if (mpic->flags & MPIC_LARGE_VECTORS)
@@ -1307,20 +1307,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
			   | MPIC_GREG_GCONF_MCK);
			   | MPIC_GREG_GCONF_MCK);


	/*
	 * Read feature register.  For non-ISU MPICs, num sources as well. On
	 * ISU MPICs, sources are counted as ISUs are added
	 */
	greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
	if (isu_size == 0) {
		if (irq_count)
			mpic->num_sources = irq_count;
		else
			mpic->num_sources =
				((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
				 >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
	}

	/*
	/*
	 * The MPIC driver will crash if there are more cores than we
	 * The MPIC driver will crash if there are more cores than we
	 * can initialize, so we may as well catch that problem here.
	 * can initialize, so we may as well catch that problem here.
@@ -1336,18 +1322,38 @@ struct mpic * __init mpic_alloc(struct device_node *node,
			 0x1000);
			 0x1000);
	}
	}


	/*
	 * Read feature register.  For non-ISU MPICs, num sources as well. On
	 * ISU MPICs, sources are counted as ISUs are added
	 */
	greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));

	/*
	 * By default, the last source number comes from the MPIC, but the
	 * device-tree and board support code can override it on buggy hw.
	 */
	last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
				>> MPIC_GREG_FEATURE_LAST_SRC_SHIFT;
	of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq);
	if (irq_count)
		last_irq = irq_count - 1;

	/* Initialize main ISU if none provided */
	/* Initialize main ISU if none provided */
	if (mpic->isu_size == 0) {
	if (!isu_size) {
		mpic->isu_size = mpic->num_sources;
		isu_size = last_irq + 1;
		mpic->num_sources = isu_size;
		mpic_map(mpic, mpic->paddr, &mpic->isus[0],
		mpic_map(mpic, mpic->paddr, &mpic->isus[0],
			 MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
				MPIC_INFO(IRQ_BASE),
				MPIC_INFO(IRQ_STRIDE) * isu_size);
	}
	}

	mpic->isu_size = isu_size;
	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
	mpic->isu_mask = (1 << mpic->isu_shift) - 1;
	mpic->isu_mask = (1 << mpic->isu_shift) - 1;


	mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR,
	mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR,
				       isu_size ? isu_size : mpic->num_sources,
				       mpic->isu_size, &mpic_host_ops,
				       &mpic_host_ops, intvec_top + 1);
				       intvec_top + 1);


	/*
	/*
	 * FIXME: The code leaks the MPIC object and mappings here; this
	 * FIXME: The code leaks the MPIC object and mappings here; this