aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/netlogic
diff options
context:
space:
mode:
authorGanesan Ramalingam <ganesanr@broadcom.com>2012-10-31 08:01:42 -0400
committerJohn Crispin <blogic@openwrt.org>2012-11-09 05:37:20 -0500
commited21cfe207276e2d2883173399dd0380db372e18 (patch)
tree99382401195a5163fc6fd2191d786034512aa874 /arch/mips/netlogic
parent38541742da05f65d77e514a70bae9b84251c4bc4 (diff)
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 <ganesanr@broadcom.com> Signed-off-by: Jayachandran C <jchandra@broadcom.com> Patchwork: http://patchwork.linux-mips.org/patch/4468 Signed-off-by: John Crispin <blogic@openwrt.org>
Diffstat (limited to 'arch/mips/netlogic')
-rw-r--r--arch/mips/netlogic/common/irq.c8
-rw-r--r--arch/mips/netlogic/common/smp.c4
-rw-r--r--arch/mips/netlogic/xlp/setup.c4
-rw-r--r--arch/mips/netlogic/xlr/Makefile4
-rw-r--r--arch/mips/netlogic/xlr/fmn-config.c290
-rw-r--r--arch/mips/netlogic/xlr/fmn.c204
-rw-r--r--arch/mips/netlogic/xlr/setup.c9
7 files changed, 516 insertions, 7 deletions
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 @@
58#elif defined(CONFIG_CPU_XLR) 58#elif defined(CONFIG_CPU_XLR)
59#include <asm/netlogic/xlr/iomap.h> 59#include <asm/netlogic/xlr/iomap.h>
60#include <asm/netlogic/xlr/pic.h> 60#include <asm/netlogic/xlr/pic.h>
61#include <asm/netlogic/xlr/fmn.h>
61#else 62#else
62#error "Unknown CPU" 63#error "Unknown CPU"
63#endif 64#endif
@@ -68,8 +69,8 @@
68#else 69#else
69#define SMP_IRQ_MASK 0 70#define SMP_IRQ_MASK 0
70#endif 71#endif
71#define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER)) 72#define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER) | \
72 73 (1ull << IRQ_FMN))
73 74
74struct nlm_pic_irq { 75struct nlm_pic_irq {
75 void (*extra_ack)(struct irq_data *); 76 void (*extra_ack)(struct irq_data *);
@@ -241,6 +242,9 @@ void __init arch_init_irq(void)
241 nlm_init_percpu_irqs(); 242 nlm_init_percpu_irqs();
242 nlm_init_node_irqs(0); 243 nlm_init_node_irqs(0);
243 write_c0_eimr(nlm_current_node()->irqmask); 244 write_c0_eimr(nlm_current_node()->irqmask);
245#if defined(CONFIG_CPU_XLR)
246 nlm_setup_fmn_irq();
247#endif
244} 248}
245 249
246void nlm_smp_irq_init(int hwcpuid) 250void nlm_smp_irq_init(int hwcpuid)
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c
index 0315b298a648..a080d9ee3cd7 100644
--- a/arch/mips/netlogic/common/smp.c
+++ b/arch/mips/netlogic/common/smp.c
@@ -118,6 +118,7 @@ static void __cpuinit nlm_init_secondary(void)
118 118
119 hwtid = hard_smp_processor_id(); 119 hwtid = hard_smp_processor_id();
120 current_cpu_data.core = hwtid / NLM_THREADS_PER_CORE; 120 current_cpu_data.core = hwtid / NLM_THREADS_PER_CORE;
121 nlm_percpu_init(hwtid);
121 nlm_smp_irq_init(hwtid); 122 nlm_smp_irq_init(hwtid);
122} 123}
123 124
@@ -129,9 +130,6 @@ void nlm_prepare_cpus(unsigned int max_cpus)
129 130
130void nlm_smp_finish(void) 131void nlm_smp_finish(void)
131{ 132{
132#ifdef notyet
133 nlm_common_msgring_cpu_init();
134#endif
135 local_irq_enable(); 133 local_irq_enable();
136} 134}
137 135
diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c
index 465b8d60463f..4894d62043ac 100644
--- a/arch/mips/netlogic/xlp/setup.c
+++ b/arch/mips/netlogic/xlp/setup.c
@@ -108,6 +108,10 @@ void xlp_mmu_init(void)
108 (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2))); 108 (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
109} 109}
110 110
111void nlm_percpu_init(int hwcpuid)
112{
113}
114
111void __init prom_init(void) 115void __init prom_init(void)
112{ 116{
113 nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); 117 nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE);
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile
index c287dea87570..05902bc6f080 100644
--- a/arch/mips/netlogic/xlr/Makefile
+++ b/arch/mips/netlogic/xlr/Makefile
@@ -1,2 +1,2 @@
1obj-y += setup.o platform.o platform-flash.o 1obj-y += fmn.o fmn-config.o setup.o platform.o platform-flash.o
2obj-$(CONFIG_SMP) += wakeup.o 2obj-$(CONFIG_SMP) += wakeup.o
diff --git a/arch/mips/netlogic/xlr/fmn-config.c b/arch/mips/netlogic/xlr/fmn-config.c
new file mode 100644
index 000000000000..bed2cffa1008
--- /dev/null
+++ b/arch/mips/netlogic/xlr/fmn-config.c
@@ -0,0 +1,290 @@
1/*
2 * Copyright (c) 2003-2012 Broadcom Corporation
3 * All Rights Reserved
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the Broadcom
9 * license below:
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <asm/cpu-info.h>
36#include <linux/irq.h>
37#include <linux/interrupt.h>
38
39#include <asm/mipsregs.h>
40#include <asm/netlogic/xlr/fmn.h>
41#include <asm/netlogic/xlr/xlr.h>
42#include <asm/netlogic/common.h>
43#include <asm/netlogic/haldefs.h>
44
45struct xlr_board_fmn_config xlr_board_fmn_config;
46
47static void __maybe_unused print_credit_config(struct xlr_fmn_info *fmn_info)
48{
49 int bkt;
50
51 pr_info("Bucket size :\n");
52 pr_info("Station\t: Size\n");
53 for (bkt = 0; bkt < 16; bkt++)
54 pr_info(" %d %d %d %d %d %d %d %d\n",
55 xlr_board_fmn_config.bucket_size[(bkt * 8) + 0],
56 xlr_board_fmn_config.bucket_size[(bkt * 8) + 1],
57 xlr_board_fmn_config.bucket_size[(bkt * 8) + 2],
58 xlr_board_fmn_config.bucket_size[(bkt * 8) + 3],
59 xlr_board_fmn_config.bucket_size[(bkt * 8) + 4],
60 xlr_board_fmn_config.bucket_size[(bkt * 8) + 5],
61 xlr_board_fmn_config.bucket_size[(bkt * 8) + 6],
62 xlr_board_fmn_config.bucket_size[(bkt * 8) + 7]);
63 pr_info("\n");
64
65 pr_info("Credits distribution :\n");
66 pr_info("Station\t: Size\n");
67 for (bkt = 0; bkt < 16; bkt++)
68 pr_info(" %d %d %d %d %d %d %d %d\n",
69 fmn_info->credit_config[(bkt * 8) + 0],
70 fmn_info->credit_config[(bkt * 8) + 1],
71 fmn_info->credit_config[(bkt * 8) + 2],
72 fmn_info->credit_config[(bkt * 8) + 3],
73 fmn_info->credit_config[(bkt * 8) + 4],
74 fmn_info->credit_config[(bkt * 8) + 5],
75 fmn_info->credit_config[(bkt * 8) + 6],
76 fmn_info->credit_config[(bkt * 8) + 7]);
77 pr_info("\n");
78}
79
80static void check_credit_distribution(void)
81{
82 struct xlr_board_fmn_config *cfg = &xlr_board_fmn_config;
83 int bkt, n, total_credits, ncores;
84
85 ncores = hweight32(nlm_current_node()->coremask);
86 for (bkt = 0; bkt < 128; bkt++) {
87 total_credits = 0;
88 for (n = 0; n < ncores; n++)
89 total_credits += cfg->cpu[n].credit_config[bkt];
90 total_credits += cfg->gmac[0].credit_config[bkt];
91 total_credits += cfg->gmac[1].credit_config[bkt];
92 total_credits += cfg->dma.credit_config[bkt];
93 total_credits += cfg->cmp.credit_config[bkt];
94 total_credits += cfg->sae.credit_config[bkt];
95 total_credits += cfg->xgmac[0].credit_config[bkt];
96 total_credits += cfg->xgmac[1].credit_config[bkt];
97 if (total_credits > cfg->bucket_size[bkt])
98 pr_err("ERROR: Bucket %d: credits (%d) > size (%d)\n",
99 bkt, total_credits, cfg->bucket_size[bkt]);
100 }
101 pr_info("Credit distribution complete.\n");
102}
103
104/**
105 * Configure bucket size and credits for a device. 'size' is the size of
106 * the buckets for the device. This size is distributed among all the CPUs
107 * so that all of them can send messages to the device.
108 *
109 * The device is also given 'cpu_credits' to send messages to the CPUs
110 *
111 * @dev_info: FMN information structure for each devices
112 * @start_stn_id: Starting station id of dev_info
113 * @end_stn_id: End station id of dev_info
114 * @num_buckets: Total number of buckets for den_info
115 * @cpu_credits: Allowed credits to cpu for each devices pointing by dev_info
116 * @size: Size of the each buckets in the device station
117 */
118static void setup_fmn_cc(struct xlr_fmn_info *dev_info, int start_stn_id,
119 int end_stn_id, int num_buckets, int cpu_credits, int size)
120{
121 int i, j, num_core, n, credits_per_cpu;
122 struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu;
123
124 num_core = hweight32(nlm_current_node()->coremask);
125 dev_info->num_buckets = num_buckets;
126 dev_info->start_stn_id = start_stn_id;
127 dev_info->end_stn_id = end_stn_id;
128
129 n = num_core;
130 if (num_core == 3)
131 n = 4;
132
133 for (i = start_stn_id; i <= end_stn_id; i++) {
134 xlr_board_fmn_config.bucket_size[i] = size;
135
136 /* Dividing device credits equally to cpus */
137 credits_per_cpu = size / n;
138 for (j = 0; j < num_core; j++)
139 cpu[j].credit_config[i] = credits_per_cpu;
140
141 /* credits left to distribute */
142 credits_per_cpu = size - (credits_per_cpu * num_core);
143
144 /* distribute the remaining credits (if any), among cores */
145 for (j = 0; (j < num_core) && (credits_per_cpu >= 4); j++) {
146 cpu[j].credit_config[i] += 4;
147 credits_per_cpu -= 4;
148 }
149 }
150
151 /* Distributing cpu per bucket credits to devices */
152 for (i = 0; i < num_core; i++) {
153 for (j = 0; j < FMN_CORE_NBUCKETS; j++)
154 dev_info->credit_config[(i * 8) + j] = cpu_credits;
155 }
156}
157
158/*
159 * Each core has 256 slots and 8 buckets,
160 * Configure the 8 buckets each with 32 slots
161 */
162static void setup_cpu_fmninfo(struct xlr_fmn_info *cpu, int num_core)
163{
164 int i, j;
165
166 for (i = 0; i < num_core; i++) {
167 cpu[i].start_stn_id = (8 * i);
168 cpu[i].end_stn_id = (8 * i + 8);
169
170 for (j = cpu[i].start_stn_id; j < cpu[i].end_stn_id; j++)
171 xlr_board_fmn_config.bucket_size[j] = 32;
172 }
173}
174
175/**
176 * Setup the FMN details for each devices according to the device available
177 * in each variant of XLR/XLS processor
178 */
179void xlr_board_info_setup(void)
180{
181 struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu;
182 struct xlr_fmn_info *gmac = xlr_board_fmn_config.gmac;
183 struct xlr_fmn_info *xgmac = xlr_board_fmn_config.xgmac;
184 struct xlr_fmn_info *dma = &xlr_board_fmn_config.dma;
185 struct xlr_fmn_info *cmp = &xlr_board_fmn_config.cmp;
186 struct xlr_fmn_info *sae = &xlr_board_fmn_config.sae;
187 int processor_id, num_core;
188
189 num_core = hweight32(nlm_current_node()->coremask);
190 processor_id = read_c0_prid() & 0xff00;
191
192 setup_cpu_fmninfo(cpu, num_core);
193 switch (processor_id) {
194 case PRID_IMP_NETLOGIC_XLS104:
195 case PRID_IMP_NETLOGIC_XLS108:
196 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
197 FMN_STNID_GMAC0_TX3, 8, 16, 32);
198 setup_fmn_cc(dma, FMN_STNID_DMA_0,
199 FMN_STNID_DMA_3, 4, 8, 64);
200 setup_fmn_cc(sae, FMN_STNID_SEC0,
201 FMN_STNID_SEC1, 2, 8, 128);
202 break;
203
204 case PRID_IMP_NETLOGIC_XLS204:
205 case PRID_IMP_NETLOGIC_XLS208:
206 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
207 FMN_STNID_GMAC0_TX3, 8, 16, 32);
208 setup_fmn_cc(dma, FMN_STNID_DMA_0,
209 FMN_STNID_DMA_3, 4, 8, 64);
210 setup_fmn_cc(sae, FMN_STNID_SEC0,
211 FMN_STNID_SEC1, 2, 8, 128);
212 break;
213
214 case PRID_IMP_NETLOGIC_XLS404:
215 case PRID_IMP_NETLOGIC_XLS408:
216 case PRID_IMP_NETLOGIC_XLS404B:
217 case PRID_IMP_NETLOGIC_XLS408B:
218 case PRID_IMP_NETLOGIC_XLS416B:
219 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
220 FMN_STNID_GMAC0_TX3, 8, 8, 32);
221 setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0,
222 FMN_STNID_GMAC1_TX3, 8, 8, 32);
223 setup_fmn_cc(dma, FMN_STNID_DMA_0,
224 FMN_STNID_DMA_3, 4, 4, 64);
225 setup_fmn_cc(cmp, FMN_STNID_CMP_0,
226 FMN_STNID_CMP_3, 4, 4, 64);
227 setup_fmn_cc(sae, FMN_STNID_SEC0,
228 FMN_STNID_SEC1, 2, 8, 128);
229 break;
230
231 case PRID_IMP_NETLOGIC_XLS412B:
232 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
233 FMN_STNID_GMAC0_TX3, 8, 8, 32);
234 setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0,
235 FMN_STNID_GMAC1_TX3, 8, 8, 32);
236 setup_fmn_cc(dma, FMN_STNID_DMA_0,
237 FMN_STNID_DMA_3, 4, 4, 64);
238 setup_fmn_cc(cmp, FMN_STNID_CMP_0,
239 FMN_STNID_CMP_3, 4, 4, 64);
240 setup_fmn_cc(sae, FMN_STNID_SEC0,
241 FMN_STNID_SEC1, 2, 8, 128);
242 break;
243
244 case PRID_IMP_NETLOGIC_XLR308:
245 case PRID_IMP_NETLOGIC_XLR308C:
246 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
247 FMN_STNID_GMAC0_TX3, 8, 16, 32);
248 setup_fmn_cc(dma, FMN_STNID_DMA_0,
249 FMN_STNID_DMA_3, 4, 8, 64);
250 setup_fmn_cc(sae, FMN_STNID_SEC0,
251 FMN_STNID_SEC1, 2, 4, 128);
252 break;
253
254 case PRID_IMP_NETLOGIC_XLR532:
255 case PRID_IMP_NETLOGIC_XLR532C:
256 case PRID_IMP_NETLOGIC_XLR516C:
257 case PRID_IMP_NETLOGIC_XLR508C:
258 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
259 FMN_STNID_GMAC0_TX3, 8, 16, 32);
260 setup_fmn_cc(dma, FMN_STNID_DMA_0,
261 FMN_STNID_DMA_3, 4, 8, 64);
262 setup_fmn_cc(sae, FMN_STNID_SEC0,
263 FMN_STNID_SEC1, 2, 4, 128);
264 break;
265
266 case PRID_IMP_NETLOGIC_XLR732:
267 case PRID_IMP_NETLOGIC_XLR716:
268 setup_fmn_cc(&xgmac[0], FMN_STNID_XMAC0_00_TX,
269 FMN_STNID_XMAC0_15_TX, 8, 0, 32);
270 setup_fmn_cc(&xgmac[1], FMN_STNID_XMAC1_00_TX,
271 FMN_STNID_XMAC1_15_TX, 8, 0, 32);
272 setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0,
273 FMN_STNID_GMAC0_TX3, 8, 24, 32);
274 setup_fmn_cc(dma, FMN_STNID_DMA_0,
275 FMN_STNID_DMA_3, 4, 4, 64);
276 setup_fmn_cc(sae, FMN_STNID_SEC0,
277 FMN_STNID_SEC1, 2, 4, 128);
278 break;
279 default:
280 pr_err("Unknown CPU with processor ID [%d]\n", processor_id);
281 pr_err("Error: Cannot initialize FMN credits.\n");
282 }
283
284 check_credit_distribution();
285
286#if 0 /* debug */
287 print_credit_config(&cpu[0]);
288 print_credit_config(&gmac[0]);
289#endif
290}
diff --git a/arch/mips/netlogic/xlr/fmn.c b/arch/mips/netlogic/xlr/fmn.c
new file mode 100644
index 000000000000..4d74f03de506
--- /dev/null
+++ b/arch/mips/netlogic/xlr/fmn.c
@@ -0,0 +1,204 @@
1/*
2 * Copyright (c) 2003-2012 Broadcom Corporation
3 * All Rights Reserved
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the Broadcom
9 * license below:
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <linux/kernel.h>
36#include <linux/irqreturn.h>
37#include <linux/irq.h>
38#include <linux/interrupt.h>
39
40#include <asm/mipsregs.h>
41#include <asm/netlogic/interrupt.h>
42#include <asm/netlogic/xlr/fmn.h>
43#include <asm/netlogic/common.h>
44
45#define COP2_CC_INIT_CPU_DEST(dest, conf) \
46do { \
47 nlm_write_c2_cc##dest(0, conf[(dest * 8) + 0]); \
48 nlm_write_c2_cc##dest(1, conf[(dest * 8) + 1]); \
49 nlm_write_c2_cc##dest(2, conf[(dest * 8) + 2]); \
50 nlm_write_c2_cc##dest(3, conf[(dest * 8) + 3]); \
51 nlm_write_c2_cc##dest(4, conf[(dest * 8) + 4]); \
52 nlm_write_c2_cc##dest(5, conf[(dest * 8) + 5]); \
53 nlm_write_c2_cc##dest(6, conf[(dest * 8) + 6]); \
54 nlm_write_c2_cc##dest(7, conf[(dest * 8) + 7]); \
55} while (0)
56
57struct fmn_message_handler {
58 void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *);
59 void *arg;
60} msg_handlers[128];
61
62/*
63 * FMN interrupt handler. We configure the FMN so that any messages in
64 * any of the CPU buckets will trigger an interrupt on the CPU.
65 * The message can be from any device on the FMN (like NAE/SAE/DMA).
66 * The source station id is used to figure out which of the registered
67 * handlers have to be called.
68 */
69static irqreturn_t fmn_message_handler(int irq, void *data)
70{
71 struct fmn_message_handler *hndlr;
72 int bucket, rv;
73 int size = 0, code = 0, src_stnid = 0;
74 struct nlm_fmn_msg msg;
75 uint32_t mflags, bkt_status;
76
77 mflags = nlm_cop2_enable();
78 /* Disable message ring interrupt */
79 nlm_fmn_setup_intr(irq, 0);
80 while (1) {
81 /* 8 bkts per core, [24:31] each bit represents one bucket
82 * Bit is Zero if bucket is not empty */
83 bkt_status = (nlm_read_c2_status() >> 24) & 0xff;
84 if (bkt_status == 0xff)
85 break;
86 for (bucket = 0; bucket < 8; bucket++) {
87 /* Continue on empty bucket */
88 if (bkt_status & (1 << bucket))
89 continue;
90 rv = nlm_fmn_receive(bucket, &size, &code, &src_stnid,
91 &msg);
92 if (rv != 0)
93 continue;
94
95 hndlr = &msg_handlers[src_stnid];
96 if (hndlr->action == NULL)
97 pr_warn("No msgring handler for stnid %d\n",
98 src_stnid);
99 else {
100 nlm_cop2_restore(mflags);
101 hndlr->action(bucket, src_stnid, size, code,
102 &msg, hndlr->arg);
103 mflags = nlm_cop2_enable();
104 }
105 }
106 };
107 /* Enable message ring intr, to any thread in core */
108 nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1);
109 nlm_cop2_restore(mflags);
110 return IRQ_HANDLED;
111}
112
113struct irqaction fmn_irqaction = {
114 .handler = fmn_message_handler,
115 .flags = IRQF_PERCPU,
116 .name = "fmn",
117};
118
119void xlr_percpu_fmn_init(void)
120{
121 struct xlr_fmn_info *cpu_fmn_info;
122 int *bucket_sizes;
123 uint32_t flags;
124 int id;
125
126 BUG_ON(nlm_thread_id() != 0);
127 id = nlm_core_id();
128
129 bucket_sizes = xlr_board_fmn_config.bucket_size;
130 cpu_fmn_info = &xlr_board_fmn_config.cpu[id];
131 flags = nlm_cop2_enable();
132
133 /* Setup bucket sizes for the core. */
134 nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]);
135 nlm_write_c2_bucksize(1, bucket_sizes[id * 8 + 1]);
136 nlm_write_c2_bucksize(2, bucket_sizes[id * 8 + 2]);
137 nlm_write_c2_bucksize(3, bucket_sizes[id * 8 + 3]);
138 nlm_write_c2_bucksize(4, bucket_sizes[id * 8 + 4]);
139 nlm_write_c2_bucksize(5, bucket_sizes[id * 8 + 5]);
140 nlm_write_c2_bucksize(6, bucket_sizes[id * 8 + 6]);
141 nlm_write_c2_bucksize(7, bucket_sizes[id * 8 + 7]);
142
143 /*
144 * For sending FMN messages, we need credits on the destination
145 * bucket. Program the credits this core has on the 128 possible
146 * destination buckets.
147 * We cannot use a loop here, because the the first argument has
148 * to be a constant integer value.
149 */
150 COP2_CC_INIT_CPU_DEST(0, cpu_fmn_info->credit_config);
151 COP2_CC_INIT_CPU_DEST(1, cpu_fmn_info->credit_config);
152 COP2_CC_INIT_CPU_DEST(2, cpu_fmn_info->credit_config);
153 COP2_CC_INIT_CPU_DEST(3, cpu_fmn_info->credit_config);
154 COP2_CC_INIT_CPU_DEST(4, cpu_fmn_info->credit_config);
155 COP2_CC_INIT_CPU_DEST(5, cpu_fmn_info->credit_config);
156 COP2_CC_INIT_CPU_DEST(6, cpu_fmn_info->credit_config);
157 COP2_CC_INIT_CPU_DEST(7, cpu_fmn_info->credit_config);
158 COP2_CC_INIT_CPU_DEST(8, cpu_fmn_info->credit_config);
159 COP2_CC_INIT_CPU_DEST(9, cpu_fmn_info->credit_config);
160 COP2_CC_INIT_CPU_DEST(10, cpu_fmn_info->credit_config);
161 COP2_CC_INIT_CPU_DEST(11, cpu_fmn_info->credit_config);
162 COP2_CC_INIT_CPU_DEST(12, cpu_fmn_info->credit_config);
163 COP2_CC_INIT_CPU_DEST(13, cpu_fmn_info->credit_config);
164 COP2_CC_INIT_CPU_DEST(14, cpu_fmn_info->credit_config);
165 COP2_CC_INIT_CPU_DEST(15, cpu_fmn_info->credit_config);
166
167 /* enable FMN interrupts on this CPU */
168 nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
169 nlm_cop2_restore(flags);
170}
171
172
173/*
174 * Register a FMN message handler with respect to the source station id
175 * @stnid: source station id
176 * @action: Handler function pointer
177 */
178int nlm_register_fmn_handler(int start_stnid, int end_stnid,
179 void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *),
180 void *arg)
181{
182 int sstnid;
183
184 for (sstnid = start_stnid; sstnid <= end_stnid; sstnid++) {
185 msg_handlers[sstnid].arg = arg;
186 smp_wmb();
187 msg_handlers[sstnid].action = action;
188 }
189 pr_debug("Registered FMN msg handler for stnid %d-%d\n",
190 start_stnid, end_stnid);
191 return 0;
192}
193
194void nlm_setup_fmn_irq(void)
195{
196 uint32_t flags;
197
198 /* setup irq only once */
199 setup_irq(IRQ_FMN, &fmn_irqaction);
200
201 flags = nlm_cop2_enable();
202 nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
203 nlm_cop2_restore(flags);
204}
diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c
index 696d4248b92f..4e7f49d3d5a8 100644
--- a/arch/mips/netlogic/xlr/setup.c
+++ b/arch/mips/netlogic/xlr/setup.c
@@ -49,6 +49,7 @@
49#include <asm/netlogic/xlr/iomap.h> 49#include <asm/netlogic/xlr/iomap.h>
50#include <asm/netlogic/xlr/pic.h> 50#include <asm/netlogic/xlr/pic.h>
51#include <asm/netlogic/xlr/gpio.h> 51#include <asm/netlogic/xlr/gpio.h>
52#include <asm/netlogic/xlr/fmn.h>
52 53
53uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE; 54uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE;
54struct psb_info nlm_prom_info; 55struct psb_info nlm_prom_info;
@@ -111,6 +112,12 @@ void __init prom_free_prom_memory(void)
111 /* Nothing yet */ 112 /* Nothing yet */
112} 113}
113 114
115void nlm_percpu_init(int hwcpuid)
116{
117 if (hwcpuid % 4 == 0)
118 xlr_percpu_fmn_init();
119}
120
114static void __init build_arcs_cmdline(int *argv) 121static void __init build_arcs_cmdline(int *argv)
115{ 122{
116 int i, remain, len; 123 int i, remain, len;
@@ -208,4 +215,6 @@ void __init prom_init(void)
208 nlm_wakeup_secondary_cpus(); 215 nlm_wakeup_secondary_cpus();
209 register_smp_ops(&nlm_smp_ops); 216 register_smp_ops(&nlm_smp_ops);
210#endif 217#endif
218 xlr_board_info_setup();
219 xlr_percpu_fmn_init();
211} 220}