1 /*
2 * Generic library functions for the microengines found on the Intel
3 * IXP2000 series of network processors.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
13
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/module.h>
18 #include <linux/string.h>
19 #include <linux/io.h>
20 #include <mach/hardware.h>
21 #include <asm/hardware/uengine.h>
22
23 #if defined(CONFIG_ARCH_IXP2000)
24 #define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE
25 #define IXP_PRODUCT_ID IXP2000_PRODUCT_ID
26 #define IXP_MISC_CONTROL IXP2000_MISC_CONTROL
27 #define IXP_RESET1 IXP2000_RESET1
28 #else
29 #if defined(CONFIG_ARCH_IXP23XX)
30 #define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE
31 #define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID
32 #define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL
33 #define IXP_RESET1 IXP23XX_RESET1
34 #else
35 #error unknown platform
36 #endif
37 #endif
38
39 #define USTORE_ADDRESS 0x000
40 #define USTORE_DATA_LOWER 0x004
41 #define USTORE_DATA_UPPER 0x008
42 #define CTX_ENABLES 0x018
43 #define CC_ENABLE 0x01c
44 #define CSR_CTX_POINTER 0x020
45 #define INDIRECT_CTX_STS 0x040
46 #define ACTIVE_CTX_STS 0x044
47 #define INDIRECT_CTX_SIG_EVENTS 0x048
48 #define INDIRECT_CTX_WAKEUP_EVENTS 0x050
49 #define NN_PUT 0x080
50 #define NN_GET 0x084
51 #define TIMESTAMP_LOW 0x0c0
52 #define TIMESTAMP_HIGH 0x0c4
53 #define T_INDEX_BYTE_INDEX 0x0f4
54 #define LOCAL_CSR_STATUS 0x180
55
56 u32 ixp2000_uengine_mask;
57
ixp2000_uengine_csr_area(int uengine)58 static void *ixp2000_uengine_csr_area(int uengine)
59 {
60 return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
61 }
62
63 /*
64 * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
65 * space means that the microengine we tried to access was also trying
66 * to access its own CSR space on the same clock cycle as we did. When
67 * this happens, we lose the arbitration process by default, and the
68 * read or write we tried to do was not actually performed, so we try
69 * again until it succeeds.
70 */
ixp2000_uengine_csr_read(int uengine,int offset)71 u32 ixp2000_uengine_csr_read(int uengine, int offset)
72 {
73 void *uebase;
74 u32 *local_csr_status;
75 u32 *reg;
76 u32 value;
77
78 uebase = ixp2000_uengine_csr_area(uengine);
79
80 local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
81 reg = (u32 *)(uebase + offset);
82 do {
83 value = ixp2000_reg_read(reg);
84 } while (ixp2000_reg_read(local_csr_status) & 1);
85
86 return value;
87 }
88 EXPORT_SYMBOL(ixp2000_uengine_csr_read);
89
ixp2000_uengine_csr_write(int uengine,int offset,u32 value)90 void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
91 {
92 void *uebase;
93 u32 *local_csr_status;
94 u32 *reg;
95
96 uebase = ixp2000_uengine_csr_area(uengine);
97
98 local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
99 reg = (u32 *)(uebase + offset);
100 do {
101 ixp2000_reg_write(reg, value);
102 } while (ixp2000_reg_read(local_csr_status) & 1);
103 }
104 EXPORT_SYMBOL(ixp2000_uengine_csr_write);
105
ixp2000_uengine_reset(u32 uengine_mask)106 void ixp2000_uengine_reset(u32 uengine_mask)
107 {
108 u32 value;
109
110 value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask;
111
112 uengine_mask &= ixp2000_uengine_mask;
113 ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask);
114 ixp2000_reg_wrb(IXP_RESET1, value);
115 }
116 EXPORT_SYMBOL(ixp2000_uengine_reset);
117
ixp2000_uengine_set_mode(int uengine,u32 mode)118 void ixp2000_uengine_set_mode(int uengine, u32 mode)
119 {
120 /*
121 * CTL_STR_PAR_EN: unconditionally enable parity checking on
122 * control store.
123 */
124 mode |= 0x10000000;
125 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
126
127 /*
128 * Enable updating of condition codes.
129 */
130 ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
131
132 /*
133 * Initialise other per-microengine registers.
134 */
135 ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
136 ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
137 ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
138 }
139 EXPORT_SYMBOL(ixp2000_uengine_set_mode);
140
make_even_parity(u32 x)141 static int make_even_parity(u32 x)
142 {
143 return hweight32(x) & 1;
144 }
145
ustore_write(int uengine,u64 insn)146 static void ustore_write(int uengine, u64 insn)
147 {
148 /*
149 * Generate even parity for top and bottom 20 bits.
150 */
151 insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
152 insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
153
154 /*
155 * Write to microstore. The second write auto-increments
156 * the USTORE_ADDRESS index register.
157 */
158 ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
159 ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
160 }
161
ixp2000_uengine_load_microcode(int uengine,u8 * ucode,int insns)162 void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
163 {
164 int i;
165
166 /*
167 * Start writing to microstore at address 0.
168 */
169 ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
170 for (i = 0; i < insns; i++) {
171 u64 insn;
172
173 insn = (((u64)ucode[0]) << 32) |
174 (((u64)ucode[1]) << 24) |
175 (((u64)ucode[2]) << 16) |
176 (((u64)ucode[3]) << 8) |
177 ((u64)ucode[4]);
178 ucode += 5;
179
180 ustore_write(uengine, insn);
181 }
182
183 /*
184 * Pad with a few NOPs at the end (to avoid the microengine
185 * aborting as it prefetches beyond the last instruction), unless
186 * we run off the end of the instruction store first, at which
187 * point the address register will wrap back to zero.
188 */
189 for (i = 0; i < 4; i++) {
190 u32 addr;
191
192 addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
193 if (addr == 0x80000000)
194 break;
195 ustore_write(uengine, 0xf0000c0300ULL);
196 }
197
198 /*
199 * End programming.
200 */
201 ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
202 }
203 EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
204
ixp2000_uengine_init_context(int uengine,int context,int pc)205 void ixp2000_uengine_init_context(int uengine, int context, int pc)
206 {
207 /*
208 * Select the right context for indirect access.
209 */
210 ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
211
212 /*
213 * Initialise signal masks to immediately go to Ready state.
214 */
215 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
216 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
217
218 /*
219 * Set program counter.
220 */
221 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
222 }
223 EXPORT_SYMBOL(ixp2000_uengine_init_context);
224
ixp2000_uengine_start_contexts(int uengine,u8 ctx_mask)225 void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
226 {
227 u32 mask;
228
229 /*
230 * Enable the specified context to go to Executing state.
231 */
232 mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
233 mask |= ctx_mask << 8;
234 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
235 }
236 EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
237
ixp2000_uengine_stop_contexts(int uengine,u8 ctx_mask)238 void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
239 {
240 u32 mask;
241
242 /*
243 * Disable the Ready->Executing transition. Note that this
244 * does not stop the context until it voluntarily yields.
245 */
246 mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
247 mask &= ~(ctx_mask << 8);
248 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
249 }
250 EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
251
check_ixp_type(struct ixp2000_uengine_code * c)252 static int check_ixp_type(struct ixp2000_uengine_code *c)
253 {
254 u32 product_id;
255 u32 rev;
256
257 product_id = ixp2000_reg_read(IXP_PRODUCT_ID);
258 if (((product_id >> 16) & 0x1f) != 0)
259 return 0;
260
261 switch ((product_id >> 8) & 0xff) {
262 #ifdef CONFIG_ARCH_IXP2000
263 case 0: /* IXP2800 */
264 if (!(c->cpu_model_bitmask & 4))
265 return 0;
266 break;
267
268 case 1: /* IXP2850 */
269 if (!(c->cpu_model_bitmask & 8))
270 return 0;
271 break;
272
273 case 2: /* IXP2400 */
274 if (!(c->cpu_model_bitmask & 2))
275 return 0;
276 break;
277 #endif
278
279 #ifdef CONFIG_ARCH_IXP23XX
280 case 4: /* IXP23xx */
281 if (!(c->cpu_model_bitmask & 0x3f0))
282 return 0;
283 break;
284 #endif
285
286 default:
287 return 0;
288 }
289
290 rev = product_id & 0xff;
291 if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
292 return 0;
293
294 return 1;
295 }
296
generate_ucode(u8 * ucode,u32 * gpr_a,u32 * gpr_b)297 static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
298 {
299 int offset;
300 int i;
301
302 offset = 0;
303
304 for (i = 0; i < 128; i++) {
305 u8 b3;
306 u8 b2;
307 u8 b1;
308 u8 b0;
309
310 b3 = (gpr_a[i] >> 24) & 0xff;
311 b2 = (gpr_a[i] >> 16) & 0xff;
312 b1 = (gpr_a[i] >> 8) & 0xff;
313 b0 = gpr_a[i] & 0xff;
314
315 /* immed[@ai, (b1 << 8) | b0] */
316 /* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */
317 ucode[offset++] = 0xf0;
318 ucode[offset++] = (b1 >> 4);
319 ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
320 ucode[offset++] = (b0 << 2);
321 ucode[offset++] = 0x80 | i;
322
323 /* immed_w1[@ai, (b3 << 8) | b2] */
324 /* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */
325 ucode[offset++] = 0xf4;
326 ucode[offset++] = 0x40 | (b3 >> 4);
327 ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
328 ucode[offset++] = (b2 << 2);
329 ucode[offset++] = 0x80 | i;
330 }
331
332 for (i = 0; i < 128; i++) {
333 u8 b3;
334 u8 b2;
335 u8 b1;
336 u8 b0;
337
338 b3 = (gpr_b[i] >> 24) & 0xff;
339 b2 = (gpr_b[i] >> 16) & 0xff;
340 b1 = (gpr_b[i] >> 8) & 0xff;
341 b0 = gpr_b[i] & 0xff;
342
343 /* immed[@bi, (b1 << 8) | b0] */
344 /* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */
345 ucode[offset++] = 0xf0;
346 ucode[offset++] = (b1 >> 4);
347 ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
348 ucode[offset++] = (i << 2) | 0x03;
349 ucode[offset++] = b0;
350
351 /* immed_w1[@bi, (b3 << 8) | b2] */
352 /* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */
353 ucode[offset++] = 0xf4;
354 ucode[offset++] = 0x40 | (b3 >> 4);
355 ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
356 ucode[offset++] = (i << 2) | 0x03;
357 ucode[offset++] = b2;
358 }
359
360 /* ctx_arb[kill] */
361 ucode[offset++] = 0xe0;
362 ucode[offset++] = 0x00;
363 ucode[offset++] = 0x01;
364 ucode[offset++] = 0x00;
365 ucode[offset++] = 0x00;
366 }
367
set_initial_registers(int uengine,struct ixp2000_uengine_code * c)368 static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
369 {
370 int per_ctx_regs;
371 u32 *gpr_a;
372 u32 *gpr_b;
373 u8 *ucode;
374 int i;
375
376 gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL);
377 gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL);
378 ucode = kmalloc(513 * 5, GFP_KERNEL);
379 if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
380 kfree(ucode);
381 kfree(gpr_b);
382 kfree(gpr_a);
383 return 1;
384 }
385
386 per_ctx_regs = 16;
387 if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
388 per_ctx_regs = 32;
389
390 for (i = 0; i < 256; i++) {
391 struct ixp2000_reg_value *r = c->initial_reg_values + i;
392 u32 *bank;
393 int inc;
394 int j;
395
396 if (r->reg == -1)
397 break;
398
399 bank = (r->reg & 0x400) ? gpr_b : gpr_a;
400 inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
401
402 j = r->reg & 0x7f;
403 while (j < 128) {
404 bank[j] = r->value;
405 j += inc;
406 }
407 }
408
409 generate_ucode(ucode, gpr_a, gpr_b);
410 ixp2000_uengine_load_microcode(uengine, ucode, 513);
411 ixp2000_uengine_init_context(uengine, 0, 0);
412 ixp2000_uengine_start_contexts(uengine, 0x01);
413 for (i = 0; i < 100; i++) {
414 u32 status;
415
416 status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
417 if (!(status & 0x80000000))
418 break;
419 }
420 ixp2000_uengine_stop_contexts(uengine, 0x01);
421
422 kfree(ucode);
423 kfree(gpr_b);
424 kfree(gpr_a);
425
426 return !!(i == 100);
427 }
428
ixp2000_uengine_load(int uengine,struct ixp2000_uengine_code * c)429 int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
430 {
431 int ctx;
432
433 if (!check_ixp_type(c))
434 return 1;
435
436 if (!(ixp2000_uengine_mask & (1 << uengine)))
437 return 1;
438
439 ixp2000_uengine_reset(1 << uengine);
440 ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
441 if (set_initial_registers(uengine, c))
442 return 1;
443 ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
444
445 for (ctx = 0; ctx < 8; ctx++)
446 ixp2000_uengine_init_context(uengine, ctx, 0);
447
448 return 0;
449 }
450 EXPORT_SYMBOL(ixp2000_uengine_load);
451
452
ixp2000_uengine_init(void)453 static int __init ixp2000_uengine_init(void)
454 {
455 int uengine;
456 u32 value;
457
458 /*
459 * Determine number of microengines present.
460 */
461 switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) {
462 #ifdef CONFIG_ARCH_IXP2000
463 case 0: /* IXP2800 */
464 case 1: /* IXP2850 */
465 ixp2000_uengine_mask = 0x00ff00ff;
466 break;
467
468 case 2: /* IXP2400 */
469 ixp2000_uengine_mask = 0x000f000f;
470 break;
471 #endif
472
473 #ifdef CONFIG_ARCH_IXP23XX
474 case 4: /* IXP23xx */
475 ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf;
476 break;
477 #endif
478
479 default:
480 printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
481 (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID));
482 ixp2000_uengine_mask = 0x00000000;
483 break;
484 }
485
486 /*
487 * Reset microengines.
488 */
489 ixp2000_uengine_reset(ixp2000_uengine_mask);
490
491 /*
492 * Synchronise timestamp counters across all microengines.
493 */
494 value = ixp2000_reg_read(IXP_MISC_CONTROL);
495 ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80);
496 for (uengine = 0; uengine < 32; uengine++) {
497 if (ixp2000_uengine_mask & (1 << uengine)) {
498 ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
499 ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
500 }
501 }
502 ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80);
503
504 return 0;
505 }
506
507 subsys_initcall(ixp2000_uengine_init);
508