[v0 PATCH 1/4] EDAC: MPIC Hypertransport IRQ support
Benjamin Herrenschmidt
benh at kernel.crashing.org
Mon May 18 08:00:23 EST 2009
On Fri, 2009-05-15 at 16:43 +0800, Harry Ciao wrote:
> Support EDAC INT mode for Hypertransport devices, where southbridge
> NMI Request messages posted through Hypertransport Channel will
> be transferred to a MPIC interrupt instance that latches MPIC INT0
> pin. Also, Hypertransport Hostbridge controller may latch MPIC INT2
> pin for Hypertransport Link Errors.
>
> Since multiple Hypertransport southbridges such as AMD8131 & AMD8111
> could post NMI request messages, EDAC core should be responsible
> for maintaining the mapping from hwirq == 0 to a virq.
>
> The edac_mpic_irq.c is inert for EDAC drivers where related hardware
> is not connecting to MPIC, so it should be controlled by CONFIG_MPIC.
It would have been simpler to ajust avoid this layer completely and
always just map the interrupts.
IE. There is no problem with calling irq_create_mapping() for the same
hwirq multiple times, though they aren't refcounted, so just don't call
irq_dispose_mapping() and you're done :-)
IRQ mappings don't need to be disposed of, especially with mpic where
they don't actually occupy resources (the reverse map is of fixed size
anyway).
Ben.
> Signed-off-by: Harry Ciao <qingtao.cao at windriver.com>
> diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
> index 07a31cf..62778ee 100644
> --- a/drivers/edac/Makefile
> +++ b/drivers/edac/Makefile
> @@ -17,6 +17,10 @@ ifdef CONFIG_PCI
> edac_core-objs += edac_pci.o edac_pci_sysfs.o
> endif
>
> +ifdef CONFIG_MPIC
> +edac_core-objs += edac_mpic_irq.o
> +endif
> +
> obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
> obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
> obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
> diff --git a/drivers/edac/edac_mpic_irq.c b/drivers/edac/edac_mpic_irq.c
> new file mode 100644
> index 0000000..26b43c0
> --- /dev/null
> +++ b/drivers/edac/edac_mpic_irq.c
> @@ -0,0 +1,145 @@
> +/*
> + * edac_mpic_irq.c -
> + * For all EDAC Hypertransport southbridge devices(such as AMD8111
> + * or AMD8131) that could post upstream NMI Request Messages, this
> + * driver is used to manage the mapping from the hardware IRQ that
> + * carried in the NMI Request Message to its related virtual IRQ.
> + *
> + * The EDAC driver for a specific Hypertransport southbridge device
> + * must implement its mach-specific method for edac_mach_get_irq().
> + *
> + * Copyright (c) 2009 Wind River Systems, Inc.
> + *
> + * Authors: Cao Qingtao <qingtao.cao at windriver.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> + * See the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/edac.h>
> +
> +struct irqmap {
> + int virq;
> + int count;
> +};
> +
> +static struct irqmap hwirq2virqs[MPIC_HWIRQS] = {
> + [MPIC_HWIRQ_HT_NMI] = {
> + .virq = NO_IRQ,
> + .count = 0,
> + },
> + [MPIC_HWIRQ_INTERNAL_ERROR] = {
> + .virq = NO_IRQ,
> + .count = 0,
> + },
> +};
> +
> +#ifdef CONFIG_PPC_MAPLE
> +static int edac_maple_get_irq(int hwirq)
> +{
> + struct device_node *np, *mpic_node = NULL;
> + int irq = NO_IRQ;
> +
> + /*
> + * Locate MPIC in the device-tree. Note that there is a bug
> + * in Maple device-tree where the type of the controller is
> + * open-pic and not interrupt-controller
> + */
> + for_each_node_by_type(np, "interrupt-controller") {
> + if (of_device_is_compatible(np, "open-pic")) {
> + mpic_node = np;
> + break;
> + }
> + }
> +
> + if (mpic_node == NULL) {
> + for_each_node_by_type(np, "open-pic") {
> + mpic_node = np;
> + break;
> + }
> + }
> +
> + if (mpic_node) {
> + irq = irq_create_of_mapping(mpic_node, &hwirq, 1);
> + of_node_put(mpic_node);
> + } else
> + printk(KERN_ERR "Failed to locate the MPIC DTB node\n");
> +
> + return irq;
> +}
> +#endif
> +
> +/*
> + * NOTE:
> + * The EDAC driver should implement and register its machine-specific
> + * method to get a virtual IRQ here.
> + */
> +static int edac_mach_get_irq(int hwirq)
> +{
> + int virq = NO_IRQ;
> +
> +#ifdef CONFIG_PPC_MAPLE
> + virq = edac_maple_get_irq(hwirq);
> +#endif
> +
> + return virq;
> +}
> +
> +int edac_get_mpic_irq(int hwirq)
> +{
> + struct irqmap *irq;
> +
> + if ((hwirq != MPIC_HWIRQ_HT_NMI) &&
> + (hwirq != MPIC_HWIRQ_INTERNAL_ERROR))
> + return NO_IRQ;
> +
> + irq = &hwirq2virqs[hwirq];
> +
> + if (irq->virq == NO_IRQ) {
> + if (irq->count == 0) {
> + irq->virq = edac_mach_get_irq(hwirq);
> + if (irq->virq != NO_IRQ)
> + irq->count++;
> + else
> + irq->count = -1; /* error */
> + }
> + } else
> + irq->count++;
> +
> + return irq->virq;
> +}
> +EXPORT_SYMBOL_GPL(edac_get_mpic_irq);
> +
> +void edac_put_mpic_irq(int hwirq)
> +{
> + struct irqmap *irq;
> +
> + if ((hwirq != MPIC_HWIRQ_HT_NMI) &&
> + (hwirq != MPIC_HWIRQ_INTERNAL_ERROR))
> + return;
> +
> + irq = &hwirq2virqs[hwirq];
> +
> + if (irq->count <= 0)
> + return;
> +
> + if (--irq->count == 0) {
> + irq_dispose_mapping(irq->virq);
> + irq->virq = NO_IRQ;
> + }
> +}
> +EXPORT_SYMBOL_GPL(edac_put_mpic_irq);
> diff --git a/include/linux/edac.h b/include/linux/edac.h
> index 7cf92e8..804dbb6 100644
> --- a/include/linux/edac.h
> +++ b/include/linux/edac.h
> @@ -38,4 +38,27 @@ static inline void opstate_init(void)
> return;
> }
>
> +#ifdef CONFIG_MPIC
> +enum {
> + /*
> + * Vector carried in southbridge NMI Request Messages
> + * posted through Hypertransport Channel
> + */
> + MPIC_HWIRQ_HT_NMI = 0,
> +
> + /*
> + * Vector for MPIC Internal Error
> + */
> + MPIC_HWIRQ_INTERNAL_ERROR = 2,
> +
> + MPIC_HWIRQS, /* must be the very last */
> +};
> +
> +/* Create a hwirq2virq mapping for the specified hwirq */
> +extern int edac_get_mpic_irq(int hwirq);
> +
> +/* Dispose the hwirq2virq mapping for the specified hwirq */
> +extern void edac_put_mpic_irq(int hwirq);
> +#endif
> +
> #endif
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list