Root/arch/arm/common/uengine.c

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
56u32 ixp2000_uengine_mask;
57
58static 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 */
71u32 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}
88EXPORT_SYMBOL(ixp2000_uengine_csr_read);
89
90void 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}
104EXPORT_SYMBOL(ixp2000_uengine_csr_write);
105
106void 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}
116EXPORT_SYMBOL(ixp2000_uengine_reset);
117
118void 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}
139EXPORT_SYMBOL(ixp2000_uengine_set_mode);
140
141static int make_even_parity(u32 x)
142{
143    return hweight32(x) & 1;
144}
145
146static 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
162void 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}
203EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
204
205void 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}
223EXPORT_SYMBOL(ixp2000_uengine_init_context);
224
225void 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}
236EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
237
238void 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}
250EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
251
252static 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
297static 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
368static 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
429int 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}
450EXPORT_SYMBOL(ixp2000_uengine_load);
451
452
453static 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
507subsys_initcall(ixp2000_uengine_init);
508

Archive Download this file



interactive