Revision 7b8737de hw/eepro100.c
b/hw/eepro100.c | ||
---|---|---|
140 | 140 |
uint16_t status; |
141 | 141 |
uint16_t command; |
142 | 142 |
uint32_t link; /* void * */ |
143 |
uint32_t tx_desc_addr; /* transmit buffer decsriptor array address. */
|
|
143 |
uint32_t tbd_array_addr; /* transmit buffer descriptor array address. */
|
|
144 | 144 |
uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */ |
145 | 145 |
uint8_t tx_threshold; /* transmit threshold */ |
146 | 146 |
uint8_t tbd_count; /* TBD number */ |
... | ... | |
267 | 267 |
|
268 | 268 |
/* From FreeBSD */ |
269 | 269 |
/* XXX: optimize */ |
270 |
static int compute_mcast_idx(const uint8_t * ep)
|
|
270 |
static unsigned compute_mcast_idx(const uint8_t * ep)
|
|
271 | 271 |
{ |
272 | 272 |
uint32_t crc; |
273 | 273 |
int carry, i, j; |
... | ... | |
285 | 285 |
} |
286 | 286 |
} |
287 | 287 |
} |
288 |
return (crc >> 26);
|
|
288 |
return (crc & BITS(7, 2)) >> 2;
|
|
289 | 289 |
} |
290 | 290 |
|
291 | 291 |
#if defined(DEBUG_EEPRO100) |
... | ... | |
648 | 648 |
{ |
649 | 649 |
EEPRO100State *s = opaque; |
650 | 650 |
TRACE(OTHER, logout("%p\n", s)); |
651 |
/* TODO: Clearing of multicast table for selective reset, too? */ |
|
652 |
memset(&s->mult[0], 0, sizeof(s->mult)); |
|
651 | 653 |
nic_selective_reset(s); |
652 | 654 |
} |
653 | 655 |
|
... | ... | |
767 | 769 |
|
768 | 770 |
static void tx_command(EEPRO100State *s) |
769 | 771 |
{ |
770 |
uint32_t tbd_array = le32_to_cpu(s->tx.tx_desc_addr);
|
|
772 |
uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
|
|
771 | 773 |
uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff); |
772 | 774 |
/* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */ |
773 | 775 |
uint8_t buf[2600]; |
... | ... | |
849 | 851 |
//~ eepro100_cx_interrupt(s); |
850 | 852 |
} |
851 | 853 |
|
854 |
static void set_multicast_list(EEPRO100State *s) |
|
855 |
{ |
|
856 |
uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0); |
|
857 |
uint16_t i; |
|
858 |
memset(&s->mult[0], 0, sizeof(s->mult)); |
|
859 |
TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count)); |
|
860 |
for (i = 0; i < multicast_count; i += 6) { |
|
861 |
uint8_t multicast_addr[6]; |
|
862 |
cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6); |
|
863 |
TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6))); |
|
864 |
unsigned mcast_idx = compute_mcast_idx(multicast_addr); |
|
865 |
assert(mcast_idx < 64); |
|
866 |
s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7)); |
|
867 |
} |
|
868 |
} |
|
869 |
|
|
852 | 870 |
static void action_command(EEPRO100State *s) |
853 | 871 |
{ |
854 | 872 |
for (;;) { |
... | ... | |
881 | 899 |
TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16))); |
882 | 900 |
break; |
883 | 901 |
case CmdMulticastList: |
884 |
//~ missing("multicast list");
|
|
902 |
set_multicast_list(s);
|
|
885 | 903 |
break; |
886 | 904 |
case CmdTx: |
887 | 905 |
if (bit_nc) { |
... | ... | |
1664 | 1682 |
/* Broadcast frame. */ |
1665 | 1683 |
TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size)); |
1666 | 1684 |
rfd_status |= 0x0002; |
1667 |
} else if (buf[0] & 0x01) { // !!!
|
|
1685 |
} else if (buf[0] & 0x01) { |
|
1668 | 1686 |
/* Multicast frame. */ |
1669 |
TRACE(RXTX, logout("%p received multicast, len=%zu\n", s, size)); |
|
1670 |
/* TODO: check multicast all bit. */ |
|
1687 |
TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size))); |
|
1671 | 1688 |
if (s->configuration[21] & BIT(3)) { |
1672 |
missing("Multicast All bit"); |
|
1673 |
} |
|
1674 |
int mcast_idx = compute_mcast_idx(buf); |
|
1675 |
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { |
|
1676 |
return size; |
|
1689 |
/* Multicast all bit is set, receive all multicast frames. */ |
|
1690 |
} else { |
|
1691 |
unsigned mcast_idx = compute_mcast_idx(buf); |
|
1692 |
assert(mcast_idx < 64); |
|
1693 |
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) { |
|
1694 |
/* Multicast frame is allowed in hash table. */ |
|
1695 |
} else if (s->configuration[15] & 1) { |
|
1696 |
/* Promiscuous: receive all. */ |
|
1697 |
rfd_status |= 0x0004; |
|
1698 |
} else { |
|
1699 |
TRACE(RXTX, logout("%p multicast ignored\n", s)); |
|
1700 |
return -1; |
|
1701 |
} |
|
1677 | 1702 |
} |
1703 |
/* TODO: Next not for promiscuous mode? */ |
|
1678 | 1704 |
rfd_status |= 0x0002; |
1679 | 1705 |
} else if (s->configuration[15] & 1) { |
1680 | 1706 |
/* Promiscuous: receive all. */ |
Also available in: Unified diff