From 77ae798f5b736dfdc692b86b393d9699052ac77a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 31 Oct 2012 12:01:39 +0000 Subject: MIPS: Netlogic: Support for multi-chip configuration Upto 4 Netlogic XLP SoCs can be connected over ICI links to form a coherent multi-node system. Each SoC has its own set of on-chip devices including PIC. To support this, add a per SoC stucture and use it for the PIC and SYS block addresses instead of using global variables. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4469 Signed-off-by: John Crispin --- arch/mips/netlogic/common/irq.c | 55 +++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'arch/mips/netlogic/common/irq.c') diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index e52bfcbce093..4d6bd8f6ee29 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -70,33 +70,34 @@ */ /* Globals */ -static uint64_t nlm_irq_mask; -static DEFINE_SPINLOCK(nlm_pic_lock); - static void xlp_pic_enable(struct irq_data *d) { unsigned long flags; + struct nlm_soc_info *nodep; int irt; + nodep = nlm_current_node(); irt = nlm_irq_to_irt(d->irq); if (irt == -1) return; - spin_lock_irqsave(&nlm_pic_lock, flags); - nlm_pic_enable_irt(nlm_pic_base, irt); - spin_unlock_irqrestore(&nlm_pic_lock, flags); + spin_lock_irqsave(&nodep->piclock, flags); + nlm_pic_enable_irt(nodep->picbase, irt); + spin_unlock_irqrestore(&nodep->piclock, flags); } static void xlp_pic_disable(struct irq_data *d) { + struct nlm_soc_info *nodep; unsigned long flags; int irt; + nodep = nlm_current_node(); irt = nlm_irq_to_irt(d->irq); if (irt == -1) return; - spin_lock_irqsave(&nlm_pic_lock, flags); - nlm_pic_disable_irt(nlm_pic_base, irt); - spin_unlock_irqrestore(&nlm_pic_lock, flags); + spin_lock_irqsave(&nodep->piclock, flags); + nlm_pic_disable_irt(nodep->picbase, irt); + spin_unlock_irqrestore(&nodep->piclock, flags); } static void xlp_pic_mask_ack(struct irq_data *d) @@ -109,8 +110,10 @@ static void xlp_pic_mask_ack(struct irq_data *d) static void xlp_pic_unmask(struct irq_data *d) { void *hd = irq_data_get_irq_handler_data(d); + struct nlm_soc_info *nodep; int irt; + nodep = nlm_current_node(); irt = nlm_irq_to_irt(d->irq); if (irt == -1) return; @@ -120,7 +123,7 @@ static void xlp_pic_unmask(struct irq_data *d) extra_ack(d); } /* Ack is a single write, no need to lock */ - nlm_pic_ack(nlm_pic_base, irt); + nlm_pic_ack(nodep->picbase, irt); } static struct irq_chip xlp_pic = { @@ -177,7 +180,11 @@ struct irq_chip nlm_cpu_intr = { void __init init_nlm_common_irqs(void) { int i, irq, irt; + uint64_t irqmask; + struct nlm_soc_info *nodep; + nodep = nlm_current_node(); + irqmask = (1ULL << IRQ_TIMER); for (i = 0; i < PIC_IRT_FIRST_IRQ; i++) irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq); @@ -189,7 +196,7 @@ void __init init_nlm_common_irqs(void) nlm_smp_function_ipi_handler); irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, nlm_smp_resched_ipi_handler); - nlm_irq_mask |= + irqmask |= ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); #endif @@ -197,11 +204,11 @@ void __init init_nlm_common_irqs(void) irt = nlm_irq_to_irt(irq); if (irt == -1) continue; - nlm_irq_mask |= (1ULL << irq); - nlm_pic_init_irt(nlm_pic_base, irt, irq, 0); + irqmask |= (1ULL << irq); + nlm_pic_init_irt(nodep->picbase, irt, irq, 0); } - nlm_irq_mask |= (1ULL << IRQ_TIMER); + nodep->irqmask = irqmask; } void __init arch_init_irq(void) @@ -209,29 +216,39 @@ void __init arch_init_irq(void) /* Initialize the irq descriptors */ init_nlm_common_irqs(); - write_c0_eimr(nlm_irq_mask); + write_c0_eimr(nlm_current_node()->irqmask); } void __cpuinit nlm_smp_irq_init(void) { /* set interrupt mask for non-zero cpus */ - write_c0_eimr(nlm_irq_mask); + write_c0_eimr(nlm_current_node()->irqmask); } asmlinkage void plat_irq_dispatch(void) { uint64_t eirr; - int i; + int i, node; + node = nlm_nodeid(); eirr = read_c0_eirr() & read_c0_eimr(); if (eirr & (1 << IRQ_TIMER)) { do_IRQ(IRQ_TIMER); return; } - +#ifdef CONFIG_SMP + if (eirr & IRQ_IPI_SMP_FUNCTION) { + do_IRQ(IRQ_IPI_SMP_FUNCTION); + return; + } + if (eirr & IRQ_IPI_SMP_RESCHEDULE) { + do_IRQ(IRQ_IPI_SMP_RESCHEDULE); + return; + } +#endif i = __ilog2_u64(eirr); if (i == -1) return; - do_IRQ(i); + do_IRQ(nlm_irq_to_xirq(node, i)); } -- cgit v1.2.3 From 38541742da05f65d77e514a70bae9b84251c4bc4 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 31 Oct 2012 12:01:41 +0000 Subject: MIPS: Netlogic: PIC IRQ handling update for multi-chip Create struct nlm_pic_irq for interrupts handled by the PIC. This simplifies IRQ handling for multi-SoC as well as the single SoC cases. Also split the setup of percpu and PIC interrupts so that we can configure the PIC interrupts for every node. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4467 Signed-off-by: John Crispin --- arch/mips/netlogic/common/irq.c | 170 +++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 73 deletions(-) (limited to 'arch/mips/netlogic/common/irq.c') diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 4d6bd8f6ee29..b89d5a6b62cc 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -62,68 +61,66 @@ #else #error "Unknown CPU" #endif -/* - * These are the routines that handle all the low level interrupt stuff. - * Actions handled here are: initialization of the interrupt map, requesting of - * interrupt lines by handlers, dispatching if interrupts to handlers, probing - * for interrupt lines - */ -/* Globals */ +#ifdef CONFIG_SMP +#define SMP_IRQ_MASK ((1ULL << IRQ_IPI_SMP_FUNCTION) | \ + (1ULL << IRQ_IPI_SMP_RESCHEDULE)) +#else +#define SMP_IRQ_MASK 0 +#endif +#define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER)) + + +struct nlm_pic_irq { + void (*extra_ack)(struct irq_data *); + struct nlm_soc_info *node; + int picirq; + int irt; + int flags; +}; + static void xlp_pic_enable(struct irq_data *d) { unsigned long flags; - struct nlm_soc_info *nodep; - int irt; + struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); - nodep = nlm_current_node(); - irt = nlm_irq_to_irt(d->irq); - if (irt == -1) - return; - spin_lock_irqsave(&nodep->piclock, flags); - nlm_pic_enable_irt(nodep->picbase, irt); - spin_unlock_irqrestore(&nodep->piclock, flags); + BUG_ON(!pd); + spin_lock_irqsave(&pd->node->piclock, flags); + nlm_pic_enable_irt(pd->node->picbase, pd->irt); + spin_unlock_irqrestore(&pd->node->piclock, flags); } static void xlp_pic_disable(struct irq_data *d) { - struct nlm_soc_info *nodep; + struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); unsigned long flags; - int irt; - nodep = nlm_current_node(); - irt = nlm_irq_to_irt(d->irq); - if (irt == -1) - return; - spin_lock_irqsave(&nodep->piclock, flags); - nlm_pic_disable_irt(nodep->picbase, irt); - spin_unlock_irqrestore(&nodep->piclock, flags); + BUG_ON(!pd); + spin_lock_irqsave(&pd->node->piclock, flags); + nlm_pic_disable_irt(pd->node->picbase, pd->irt); + spin_unlock_irqrestore(&pd->node->piclock, flags); } static void xlp_pic_mask_ack(struct irq_data *d) { - uint64_t mask = 1ull << d->irq; + struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + uint64_t mask = 1ull << pd->picirq; write_c0_eirr(mask); /* ack by writing EIRR */ } static void xlp_pic_unmask(struct irq_data *d) { - void *hd = irq_data_get_irq_handler_data(d); - struct nlm_soc_info *nodep; - int irt; + struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); - nodep = nlm_current_node(); - irt = nlm_irq_to_irt(d->irq); - if (irt == -1) + if (!pd) return; - if (hd) { - void (*extra_ack)(void *) = hd; - extra_ack(d); - } + if (pd->extra_ack) + pd->extra_ack(d); + /* Ack is a single write, no need to lock */ - nlm_pic_ack(nodep->picbase, irt); + nlm_pic_ack(pd->node->picbase, pd->irt); } static struct irq_chip xlp_pic = { @@ -177,51 +174,84 @@ struct irq_chip nlm_cpu_intr = { .irq_eoi = cpuintr_ack, }; -void __init init_nlm_common_irqs(void) +static void __init nlm_init_percpu_irqs(void) { - int i, irq, irt; - uint64_t irqmask; - struct nlm_soc_info *nodep; + int i; - nodep = nlm_current_node(); - irqmask = (1ULL << IRQ_TIMER); for (i = 0; i < PIC_IRT_FIRST_IRQ; i++) irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq); - - for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++) - irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq); - #ifdef CONFIG_SMP irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, nlm_smp_function_ipi_handler); irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, nlm_smp_resched_ipi_handler); - irqmask |= - ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); #endif +} + +void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) +{ + struct nlm_pic_irq *pic_data; + int xirq; + + xirq = nlm_irq_to_xirq(node, irq); + pic_data = kzalloc(sizeof(*pic_data), GFP_KERNEL); + BUG_ON(pic_data == NULL); + pic_data->irt = irt; + pic_data->picirq = picirq; + pic_data->node = nlm_get_node(node); + irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); + irq_set_handler_data(xirq, pic_data); +} - for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) { - irt = nlm_irq_to_irt(irq); +void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) +{ + struct nlm_pic_irq *pic_data; + int xirq; + + xirq = nlm_irq_to_xirq(node, irq); + pic_data = irq_get_handler_data(xirq); + pic_data->extra_ack = xack; +} + +static void nlm_init_node_irqs(int node) +{ + int i, irt; + uint64_t irqmask; + struct nlm_soc_info *nodep; + + pr_info("Init IRQ for node %d\n", node); + nodep = nlm_get_node(node); + irqmask = PERCPU_IRQ_MASK; + for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) { + irt = nlm_irq_to_irt(i); if (irt == -1) continue; - irqmask |= (1ULL << irq); - nlm_pic_init_irt(nodep->picbase, irt, irq, 0); + nlm_setup_pic_irq(node, i, i, irt); + /* set interrupts to first cpu in node */ + nlm_pic_init_irt(nodep->picbase, irt, i, + node * NLM_CPUS_PER_NODE); + irqmask |= (1ull << i); } - nodep->irqmask = irqmask; } void __init arch_init_irq(void) { /* Initialize the irq descriptors */ - init_nlm_common_irqs(); - + nlm_init_percpu_irqs(); + nlm_init_node_irqs(0); write_c0_eimr(nlm_current_node()->irqmask); } -void __cpuinit nlm_smp_irq_init(void) +void nlm_smp_irq_init(int hwcpuid) { - /* set interrupt mask for non-zero cpus */ + int node, cpu; + + node = hwcpuid / NLM_CPUS_PER_NODE; + cpu = hwcpuid % NLM_CPUS_PER_NODE; + + if (cpu == 0 && node != 0) + nlm_init_node_irqs(node); write_c0_eimr(nlm_current_node()->irqmask); } @@ -232,23 +262,17 @@ asmlinkage void plat_irq_dispatch(void) node = nlm_nodeid(); eirr = read_c0_eirr() & read_c0_eimr(); - if (eirr & (1 << IRQ_TIMER)) { - do_IRQ(IRQ_TIMER); - return; - } -#ifdef CONFIG_SMP - if (eirr & IRQ_IPI_SMP_FUNCTION) { - do_IRQ(IRQ_IPI_SMP_FUNCTION); - return; - } - if (eirr & IRQ_IPI_SMP_RESCHEDULE) { - do_IRQ(IRQ_IPI_SMP_RESCHEDULE); - return; - } -#endif + i = __ilog2_u64(eirr); if (i == -1) return; + /* per-CPU IRQs don't need translation */ + if (eirr & PERCPU_IRQ_MASK) { + do_IRQ(i); + return; + } + + /* top level irq handling */ do_IRQ(nlm_irq_to_xirq(node, i)); } -- cgit v1.2.3 From ed21cfe207276e2d2883173399dd0380db372e18 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Wed, 31 Oct 2012 12:01:42 +0000 Subject: MIPS: Netlogic: Support for XLR/XLS Fast Message Network On XLR/XLS, the cpu cores communicate with fast on-chip devices (e.g. network accelerator, security engine etc.) using the Fast Messaging Network(FMN). The FMN queues and credits needs to be configured and intialized before it can be used. The co-processor 2 on XLR/XLS CPU cores has registers for FMN access, and the XLR/XLS has custom instructions for sending and loading messages. The FMN can deliver also per-cpu interrupts when messages are available at the CPU. This patch adds FMN initialization, adds interrupt setup and handling, and also provides support for sending and receiving FMN messages. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4468 Signed-off-by: John Crispin --- arch/mips/netlogic/common/irq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/mips/netlogic/common/irq.c') diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index b89d5a6b62cc..00dcc7a2bc5a 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -58,6 +58,7 @@ #elif defined(CONFIG_CPU_XLR) #include #include +#include #else #error "Unknown CPU" #endif @@ -68,8 +69,8 @@ #else #define SMP_IRQ_MASK 0 #endif -#define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER)) - +#define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER) | \ + (1ull << IRQ_FMN)) struct nlm_pic_irq { void (*extra_ack)(struct irq_data *); @@ -241,6 +242,9 @@ void __init arch_init_irq(void) nlm_init_percpu_irqs(); nlm_init_node_irqs(0); write_c0_eimr(nlm_current_node()->irqmask); +#if defined(CONFIG_CPU_XLR) + nlm_setup_fmn_irq(); +#endif } void nlm_smp_irq_init(int hwcpuid) -- cgit v1.2.3