[PATCH] General CHRP/MPC5K2 platform support patch

Nicolas DET nd at bplan-gmbh.de
Sat Oct 28 23:43:29 EST 2006


Subject: Re: [PATCH] General CHRP/MPC5K2 platform support patch
Sent: Sat, 28 Oct 2006
From: "Benjamin Herrenschmidt" <benh at kernel.crashing.org>

> On Fri, 2006-10-27 at 17:04 +0200, Nicolas DET wrote:
> 
> > +static void mpc52xx_ic_mask(unsigned int virq)
> > +{
> > +	u32 val;
> > +	int irq;
> > +	int l1irq;
> > +	int l2irq;
> > +
> > +	irq = irq_map[virq].hwirq;
> > +	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
> > +	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
> > +
> > +	pr_debug("%s: irq=%x. l1=%d, l2=%dn", __func__, irq, l1irq, l2irq);
> > +
> > +	switch (l1irq) {
> > +	case MPC52xx_IRQ_L1_CRIT:
> > +		if (l2irq != 0)
> > +			BUG();
> > +
> > +		val = in_be32(&intr->ctrl);
> > +		val &= ~(1 << 11);
> > +		out_be32(&intr->ctrl, val);
> > +		break;
> > +
> > +	case MPC52xx_IRQ_L1_MAIN:
> > +		if ( (l2irq >= 1) && (l2irq <= 3) ) {
> > +			val = in_be32(&intr->ctrl);
> > +			val &= ~(1 << (11 - l2irq));
> > +			out_be32(&intr->ctrl, val);
> > +		} else {
> > +			val = in_be32(&intr->main_mask);
> > +			val |= 1 << (16 - l2irq);
> > +			out_be32(&intr->main_mask, val);
> > +		}
> > +		break;
> 
> Any reason why you do the above instead o defining two diferent levels
> instead. Also, L1_CRIT would fit in the L1_MAIN case too...
> 
> I don't see the point of having also XXX-l2, just put a bit number in L2
> and be done with it.
> 
> The idea is to streamling the code, such that you can index an array
> with l1irq to get the register, and build a mask. No test, no switch
> case, etc...
> 
> Actually... the most performant way of doing all this is to have a
> different irq_chip (with a different set of ask,mask,unmask) for each
> "L1" so that they get right to the point. But I would settle for an
> array indexed by L1.
> 

Ok. Let's go for the most performant then. So 4 irq_chip for the for type. Each
 is very simple: just clear/set the approprite bit in the appropriate register.



> > +static void mpc52xx_ic_mask_and_ack(unsigned int irq)
> > +{
> > +	mpc52xx_ic_mask(irq);
> > +	mpc52xx_ic_ack(irq);
> > +}
> 
> The above is unnuecessary. The core will call mask and ack.

Ok. Removed.

> > +static struct irq_chip mpc52xx_irqchip = {
> > +	.typename = " MPC52xx  ",
> > +	.mask = mpc52xx_ic_mask,
> > +	.unmask = mpc52xx_ic_unmask,
> > +	.mask_ack = mpc52xx_ic_mask_and_ack,
> > +};
> 
> In the above, you need to provide ack.

Done.

> > +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node
> *node)
> > +{
> > +	pr_debug("%s: %p vs %pn", __func__, find_mpc52xx_picnode(), node);
> > +	return find_mpc52xx_picnode() == node;
> > +}
> 
> Don't redo the whole find all the time. Put the node in your
> irq_host->host_data at init time and compare it there. That way, also,
> find_mpc53xx_picnode() thingy can just stay static to chrp/setup.c. The
> way you did it would be a problem if we had more than one platform using
> 52xx built in the same kernel.
>

done.

> > +static int mpc52xx_islevel(int num)
> > +{
> > +	u32 ictl_req;
> > +	int ictl_type;
> > +
> > +	ictl_req = in_be32(&intr->ctrl);
> > +	ictl_type = (ictl_req >> 16) & 0x3;
> > +
> > +	switch (ictl_type) {
> > +	case 0:
> > +	case 3:
> > +		return 1;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> You only have level/edge settings, not polarity ? Also, you aren't
> giving the user or device-tree the option to set the type manually....
> 
> Ideally, you should use the bits in IRQ_TYPE_SENSE_MASK to fully
> define the irq type/polarity and provide a set_irq_type() callback.
> 
> Also, beware that you cannot call set_irq_chip_and_handler() from within
> set_irq_type() due to a spinlock recursion issue. There is a patch
> floating on the list for IPIC fixing an issue of that sort, you may want
> to have a look.
> 
> In general, look at what others are doing, notably mpic and ipic.

I looked in i8258.c, let's look into others ;-)

> You can also keep IRQ_LEVEL in "sync" with the other polarity bits, it's
> really only useful to display the polarity in /proc/interrupts.
> 
> Note that your map code would always OR the bit, never clear it. It
> should have probably cleared it before the switch/case.


> > +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq)
> > +{
> > +	pr_debug("%s: v=%xn", __func__, virq);
> > +
> > +	mpc52xx_ic_mask(virq);
> > +	set_irq_chip_and_handler(virq, NULL, NULL);
> > +	synchronize_irq(virq);
> > +}
> 
> The common code will do all of the above. Your unmap can be empty. (Or
> just don't do an unmap).
> 

Ok.

> > +static struct irq_host_ops mpc52xx_irqhost_ops = {
> > +	.match = mpc52xx_irqhost_match,
> > +	.xlate = mpc52xx_irqhost_xlate,
> > +	.map = mpc52xx_irqhost_map,
> > +	.unmap = mpc52xx_irqhost_unmap,
> > +};
> > +
> > +void __init mpc52xx_init_irq(void)
> > +{
> > +	int i;
> > +	u32 intr_ctrl;
> > +
> > +	/* Remap the necessary zones */
> > +	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
> > +	sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
> > +
> > +	if ((intr == NULL) || (sdma == NULL))
> > +		panic("Can't ioremap PIC/SDMA register or init_irq !");
> > +
> > +	/* Disable all interrupt sources. */
> > +	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
> > +	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
> > +	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
> > +	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
> > +	intr_ctrl = in_be32(&intr->ctrl);
> > +	intr_ctrl &= 0x00ff0000;	/* Keeps IRQ[0-3] config */
> > +	intr_ctrl |= 0x0f000000 |	/* clear IRQ 0-3 */
> > +	    0x00001000 |	/* MEE master external enable */
> > +	    0x00000000 |	/* 0 means disable IRQ 0-3 */
> > +	    0x00000001;		/* CEb route critical normally */
> > +	out_be32(&intr->ctrl, intr_ctrl);
> > +
> > +	/* Zero a bunch of the priority settings.  */
> > +	out_be32(&intr->per_pri1, 0);
> > +	out_be32(&intr->per_pri2, 0);
> > +	out_be32(&intr->per_pri3, 0);
> > +	out_be32(&intr->main_pri1, 0);
> > +	out_be32(&intr->main_pri2, 0);
> > +	/* Initialize irq_desc[i].handler's with mpc52xx_ic. */
> > +	for (i = 0; i < NR_IRQS; i++) {
> > +		irq_desc[i].chip = &mpc52xx_irqchip;
> > +		irq_desc[i].status = IRQ_LEVEL;
> > +
> > +	}
> 
> The above is completely bogus and should be just removed. You should not
> touch the irq_desc array. You should only ever modify irq_desc's that
> have been assigned to you by your host->map callback.
> 

Ok.

> > +	/*
> > +	 * As last step, add an irq host to translate the real
> > +	 * hw irq information provided by the ofw to linux virq
> > +	 */
> > +
> > +	mpc52xx_irqhost =
> > +	    irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops,
> > +			   -1);
> > +}
> 
> As I said before, NR_IRQ is a poor choice for the size of the revmap.
> You should have a constant somewhere defining what is your max HW irq
> number. and use that +1, or a hw irq count.

Done: 64

Bye



More information about the Linuxppc-embedded mailing list