Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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