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

Commit 7df2457d authored by Olof Johansson's avatar Olof Johansson Committed by Paul Mackerras
Browse files

[POWERPC] MPIC: support more than 256 sources



Allow more than the default 256 MPIC sources. Allocates a new flag
(MPIC_LARGE_VECTORS) to be used by platform code when instantiating
the mpic.

I picked 11 bits worth right now since it would cover the number of
sources on any hardware I have seen. It can always be increased later
if needed.

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 6529c13d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -130,8 +130,9 @@ static __init void pas_init_IRQ(void)
	openpic_addr = of_read_number(opprop, naddr);
	printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);

	mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0,
			  " PAS-OPIC  ");
	mpic = mpic_alloc(mpic_node, openpic_addr,
			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
			  0, 0, " PAS-OPIC  ");
	BUG_ON(!mpic);

	mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
+42 −22
Original line number Diff line number Diff line
@@ -496,13 +496,18 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
{
	unsigned int src = mpic_irq_to_hw(irq);
	struct mpic *mpic;

	if (irq < NUM_ISA_INTERRUPTS)
		return NULL;

	mpic = irq_desc[irq].chip_data;

	if (is_ipi)
		*is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3);
		*is_ipi = (src >= mpic->ipi_vecs[0] &&
			   src <= mpic->ipi_vecs[3]);

	return irq_desc[irq].chip_data;
	return mpic;
}

/* Convert a cpu mask from logical to physical cpu numbers. */
@@ -540,7 +545,11 @@ static inline void mpic_eoi(struct mpic *mpic)
#ifdef CONFIG_SMP
static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
{
	smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0);
	struct mpic *mpic;

	mpic = mpic_find(irq, NULL);
	smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]);

	return IRQ_HANDLED;
}
#endif /* CONFIG_SMP */
@@ -663,7 +672,7 @@ static void mpic_end_ht_irq(unsigned int irq)
static void mpic_unmask_ipi(unsigned int irq)
{
	struct mpic *mpic = mpic_from_ipi(irq);
	unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0;
	unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0];

	DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
	mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
@@ -807,11 +816,11 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,

	DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);

	if (hw == MPIC_VEC_SPURRIOUS)
	if (hw == mpic->spurious_vec)
		return -EINVAL;

#ifdef CONFIG_SMP
	else if (hw >= MPIC_VEC_IPI_0) {
	else if (hw >= mpic->ipi_vecs[0]) {
		WARN_ON(!(mpic->flags & MPIC_PRIMARY));

		DBG("mpic: mapping as IPI\n");
@@ -904,6 +913,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
	u32		reg;
	const char	*vers;
	int		i;
	int		intvec_top;
	u64		paddr = phys_addr;

	mpic = alloc_bootmem(sizeof(struct mpic));
@@ -914,9 +924,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
	mpic->name = name;
	mpic->of_node = of_node_get(node);

	mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256,
	mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size,
				       &mpic_host_ops,
				       MPIC_VEC_SPURRIOUS);
				       flags & MPIC_LARGE_VECTORS ? 2048 : 256);
	if (mpic->irqhost == NULL) {
		of_node_put(node);
		return NULL;
@@ -944,6 +954,21 @@ struct mpic * __init mpic_alloc(struct device_node *node,
	mpic->irq_count = irq_count;
	mpic->num_sources = 0; /* so far */

	if (flags & MPIC_LARGE_VECTORS)
		intvec_top = 2047;
	else
		intvec_top = 255;

	mpic->timer_vecs[0] = intvec_top - 8;
	mpic->timer_vecs[1] = intvec_top - 7;
	mpic->timer_vecs[2] = intvec_top - 6;
	mpic->timer_vecs[3] = intvec_top - 5;
	mpic->ipi_vecs[0]   = intvec_top - 4;
	mpic->ipi_vecs[1]   = intvec_top - 3;
	mpic->ipi_vecs[2]   = intvec_top - 2;
	mpic->ipi_vecs[3]   = intvec_top - 1;
	mpic->spurious_vec  = intvec_top;

	/* Check for "big-endian" in device-tree */
	if (node && get_property(node, "big-endian", NULL) != NULL)
		mpic->flags |= MPIC_BIG_ENDIAN;
@@ -1084,11 +1109,6 @@ void __init mpic_init(struct mpic *mpic)
	int i;

	BUG_ON(mpic->num_sources == 0);
	WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0);

	/* Sanitize source count */
	if (mpic->num_sources > MPIC_VEC_IPI_0)
		mpic->num_sources = MPIC_VEC_IPI_0;

	printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);

@@ -1104,7 +1124,7 @@ void __init mpic_init(struct mpic *mpic)
			   i * MPIC_INFO(TIMER_STRIDE) +
			   MPIC_INFO(TIMER_VECTOR_PRI),
			   MPIC_VECPRI_MASK |
			   (MPIC_VEC_TIMER_0 + i));
			   (mpic->timer_vecs[0] + i));
	}

	/* Initialize IPIs to our reserved vectors and mark them disabled for now */
@@ -1113,7 +1133,7 @@ void __init mpic_init(struct mpic *mpic)
		mpic_ipi_write(i,
			       MPIC_VECPRI_MASK |
			       (10 << MPIC_VECPRI_PRIORITY_SHIFT) |
			       (MPIC_VEC_IPI_0 + i));
			       (mpic->ipi_vecs[0] + i));
	}

	/* Initialize interrupt sources */
@@ -1136,8 +1156,8 @@ void __init mpic_init(struct mpic *mpic)
			       1 << hard_smp_processor_id());
	}
	
	/* Init spurrious vector */
	mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS);
	/* Init spurious vector */
	mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec);

	/* Disable 8259 passthrough, if supported */
	if (!(mpic->flags & MPIC_NO_PTHROU_DIS))
@@ -1184,9 +1204,9 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)

	spin_lock_irqsave(&mpic_lock, flags);
	if (is_ipi) {
		reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) &
		reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) &
			~MPIC_VECPRI_PRIORITY_MASK;
		mpic_ipi_write(src - MPIC_VEC_IPI_0,
		mpic_ipi_write(src - mpic->ipi_vecs[0],
			       reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
	} else {
		reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
@@ -1207,7 +1227,7 @@ unsigned int mpic_irq_get_priority(unsigned int irq)

	spin_lock_irqsave(&mpic_lock, flags);
	if (is_ipi)
		reg = mpic_ipi_read(src = MPIC_VEC_IPI_0);
		reg = mpic_ipi_read(src = mpic->ipi_vecs[0]);
	else
		reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
	spin_unlock_irqrestore(&mpic_lock, flags);
@@ -1313,7 +1333,7 @@ unsigned int mpic_get_one_irq(struct mpic *mpic)
#ifdef DEBUG_LOW
	DBG("%s: get_one_irq(): %d\n", mpic->name, src);
#endif
	if (unlikely(src == MPIC_VEC_SPURRIOUS))
	if (unlikely(src == mpic->spurious_vec))
		return NO_IRQ;
	return irq_linear_revmap(mpic->irqhost, src);
}
@@ -1345,7 +1365,7 @@ void mpic_request_ipis(void)

	for (i = 0; i < 4; i++) {
		unsigned int vipi = irq_create_mapping(mpic->irqhost,
						       MPIC_VEC_IPI_0 + i);
						       mpic->ipi_vecs[0] + i);
		if (vipi == NO_IRQ) {
			printk(KERN_ERR "Failed to map IPI %d\n", i);
			break;
+9 −15
Original line number Diff line number Diff line
@@ -102,21 +102,6 @@
#define MPIC_MAX_CPUS		32
#define MPIC_MAX_ISU		32

/*
 * Special vector numbers (internal use only)
 */
#define MPIC_VEC_SPURRIOUS	255
#define MPIC_VEC_IPI_3		254
#define MPIC_VEC_IPI_2		253
#define MPIC_VEC_IPI_1		252
#define MPIC_VEC_IPI_0		251

/* unused */
#define MPIC_VEC_TIMER_3	250
#define MPIC_VEC_TIMER_2	249
#define MPIC_VEC_TIMER_1	248
#define MPIC_VEC_TIMER_0	247

/*
 * Tsi108 implementation of MPIC has many differences from the original one
 */
@@ -276,6 +261,13 @@ struct mpic
	unsigned char		*senses;
	unsigned int		senses_count;

	/* vector numbers used for internal sources (ipi/timers) */
	unsigned int		ipi_vecs[4];
	unsigned int		timer_vecs[4];

	/* Spurious vector to program into unused sources */
	unsigned int		spurious_vec;

#ifdef CONFIG_MPIC_BROKEN_U3
	/* The fixup table */
	struct mpic_irq_fixup	*fixups;
@@ -332,6 +324,8 @@ struct mpic
#define MPIC_NO_PTHROU_DIS		0x00000040
/* DCR based MPIC */
#define MPIC_USES_DCR			0x00000080
/* MPIC has 11-bit vector fields (or larger) */
#define MPIC_LARGE_VECTORS		0x00000100

/* MPIC HW modification ID */
#define MPIC_REGSET_MASK		0xf0000000