diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
| -rw-r--r-- | arch/powerpc/sysdev/mpic.c | 121 | 
1 files changed, 62 insertions, 59 deletions
| diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e9ccb1015de..9ac71ebd2c40 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)  	DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",  	    mpic, d->irq, src, flow_type); -	if (src >= mpic->irq_count) +	if (src >= mpic->num_sources)  		return -EINVAL;  	if (flow_type == IRQ_TYPE_NONE) @@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)  	DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",  	    mpic, virq, src, vector); -	if (src >= mpic->irq_count) +	if (src >= mpic->num_sources)  		return;  	vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); @@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid)  	DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",  	    mpic, virq, src, cpuid); -	if (src >= mpic->irq_count) +	if (src >= mpic->num_sources)  		return;  	mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); @@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = {  #endif /* CONFIG_MPIC_U3_HT_IRQS */ -static int mpic_host_match(struct irq_host *h, struct device_node *node) +static int mpic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* Exact match, unless mpic node is NULL */  	return h->of_node == NULL || h->of_node == node;  } -static int mpic_host_map(struct irq_host *h, unsigned int virq, +static int mpic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	struct mpic *mpic = h->host_data; @@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,  		return 0;  	} -	if (hw >= mpic->irq_count) +	if (hw >= mpic->num_sources)  		return -EINVAL;  	mpic_msi_reserve_hwirq(mpic, hw); @@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)  	BUG_ON(!(mpic->flags & MPIC_SECONDARY));  	virq = mpic_get_one_irq(mpic); -	if (virq != NO_IRQ) +	if (virq)  		generic_handle_irq(virq);  	chip->irq_eoi(&desc->irq_data);  } -static struct irq_host_ops mpic_host_ops = { +static struct irq_domain_ops mpic_host_ops = {  	.match = mpic_host_match,  	.map = mpic_host_map,  	.xlate = mpic_host_xlate, @@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	u32 greg_feature;  	const char *vers;  	const u32 *psrc; +	u32 last_irq;  	/* Default MPIC search parameters */  	static const struct of_device_id __initconst mpic_device_id[] = { @@ -1182,6 +1183,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,  		}  	} +	/* Read extra device-tree properties into the flags variable */ +	if (of_get_property(node, "big-endian", NULL)) +		flags |= MPIC_BIG_ENDIAN; +	if (of_get_property(node, "pic-no-reset", NULL)) +		flags |= MPIC_NO_RESET; +	if (of_get_property(node, "single-cpu-affinity", NULL)) +		flags |= MPIC_SINGLE_DEST_CPU; +	if (of_device_is_compatible(node, "fsl,mpic")) +		flags |= MPIC_FSL; +  	mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);  	if (mpic == NULL)  		goto err_of_node_put; @@ -1189,15 +1200,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	mpic->name = name;  	mpic->node = node;  	mpic->paddr = phys_addr; +	mpic->flags = flags;  	mpic->hc_irq = mpic_irq_chip;  	mpic->hc_irq.name = name; -	if (!(flags & MPIC_SECONDARY)) +	if (!(mpic->flags & MPIC_SECONDARY))  		mpic->hc_irq.irq_set_affinity = mpic_set_affinity;  #ifdef CONFIG_MPIC_U3_HT_IRQS  	mpic->hc_ht_irq = mpic_irq_ht_chip;  	mpic->hc_ht_irq.name = name; -	if (!(flags & MPIC_SECONDARY)) +	if (!(mpic->flags & MPIC_SECONDARY))  		mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;  #endif /* CONFIG_MPIC_U3_HT_IRQS */ @@ -1209,12 +1221,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	mpic->hc_tm = mpic_tm_chip;  	mpic->hc_tm.name = name; -	mpic->flags = flags; -	mpic->isu_size = isu_size; -	mpic->irq_count = irq_count;  	mpic->num_sources = 0; /* so far */ -	if (flags & MPIC_LARGE_VECTORS) +	if (mpic->flags & MPIC_LARGE_VECTORS)  		intvec_top = 2047;  	else  		intvec_top = 255; @@ -1233,12 +1242,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	mpic->ipi_vecs[3]   = intvec_top - 1;  	mpic->spurious_vec  = intvec_top; -	/* Check for "big-endian" in device-tree */ -	if (of_get_property(mpic->node, "big-endian", NULL) != NULL) -		mpic->flags |= MPIC_BIG_ENDIAN; -	if (of_device_is_compatible(mpic->node, "fsl,mpic")) -		mpic->flags |= MPIC_FSL; -  	/* Look for protected sources */  	psrc = of_get_property(mpic->node, "protected-sources", &psize);  	if (psrc) { @@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	}  #ifdef CONFIG_MPIC_WEIRD -	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; +	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)];  #endif  	/* default register type */ -	if (flags & MPIC_BIG_ENDIAN) +	if (mpic->flags & MPIC_BIG_ENDIAN)  		mpic->reg_type = mpic_access_mmio_be;  	else  		mpic->reg_type = mpic_access_mmio_le; @@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	 * only if the kernel includes DCR support.  	 */  #ifdef CONFIG_PPC_DCR -	if (flags & MPIC_USES_DCR) +	if (mpic->flags & MPIC_USES_DCR)  		mpic->reg_type = mpic_access_dcr;  #else -	BUG_ON(flags & MPIC_USES_DCR); +	BUG_ON(mpic->flags & MPIC_USES_DCR);  #endif  	/* Map the global registers */ @@ -1283,10 +1286,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	/* When using a device-node, reset requests are only honored if the MPIC  	 * is allowed to reset.  	 */ -	if (of_get_property(mpic->node, "pic-no-reset", NULL)) -		mpic->flags |= MPIC_NO_RESET; - -	if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { +	if (!(mpic->flags & MPIC_NO_RESET)) {  		printk(KERN_DEBUG "mpic: Resetting\n");  		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),  			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) @@ -1297,31 +1297,17 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	}  	/* CoreInt */ -	if (flags & MPIC_ENABLE_COREINT) +	if (mpic->flags & MPIC_ENABLE_COREINT)  		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),  			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))  			   | MPIC_GREG_GCONF_COREINT); -	if (flags & MPIC_ENABLE_MCK) +	if (mpic->flags & MPIC_ENABLE_MCK)  		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),  			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))  			   | 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 (flags & MPIC_BROKEN_FRR_NIRQS) -			mpic->num_sources = mpic->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  	 * can initialize, so we may as well catch that problem here.  	 */ @@ -1336,19 +1322,42 @@ struct mpic * __init mpic_alloc(struct device_node *node,  			 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. +	 * If we get passed an isu_size (multi-isu MPIC) then we use that +	 * as a default instead of the value read from the HW. +	 */ +	last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) +				>> MPIC_GREG_FEATURE_LAST_SRC_SHIFT;	 +	if (isu_size) +		last_irq = isu_size  * MPIC_MAX_ISU - 1; +	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 */ -	if (mpic->isu_size == 0) { -		mpic->isu_size = mpic->num_sources; +	if (!isu_size) { +		isu_size = last_irq + 1; +		mpic->num_sources = isu_size;  		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_mask = (1 << mpic->isu_shift) - 1; -	mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, -				       isu_size ? isu_size : mpic->num_sources, -				       &mpic_host_ops, -				       flags & MPIC_LARGE_VECTORS ? 2048 : 256); +	mpic->irqhost = irq_domain_add_linear(mpic->node, +				       last_irq + 1, +				       &mpic_host_ops, mpic);  	/*  	 * FIXME: The code leaks the MPIC object and mappings here; this @@ -1357,8 +1366,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	if (mpic->irqhost == NULL)  		return NULL; -	mpic->irqhost->host_data = mpic; -  	/* Display version */  	switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {  	case 1: @@ -1383,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	mpic->next = mpics;  	mpics = mpic; -	if (!(flags & MPIC_SECONDARY)) { +	if (!(mpic->flags & MPIC_SECONDARY)) {  		mpic_primary = mpic;  		irq_set_default_host(mpic->irqhost);  	} @@ -1450,10 +1457,6 @@ void __init mpic_init(struct mpic *mpic)  			       (mpic->ipi_vecs[0] + i));  	} -	/* Initialize interrupt sources */ -	if (mpic->irq_count == 0) -		mpic->irq_count = mpic->num_sources; -  	/* Do the HT PIC fixups on U3 broken mpic */  	DBG("MPIC flags: %x\n", mpic->flags);  	if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { | 
