Revision f6953f13 hw/etraxfs_eth.c
b/hw/etraxfs_eth.c | ||
---|---|---|
53 | 53 |
|
54 | 54 |
switch (regnum) { |
55 | 55 |
case 1: |
56 |
/* MR1. */
|
|
56 |
/* MR1. */
|
|
57 | 57 |
/* Speeds and modes. */ |
58 | 58 |
r |= (1 << 13) | (1 << 14); |
59 | 59 |
r |= (1 << 11) | (1 << 12); |
60 | 60 |
r |= (1 << 5); /* Autoneg complete. */ |
61 |
r |= (1 << 3); /* Autoneg able. */
|
|
62 |
r |= (1 << 2); /* Link. */
|
|
61 |
r |= (1 << 3); /* Autoneg able. */
|
|
62 |
r |= (1 << 2); /* Link. */
|
|
63 | 63 |
break; |
64 | 64 |
case 5: |
65 | 65 |
/* Link partner ability. |
... | ... | |
123 | 123 |
|
124 | 124 |
struct qemu_mdio |
125 | 125 |
{ |
126 |
/* bus. */
|
|
126 |
/* bus. */
|
|
127 | 127 |
int mdc; |
128 | 128 |
int mdio; |
129 | 129 |
|
... | ... | |
285 | 285 |
|
286 | 286 |
/* ETRAX-FS Ethernet MAC block starts here. */ |
287 | 287 |
|
288 |
#define R_STAT 0x2c |
|
289 |
#define RW_MGM_CTRL 0x28 |
|
290 |
#define FS_ETH_MAX_REGS 0x5c |
|
288 |
#define RW_MA0_LO 0x00 |
|
289 |
#define RW_MA0_HI 0x04 |
|
290 |
#define RW_MA1_LO 0x08 |
|
291 |
#define RW_MA1_HI 0x0c |
|
292 |
#define RW_GA_LO 0x10 |
|
293 |
#define RW_GA_HI 0x14 |
|
294 |
#define RW_GEN_CTRL 0x18 |
|
295 |
#define RW_REC_CTRL 0x1c |
|
296 |
#define RW_TR_CTRL 0x20 |
|
297 |
#define RW_CLR_ERR 0x24 |
|
298 |
#define RW_MGM_CTRL 0x28 |
|
299 |
#define R_STAT 0x2c |
|
300 |
#define FS_ETH_MAX_REGS 0x5c |
|
291 | 301 |
|
292 | 302 |
struct fs_eth |
293 | 303 |
{ |
294 |
CPUState *env;
|
|
304 |
CPUState *env;
|
|
295 | 305 |
qemu_irq *irq; |
296 |
target_phys_addr_t base;
|
|
306 |
target_phys_addr_t base;
|
|
297 | 307 |
VLANClientState *vc; |
298 |
uint8_t macaddr[6]; |
|
299 | 308 |
int ethregs; |
300 | 309 |
|
310 |
/* Two addrs in the filter. */ |
|
311 |
uint8_t macaddr[2][6]; |
|
301 | 312 |
uint32_t regs[FS_ETH_MAX_REGS]; |
302 | 313 |
|
303 | 314 |
unsigned char rx_fifo[1536]; |
... | ... | |
309 | 320 |
|
310 | 321 |
/* MDIO bus. */ |
311 | 322 |
struct qemu_mdio mdio_bus; |
312 |
/* PHY. */
|
|
323 |
/* PHY. */
|
|
313 | 324 |
struct qemu_phy phy; |
314 | 325 |
}; |
315 | 326 |
|
316 | 327 |
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) |
317 | 328 |
{ |
318 |
struct fs_eth *eth = opaque;
|
|
319 |
CPUState *env = eth->env;
|
|
320 |
cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
|
|
321 |
addr, env->pc);
|
|
322 |
return 0;
|
|
329 |
struct fs_eth *eth = opaque;
|
|
330 |
CPUState *env = eth->env;
|
|
331 |
cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
|
|
332 |
addr, env->pc);
|
|
333 |
return 0;
|
|
323 | 334 |
} |
324 | 335 |
|
325 | 336 |
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) |
326 | 337 |
{ |
327 |
struct fs_eth *eth = opaque;
|
|
328 |
D(CPUState *env = eth->env);
|
|
329 |
uint32_t r = 0;
|
|
338 |
struct fs_eth *eth = opaque;
|
|
339 |
D(CPUState *env = eth->env);
|
|
340 |
uint32_t r = 0;
|
|
330 | 341 |
|
331 |
/* Make addr relative to this instances base. */
|
|
332 |
addr -= eth->base;
|
|
333 |
switch (addr) {
|
|
342 |
/* Make addr relative to this instances base. */
|
|
343 |
addr -= eth->base;
|
|
344 |
switch (addr) {
|
|
334 | 345 |
case R_STAT: |
335 | 346 |
/* Attach an MDIO/PHY abstraction. */ |
336 | 347 |
r = eth->mdio_bus.mdio & 1; |
337 | 348 |
break; |
338 |
default:
|
|
349 |
default:
|
|
339 | 350 |
r = eth->regs[addr]; |
340 |
D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
|
|
341 |
break;
|
|
342 |
}
|
|
343 |
return r;
|
|
351 |
D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
|
|
352 |
break;
|
|
353 |
}
|
|
354 |
return r;
|
|
344 | 355 |
} |
345 | 356 |
|
346 | 357 |
static void |
347 | 358 |
eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) |
348 | 359 |
{ |
349 |
struct fs_eth *eth = opaque; |
|
350 |
CPUState *env = eth->env; |
|
351 |
cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", |
|
352 |
addr, env->pc); |
|
360 |
struct fs_eth *eth = opaque; |
|
361 |
CPUState *env = eth->env; |
|
362 |
cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", |
|
363 |
addr, env->pc); |
|
364 |
} |
|
365 |
|
|
366 |
static void eth_update_ma(struct fs_eth *eth, int ma) |
|
367 |
{ |
|
368 |
int reg; |
|
369 |
int i = 0; |
|
370 |
|
|
371 |
ma &= 1; |
|
372 |
|
|
373 |
reg = RW_MA0_LO; |
|
374 |
if (ma) |
|
375 |
reg = RW_MA1_LO; |
|
376 |
|
|
377 |
eth->macaddr[ma][i++] = eth->regs[reg]; |
|
378 |
eth->macaddr[ma][i++] = eth->regs[reg] >> 8; |
|
379 |
eth->macaddr[ma][i++] = eth->regs[reg] >> 16; |
|
380 |
eth->macaddr[ma][i++] = eth->regs[reg] >> 24; |
|
381 |
eth->macaddr[ma][i++] = eth->regs[reg + 4]; |
|
382 |
eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8; |
|
383 |
|
|
384 |
D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, |
|
385 |
eth->macaddr[ma][0], eth->macaddr[ma][1], |
|
386 |
eth->macaddr[ma][2], eth->macaddr[ma][3], |
|
387 |
eth->macaddr[ma][4], eth->macaddr[ma][5])); |
|
353 | 388 |
} |
354 | 389 |
|
355 | 390 |
static void |
356 | 391 |
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
357 | 392 |
{ |
358 |
struct fs_eth *eth = opaque; |
|
359 |
CPUState *env = eth->env; |
|
393 |
struct fs_eth *eth = opaque; |
|
394 |
CPUState *env = eth->env; |
|
395 |
|
|
396 |
/* Make addr relative to this instances base. */ |
|
397 |
addr -= eth->base; |
|
398 |
switch (addr) |
|
399 |
{ |
|
400 |
case RW_MA0_LO: |
|
401 |
eth->regs[addr] = value; |
|
402 |
eth_update_ma(eth, 0); |
|
403 |
break; |
|
404 |
case RW_MA0_HI: |
|
405 |
eth->regs[addr] = value; |
|
406 |
eth_update_ma(eth, 0); |
|
407 |
break; |
|
408 |
case RW_MA1_LO: |
|
409 |
eth->regs[addr] = value; |
|
410 |
eth_update_ma(eth, 1); |
|
411 |
break; |
|
412 |
case RW_MA1_HI: |
|
413 |
eth->regs[addr] = value; |
|
414 |
eth_update_ma(eth, 1); |
|
415 |
break; |
|
360 | 416 |
|
361 |
/* Make addr relative to this instances base. */ |
|
362 |
addr -= eth->base; |
|
363 |
switch (addr) |
|
364 |
{ |
|
365 | 417 |
case RW_MGM_CTRL: |
366 | 418 |
/* Attach an MDIO/PHY abstraction. */ |
367 | 419 |
if (value & 2) |
... | ... | |
371 | 423 |
eth->mdio_bus.mdc = !!(value & 4); |
372 | 424 |
break; |
373 | 425 |
|
374 |
default: |
|
375 |
printf ("%s %x %x pc=%x\n", |
|
376 |
__func__, addr, value, env->pc); |
|
377 |
break; |
|
378 |
} |
|
426 |
default: |
|
427 |
eth->regs[addr] = value; |
|
428 |
printf ("%s %x %x pc=%x\n", |
|
429 |
__func__, addr, value, env->pc); |
|
430 |
break; |
|
431 |
} |
|
432 |
} |
|
433 |
|
|
434 |
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom |
|
435 |
filter dropping group addresses we have not joined. The filter has 64 |
|
436 |
bits (m). The has function is a simple nible xor of the group addr. */ |
|
437 |
static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) |
|
438 |
{ |
|
439 |
unsigned int hsh; |
|
440 |
int m_individual = eth->regs[RW_REC_CTRL] & 4; |
|
441 |
int match; |
|
442 |
|
|
443 |
/* First bit on the wire of a MAC address signals multicast or |
|
444 |
physical address. */ |
|
445 |
if (!m_individual && !sa[0] & 1) |
|
446 |
return 0; |
|
447 |
|
|
448 |
/* Calculate the hash index for the GA registers. */ |
|
449 |
hsh = 0; |
|
450 |
hsh ^= (*sa) & 0x3f; |
|
451 |
hsh ^= ((*sa) >> 6) & 0x03; |
|
452 |
++sa; |
|
453 |
hsh ^= ((*sa) << 2) & 0x03c; |
|
454 |
hsh ^= ((*sa) >> 4) & 0xf; |
|
455 |
++sa; |
|
456 |
hsh ^= ((*sa) << 4) & 0x30; |
|
457 |
hsh ^= ((*sa) >> 2) & 0x3f; |
|
458 |
++sa; |
|
459 |
hsh ^= (*sa) & 0x3f; |
|
460 |
hsh ^= ((*sa) >> 6) & 0x03; |
|
461 |
++sa; |
|
462 |
hsh ^= ((*sa) << 2) & 0x03c; |
|
463 |
hsh ^= ((*sa) >> 4) & 0xf; |
|
464 |
++sa; |
|
465 |
hsh ^= ((*sa) << 4) & 0x30; |
|
466 |
hsh ^= ((*sa) >> 2) & 0x3f; |
|
467 |
|
|
468 |
hsh &= 63; |
|
469 |
if (hsh > 31) |
|
470 |
match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); |
|
471 |
else |
|
472 |
match = eth->regs[RW_GA_LO] & (1 << hsh); |
|
473 |
D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, |
|
474 |
eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); |
|
475 |
return match; |
|
379 | 476 |
} |
380 | 477 |
|
381 | 478 |
static int eth_can_receive(void *opaque) |
... | ... | |
393 | 490 |
|
394 | 491 |
static void eth_receive(void *opaque, const uint8_t *buf, int size) |
395 | 492 |
{ |
493 |
unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
|
396 | 494 |
struct fs_eth *eth = opaque; |
495 |
int use_ma0 = eth->regs[RW_REC_CTRL] & 1; |
|
496 |
int use_ma1 = eth->regs[RW_REC_CTRL] & 2; |
|
497 |
int r_bcast = eth->regs[RW_REC_CTRL] & 8; |
|
498 |
|
|
499 |
if (size < 12) |
|
500 |
return; |
|
501 |
|
|
502 |
D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", |
|
503 |
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], |
|
504 |
use_ma0, use_ma1, r_bcast)); |
|
505 |
|
|
506 |
/* Does the frame get through the address filters? */ |
|
507 |
if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) |
|
508 |
&& (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) |
|
509 |
&& (!r_bcast || memcmp(buf, sa_bcast, 6)) |
|
510 |
&& !eth_match_groupaddr(eth, buf)) |
|
511 |
return; |
|
512 |
|
|
397 | 513 |
if (size > sizeof(eth->rx_fifo)) { |
398 |
/* TODO: signal error. */ |
|
514 |
/* TODO: signal error. */ |
|
515 |
} else if (eth->rx_fifo_len) { |
|
516 |
/* FIFO overrun. */ |
|
399 | 517 |
} else { |
400 | 518 |
memcpy(eth->rx_fifo, buf, size); |
401 |
/* +4, HW passes the CRC to sw. */
|
|
519 |
/* +4, HW passes the CRC to sw. */
|
|
402 | 520 |
eth->rx_fifo_len = size + 4; |
403 | 521 |
eth->rx_fifo_pos = 0; |
404 | 522 |
} |
... | ... | |
471 | 589 |
eth->irq = irq; |
472 | 590 |
eth->dma_out = dma; |
473 | 591 |
eth->dma_in = dma + 1; |
474 |
memcpy(eth->macaddr, nd->macaddr, 6); |
|
475 | 592 |
|
476 | 593 |
/* Connect the phy. */ |
477 | 594 |
tdk_init(ð->phy); |
Also available in: Unified diff