Commit f6953f1345daeea02986fcb78d19f4727bf9992c

Authored by edgar_igl
1 parent 57e49b40

ETRAX: Add support for the ethernet receivers dest addr filters.

* Support the station address filters MA0 and MA1.
* Model the group address bloom filter.
* Indentation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4487 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 162 additions and 45 deletions
hw/etraxfs_eth.c
@@ -53,13 +53,13 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) @@ -53,13 +53,13 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
53 53
54 switch (regnum) { 54 switch (regnum) {
55 case 1: 55 case 1:
56 - /* MR1. */ 56 + /* MR1. */
57 /* Speeds and modes. */ 57 /* Speeds and modes. */
58 r |= (1 << 13) | (1 << 14); 58 r |= (1 << 13) | (1 << 14);
59 r |= (1 << 11) | (1 << 12); 59 r |= (1 << 11) | (1 << 12);
60 r |= (1 << 5); /* Autoneg complete. */ 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 break; 63 break;
64 case 5: 64 case 5:
65 /* Link partner ability. 65 /* Link partner ability.
@@ -123,7 +123,7 @@ tdk_init(struct qemu_phy *phy) @@ -123,7 +123,7 @@ tdk_init(struct qemu_phy *phy)
123 123
124 struct qemu_mdio 124 struct qemu_mdio
125 { 125 {
126 - /* bus. */ 126 + /* bus. */
127 int mdc; 127 int mdc;
128 int mdio; 128 int mdio;
129 129
@@ -285,19 +285,30 @@ static void mdio_cycle(struct qemu_mdio *bus) @@ -285,19 +285,30 @@ static void mdio_cycle(struct qemu_mdio *bus)
285 285
286 /* ETRAX-FS Ethernet MAC block starts here. */ 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 struct fs_eth 302 struct fs_eth
293 { 303 {
294 - CPUState *env; 304 + CPUState *env;
295 qemu_irq *irq; 305 qemu_irq *irq;
296 - target_phys_addr_t base; 306 + target_phys_addr_t base;
297 VLANClientState *vc; 307 VLANClientState *vc;
298 - uint8_t macaddr[6];  
299 int ethregs; 308 int ethregs;
300 309
  310 + /* Two addrs in the filter. */
  311 + uint8_t macaddr[2][6];
301 uint32_t regs[FS_ETH_MAX_REGS]; 312 uint32_t regs[FS_ETH_MAX_REGS];
302 313
303 unsigned char rx_fifo[1536]; 314 unsigned char rx_fifo[1536];
@@ -309,59 +320,100 @@ struct fs_eth @@ -309,59 +320,100 @@ struct fs_eth
309 320
310 /* MDIO bus. */ 321 /* MDIO bus. */
311 struct qemu_mdio mdio_bus; 322 struct qemu_mdio mdio_bus;
312 - /* PHY. */ 323 + /* PHY. */
313 struct qemu_phy phy; 324 struct qemu_phy phy;
314 }; 325 };
315 326
316 static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) 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 static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) 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 case R_STAT: 345 case R_STAT:
335 /* Attach an MDIO/PHY abstraction. */ 346 /* Attach an MDIO/PHY abstraction. */
336 r = eth->mdio_bus.mdio & 1; 347 r = eth->mdio_bus.mdio & 1;
337 break; 348 break;
338 - default: 349 + default:
339 r = eth->regs[addr]; 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 static void 357 static void
347 eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) 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 static void 390 static void
356 eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) 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 case RW_MGM_CTRL: 417 case RW_MGM_CTRL:
366 /* Attach an MDIO/PHY abstraction. */ 418 /* Attach an MDIO/PHY abstraction. */
367 if (value & 2) 419 if (value & 2)
@@ -371,11 +423,56 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -371,11 +423,56 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
371 eth->mdio_bus.mdc = !!(value & 4); 423 eth->mdio_bus.mdc = !!(value & 4);
372 break; 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 static int eth_can_receive(void *opaque) 478 static int eth_can_receive(void *opaque)
@@ -393,12 +490,33 @@ static int eth_can_receive(void *opaque) @@ -393,12 +490,33 @@ static int eth_can_receive(void *opaque)
393 490
394 static void eth_receive(void *opaque, const uint8_t *buf, int size) 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 struct fs_eth *eth = opaque; 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 if (size > sizeof(eth->rx_fifo)) { 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 } else { 517 } else {
400 memcpy(eth->rx_fifo, buf, size); 518 memcpy(eth->rx_fifo, buf, size);
401 - /* +4, HW passes the CRC to sw. */ 519 + /* +4, HW passes the CRC to sw. */
402 eth->rx_fifo_len = size + 4; 520 eth->rx_fifo_len = size + 4;
403 eth->rx_fifo_pos = 0; 521 eth->rx_fifo_pos = 0;
404 } 522 }
@@ -471,7 +589,6 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, @@ -471,7 +589,6 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
471 eth->irq = irq; 589 eth->irq = irq;
472 eth->dma_out = dma; 590 eth->dma_out = dma;
473 eth->dma_in = dma + 1; 591 eth->dma_in = dma + 1;
474 - memcpy(eth->macaddr, nd->macaddr, 6);  
475 592
476 /* Connect the phy. */ 593 /* Connect the phy. */
477 tdk_init(&eth->phy); 594 tdk_init(&eth->phy);