• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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