On Wed, Jan 21, 2009 at 01:55:41PM -0700, Grant Likely wrote: > From: Grant Likely <grant.lik...@secretlab.ca> > > Rework the mpc5200-pic driver to simplify it and fix up the setting > of desc->status when set_type is called for internal IRQs (so they > are reported as level, not edge). The simplification is due to > splitting off the handling of external IRQs into a separate block > so they don't need to be handled as exceptions in the normal > CRIT, MAIN and PERP paths. > > Signed-off-by: Grant Likely <grant.lik...@secretlab.ca> > CC: Wolfram Sang <w.s...@pengutronix.de>
Can't say much about this one as I have never dealt with the PIC directly so far. Yet, my phyCORE-MPC5200B-tiny behaves normal, so Tested-by: Wolfram Sang <w.s...@pengutronix.de> > --- > > arch/powerpc/platforms/52xx/mpc52xx_pic.c | 145 > ++++++++++++----------------- > 1 files changed, 58 insertions(+), 87 deletions(-) > > > diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c > b/arch/powerpc/platforms/52xx/mpc52xx_pic.c > index c0a9559..277c9c5 100644 > --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c > +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c > @@ -190,10 +190,10 @@ static void mpc52xx_extirq_ack(unsigned int virq) > > static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) > { > - struct irq_desc *desc = get_irq_desc(virq); > u32 ctrl_reg, type; > int irq; > int l2irq; > + void *handler = handle_level_irq; > > irq = irq_map[virq].hwirq; > l2irq = irq & MPC52xx_IRQ_L2_MASK; > @@ -201,32 +201,21 @@ static int mpc52xx_extirq_set_type(unsigned int virq, > unsigned int flow_type) > pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, > flow_type); > > switch (flow_type) { > - case IRQF_TRIGGER_HIGH: > - type = 0; > - break; > - case IRQF_TRIGGER_RISING: > - type = 1; > - break; > - case IRQF_TRIGGER_FALLING: > - type = 2; > - break; > - case IRQF_TRIGGER_LOW: > - type = 3; > - break; > + case IRQF_TRIGGER_HIGH: type = 0; break; > + case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break; > + case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break; > + case IRQF_TRIGGER_LOW: type = 3; break; > default: > type = 0; > } > > - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); > - desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; > - if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) > - desc->status |= IRQ_LEVEL; > - > ctrl_reg = in_be32(&intr->ctrl); > ctrl_reg &= ~(0x3 << (22 - (l2irq * 2))); > ctrl_reg |= (type << (22 - (l2irq * 2))); > out_be32(&intr->ctrl, ctrl_reg); > > + __set_irq_handler_unlocked(virq, handler); > + > return 0; > } > > @@ -241,6 +230,11 @@ static struct irq_chip mpc52xx_extirq_irqchip = { > /* > * Main interrupt irq_chip > */ > +static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type) > +{ > + return 0; /* Do nothing so that the sense mask will get updated */ > +} > + > static void mpc52xx_main_mask(unsigned int virq) > { > int irq; > @@ -268,6 +262,7 @@ static struct irq_chip mpc52xx_main_irqchip = { > .mask = mpc52xx_main_mask, > .mask_ack = mpc52xx_main_mask, > .unmask = mpc52xx_main_unmask, > + .set_type = mpc52xx_null_set_type, > }; > > /* > @@ -300,6 +295,7 @@ static struct irq_chip mpc52xx_periph_irqchip = { > .mask = mpc52xx_periph_mask, > .mask_ack = mpc52xx_periph_mask, > .unmask = mpc52xx_periph_unmask, > + .set_type = mpc52xx_null_set_type, > }; > > /* > @@ -343,9 +339,19 @@ static struct irq_chip mpc52xx_sdma_irqchip = { > .mask = mpc52xx_sdma_mask, > .unmask = mpc52xx_sdma_unmask, > .ack = mpc52xx_sdma_ack, > + .set_type = mpc52xx_null_set_type, > }; > > /** > + * mpc52xx_is_extirq - Returns true if hwirq number is for an external IRQ > + */ > +static int mpc52xx_is_extirq(int l1, int l2) > +{ > + return ((l1 == 0) && (l2 == 0)) || > + ((l1 == 1) && (l2 >= 1) && (l2 <= 3)); > +} > + > +/** > * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts > property > */ > static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, > @@ -363,38 +369,23 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, > struct device_node *ct, > > intrvect_l1 = (int)intspec[0]; > intrvect_l2 = (int)intspec[1]; > - intrvect_type = (int)intspec[2]; > + intrvect_type = (int)intspec[2] & 0x3; > > intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & > MPC52xx_IRQ_L1_MASK; > intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK; > > - pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, > - intrvect_l2); > - > *out_hwirq = intrvect_linux; > - *out_flags = mpc52xx_map_senses[intrvect_type]; > + *out_flags = IRQ_TYPE_LEVEL_LOW; > + if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2)) > + *out_flags = mpc52xx_map_senses[intrvect_type]; > > + pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, > + intrvect_l2); > return 0; > } > > /** > - * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge) > - * > - * Only external IRQs need this. > - */ > -static int mpc52xx_irqx_gettype(int irq) > -{ > - int type; > - u32 ctrl_reg; > - > - ctrl_reg = in_be32(&intr->ctrl); > - type = (ctrl_reg >> (22 - irq * 2)) & 0x3; > - > - return mpc52xx_map_senses[type]; > -} > - > -/** > * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure > */ > static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, > @@ -402,68 +393,46 @@ static int mpc52xx_irqhost_map(struct irq_host *h, > unsigned int virq, > { > int l1irq; > int l2irq; > - struct irq_chip *good_irqchip; > + struct irq_chip *irqchip; > void *good_handle; > int type; > + u32 reg; > > l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; > l2irq = irq & MPC52xx_IRQ_L2_MASK; > > /* > - * Most of ours IRQs will be level low > - * Only external IRQs on some platform may be others > + * External IRQs are handled differently by the hardware so they are > + * handled by a dedicated irq_chip structure. > */ > - type = IRQ_TYPE_LEVEL_LOW; > + if (mpc52xx_is_extirq(l1irq, l2irq)) { > + reg = in_be32(&intr->ctrl); > + type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3]; > + if ((type == IRQ_TYPE_EDGE_FALLING) || > + (type == IRQ_TYPE_EDGE_RISING)) > + good_handle = handle_edge_irq; > + else > + good_handle = handle_level_irq; > + > + set_irq_chip_and_handler(virq, &mpc52xx_extirq_irqchip, > good_handle); > + pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n", > + __func__, l2irq, virq, (int)irq, type); > + return 0; > + } > > + /* It is an internal SOC irq. Choose the correct irq_chip */ > switch (l1irq) { > - case MPC52xx_IRQ_L1_CRIT: > - pr_debug("%s: Critical. l2=%x\n", __func__, l2irq); > - > - BUG_ON(l2irq != 0); > - > - type = mpc52xx_irqx_gettype(l2irq); > - good_irqchip = &mpc52xx_extirq_irqchip; > - break; > - > - case MPC52xx_IRQ_L1_MAIN: > - pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq); > - > - if ((l2irq >= 1) && (l2irq <= 3)) { > - type = mpc52xx_irqx_gettype(l2irq); > - good_irqchip = &mpc52xx_extirq_irqchip; > - } else { > - good_irqchip = &mpc52xx_main_irqchip; > - } > - break; > - > - case MPC52xx_IRQ_L1_PERP: > - pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq); > - good_irqchip = &mpc52xx_periph_irqchip; > - break; > - > - case MPC52xx_IRQ_L1_SDMA: > - pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq); > - good_irqchip = &mpc52xx_sdma_irqchip; > - break; > - > + case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break; > + case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break; > + case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break; > default: > - pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq); > + pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n", > + __func__, virq, l1irq, l2irq); > return -EINVAL; > } > > - switch (type) { > - case IRQ_TYPE_EDGE_FALLING: > - case IRQ_TYPE_EDGE_RISING: > - good_handle = handle_edge_irq; > - break; > - default: > - good_handle = handle_level_irq; > - } > - > - set_irq_chip_and_handler(virq, good_irqchip, good_handle); > - > - pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq, > - (int)irq, type); > + set_irq_chip_and_handler(virq, irqchip, handle_level_irq); > + pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq); > > return 0; > } > @@ -502,6 +471,8 @@ void __init mpc52xx_init_irq(void) > panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " > "Check node !"); > > + pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr); > + > /* Disable all interrupt sources. */ > out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ > out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ > -- Dipl.-Ing. Wolfram Sang | http://www.pengutronix.de Pengutronix - Linux Solutions for Science and Industry
signature.asc
Description: Digital signature
_______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev