diff options
-rw-r--r-- | hw/etraxfs_eth.c | 922 |
1 files changed, 466 insertions, 456 deletions
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ec23fa6edf..0b474c0843 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -35,582 +35,592 @@ #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -/* - * The MDIO extensions in the TDK PHY model were reversed engineered from the +/* + * The MDIO extensions in the TDK PHY model were reversed engineered from the * linux driver (PHYID and Diagnostics reg). * TODO: Add friendly names for the register nums. */ struct qemu_phy { - uint32_t regs[32]; + uint32_t regs[32]; - int link; + int link; - unsigned int (*read)(struct qemu_phy *phy, unsigned int req); - void (*write)(struct qemu_phy *phy, unsigned int req, - unsigned int data); + unsigned int (*read)(struct qemu_phy *phy, unsigned int req); + void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); }; static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) { - int regnum; - unsigned r = 0; - - regnum = req & 0x1f; - - switch (regnum) { - case 1: - if (!phy->link) - break; - /* MR1. */ - /* Speeds and modes. */ - r |= (1 << 13) | (1 << 14); - r |= (1 << 11) | (1 << 12); - r |= (1 << 5); /* Autoneg complete. */ - r |= (1 << 3); /* Autoneg able. */ - r |= (1 << 2); /* link. */ - break; - case 5: - /* Link partner ability. - We are kind; always agree with whatever best mode - the guest advertises. */ - r = 1 << 14; /* Success. */ - /* Copy advertised modes. */ - r |= phy->regs[4] & (15 << 5); - /* Autoneg support. */ - r |= 1; - break; - case 18: - { - /* Diagnostics reg. */ - int duplex = 0; - int speed_100 = 0; - - if (!phy->link) - break; - - /* Are we advertising 100 half or 100 duplex ? */ - speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); - speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); - - /* Are we advertising 10 duplex or 100 duplex ? */ - duplex = !!(phy->regs[4] & ADVERTISE_100FULL); - duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); - r = (speed_100 << 10) | (duplex << 11); - } - break; - - default: - r = phy->regs[regnum]; - break; - } - D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); - return r; + int regnum; + unsigned r = 0; + + regnum = req & 0x1f; + + switch (regnum) { + case 1: + if (!phy->link) { + break; + } + /* MR1. */ + /* Speeds and modes. */ + r |= (1 << 13) | (1 << 14); + r |= (1 << 11) | (1 << 12); + r |= (1 << 5); /* Autoneg complete. */ + r |= (1 << 3); /* Autoneg able. */ + r |= (1 << 2); /* link. */ + break; + case 5: + /* Link partner ability. + We are kind; always agree with whatever best mode + the guest advertises. */ + r = 1 << 14; /* Success. */ + /* Copy advertised modes. */ + r |= phy->regs[4] & (15 << 5); + /* Autoneg support. */ + r |= 1; + break; + case 18: + { + /* Diagnostics reg. */ + int duplex = 0; + int speed_100 = 0; + + if (!phy->link) { + break; + } + + /* Are we advertising 100 half or 100 duplex ? */ + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); + + /* Are we advertising 10 duplex or 100 duplex ? */ + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); + r = (speed_100 << 10) | (duplex << 11); + } + break; + + default: + r = phy->regs[regnum]; + break; + } + D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); + return r; } -static void +static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) { - int regnum; - - regnum = req & 0x1f; - D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); - switch (regnum) { - default: - phy->regs[regnum] = data; - break; - } + int regnum; + + regnum = req & 0x1f; + D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); + switch (regnum) { + default: + phy->regs[regnum] = data; + break; + } } -static void +static void tdk_init(struct qemu_phy *phy) { - phy->regs[0] = 0x3100; - /* PHY Id. */ - phy->regs[2] = 0x0300; - phy->regs[3] = 0xe400; - /* Autonegotiation advertisement reg. */ - phy->regs[4] = 0x01E1; - phy->link = 1; - - phy->read = tdk_read; - phy->write = tdk_write; + phy->regs[0] = 0x3100; + /* PHY Id. */ + phy->regs[2] = 0x0300; + phy->regs[3] = 0xe400; + /* Autonegotiation advertisement reg. */ + phy->regs[4] = 0x01E1; + phy->link = 1; + + phy->read = tdk_read; + phy->write = tdk_write; } struct qemu_mdio { - /* bus. */ - int mdc; - int mdio; - - /* decoder. */ - enum { - PREAMBLE, - SOF, - OPC, - ADDR, - REQ, - TURNAROUND, - DATA - } state; - unsigned int drive; - - unsigned int cnt; - unsigned int addr; - unsigned int opc; - unsigned int req; - unsigned int data; - - struct qemu_phy *devs[32]; + /* bus. */ + int mdc; + int mdio; + + /* decoder. */ + enum { + PREAMBLE, + SOF, + OPC, + ADDR, + REQ, + TURNAROUND, + DATA + } state; + unsigned int drive; + + unsigned int cnt; + unsigned int addr; + unsigned int opc; + unsigned int req; + unsigned int data; + + struct qemu_phy *devs[32]; }; -static void +static void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = phy; + bus->devs[addr & 0x1f] = phy; } #ifdef USE_THIS_DEAD_CODE -static void +static void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = NULL; + bus->devs[addr & 0x1f] = NULL; } #endif static void mdio_read_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; - - phy = bus->devs[bus->addr]; - if (phy && phy->read) - bus->data = phy->read(phy, bus->req); - else - bus->data = 0xffff; + struct qemu_phy *phy; + + phy = bus->devs[bus->addr]; + if (phy && phy->read) { + bus->data = phy->read(phy, bus->req); + } else { + bus->data = 0xffff; + } } static void mdio_write_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; + struct qemu_phy *phy; - phy = bus->devs[bus->addr]; - if (phy && phy->write) - phy->write(phy, bus->req, bus->data); + phy = bus->devs[bus->addr]; + if (phy && phy->write) { + phy->write(phy, bus->req, bus->data); + } } static void mdio_cycle(struct qemu_mdio *bus) { - bus->cnt++; + bus->cnt++; - D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", - bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); + D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", + bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); #if 0 - if (bus->mdc) - printf("%d", bus->mdio); + if (bus->mdc) { + printf("%d", bus->mdio); + } #endif - switch (bus->state) - { - case PREAMBLE: - if (bus->mdc) { - if (bus->cnt >= (32 * 2) && !bus->mdio) { - bus->cnt = 0; - bus->state = SOF; - bus->data = 0; - } - } - break; - case SOF: - if (bus->mdc) { - if (bus->mdio != 1) - printf("WARNING: no SOF\n"); - if (bus->cnt == 1*2) { - bus->cnt = 0; - bus->opc = 0; - bus->state = OPC; - } - } - break; - case OPC: - if (bus->mdc) { - bus->opc <<= 1; - bus->opc |= bus->mdio & 1; - if (bus->cnt == 2*2) { - bus->cnt = 0; - bus->addr = 0; - bus->state = ADDR; - } - } - break; - case ADDR: - if (bus->mdc) { - bus->addr <<= 1; - bus->addr |= bus->mdio & 1; - - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->req = 0; - bus->state = REQ; - } - } - break; - case REQ: - if (bus->mdc) { - bus->req <<= 1; - bus->req |= bus->mdio & 1; - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->state = TURNAROUND; - } - } - break; - case TURNAROUND: - if (bus->mdc && bus->cnt == 2*2) { - bus->mdio = 0; - bus->cnt = 0; - - if (bus->opc == 2) { - bus->drive = 1; - mdio_read_req(bus); - bus->mdio = bus->data & 1; - } - bus->state = DATA; - } - break; - case DATA: - if (!bus->mdc) { - if (bus->drive) { - bus->mdio = !!(bus->data & (1 << 15)); - bus->data <<= 1; - } - } else { - if (!bus->drive) { - bus->data <<= 1; - bus->data |= bus->mdio; - } - if (bus->cnt == 16 * 2) { - bus->cnt = 0; - bus->state = PREAMBLE; - if (!bus->drive) - mdio_write_req(bus); - bus->drive = 0; - } - } - break; - default: - break; - } + switch (bus->state) { + case PREAMBLE: + if (bus->mdc) { + if (bus->cnt >= (32 * 2) && !bus->mdio) { + bus->cnt = 0; + bus->state = SOF; + bus->data = 0; + } + } + break; + case SOF: + if (bus->mdc) { + if (bus->mdio != 1) { + printf("WARNING: no SOF\n"); + } + if (bus->cnt == 1*2) { + bus->cnt = 0; + bus->opc = 0; + bus->state = OPC; + } + } + break; + case OPC: + if (bus->mdc) { + bus->opc <<= 1; + bus->opc |= bus->mdio & 1; + if (bus->cnt == 2*2) { + bus->cnt = 0; + bus->addr = 0; + bus->state = ADDR; + } + } + break; + case ADDR: + if (bus->mdc) { + bus->addr <<= 1; + bus->addr |= bus->mdio & 1; + + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->req = 0; + bus->state = REQ; + } + } + break; + case REQ: + if (bus->mdc) { + bus->req <<= 1; + bus->req |= bus->mdio & 1; + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->state = TURNAROUND; + } + } + break; + case TURNAROUND: + if (bus->mdc && bus->cnt == 2*2) { + bus->mdio = 0; + bus->cnt = 0; + + if (bus->opc == 2) { + bus->drive = 1; + mdio_read_req(bus); + bus->mdio = bus->data & 1; + } + bus->state = DATA; + } + break; + case DATA: + if (!bus->mdc) { + if (bus->drive) { + bus->mdio = !!(bus->data & (1 << 15)); + bus->data <<= 1; + } + } else { + if (!bus->drive) { + bus->data <<= 1; + bus->data |= bus->mdio; + } + if (bus->cnt == 16 * 2) { + bus->cnt = 0; + bus->state = PREAMBLE; + if (!bus->drive) { + mdio_write_req(bus); + } + bus->drive = 0; + } + } + break; + default: + break; + } } /* ETRAX-FS Ethernet MAC block starts here. */ -#define RW_MA0_LO 0x00 -#define RW_MA0_HI 0x01 -#define RW_MA1_LO 0x02 -#define RW_MA1_HI 0x03 -#define RW_GA_LO 0x04 -#define RW_GA_HI 0x05 -#define RW_GEN_CTRL 0x06 -#define RW_REC_CTRL 0x07 -#define RW_TR_CTRL 0x08 -#define RW_CLR_ERR 0x09 -#define RW_MGM_CTRL 0x0a -#define R_STAT 0x0b -#define FS_ETH_MAX_REGS 0x17 +#define RW_MA0_LO 0x00 +#define RW_MA0_HI 0x01 +#define RW_MA1_LO 0x02 +#define RW_MA1_HI 0x03 +#define RW_GA_LO 0x04 +#define RW_GA_HI 0x05 +#define RW_GEN_CTRL 0x06 +#define RW_REC_CTRL 0x07 +#define RW_TR_CTRL 0x08 +#define RW_CLR_ERR 0x09 +#define RW_MGM_CTRL 0x0a +#define R_STAT 0x0b +#define FS_ETH_MAX_REGS 0x17 struct fs_eth { - SysBusDevice busdev; - MemoryRegion mmio; - NICState *nic; - NICConf conf; - - /* Two addrs in the filter. */ - uint8_t macaddr[2][6]; - uint32_t regs[FS_ETH_MAX_REGS]; - - union { - void *vdma_out; - struct etraxfs_dma_client *dma_out; - }; - union { - void *vdma_in; - struct etraxfs_dma_client *dma_in; - }; - - /* MDIO bus. */ - struct qemu_mdio mdio_bus; - unsigned int phyaddr; - int duplex_mismatch; - - /* PHY. */ - struct qemu_phy phy; + SysBusDevice busdev; + MemoryRegion mmio; + NICState *nic; + NICConf conf; + + /* Two addrs in the filter. */ + uint8_t macaddr[2][6]; + uint32_t regs[FS_ETH_MAX_REGS]; + + union { + void *vdma_out; + struct etraxfs_dma_client *dma_out; + }; + union { + void *vdma_in; + struct etraxfs_dma_client *dma_in; + }; + + /* MDIO bus. */ + struct qemu_mdio mdio_bus; + unsigned int phyaddr; + int duplex_mismatch; + + /* PHY. */ + struct qemu_phy phy; }; static void eth_validate_duplex(struct fs_eth *eth) { - struct qemu_phy *phy; - unsigned int phy_duplex; - unsigned int mac_duplex; - int new_mm = 0; - - phy = eth->mdio_bus.devs[eth->phyaddr]; - phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); - mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); - - if (mac_duplex != phy_duplex) - new_mm = 1; - - if (eth->regs[RW_GEN_CTRL] & 1) { - if (new_mm != eth->duplex_mismatch) { - if (new_mm) - printf("HW: WARNING " - "ETH duplex mismatch MAC=%d PHY=%d\n", - mac_duplex, phy_duplex); - else - printf("HW: ETH duplex ok.\n"); - } - eth->duplex_mismatch = new_mm; - } + struct qemu_phy *phy; + unsigned int phy_duplex; + unsigned int mac_duplex; + int new_mm = 0; + + phy = eth->mdio_bus.devs[eth->phyaddr]; + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); + + if (mac_duplex != phy_duplex) { + new_mm = 1; + } + + if (eth->regs[RW_GEN_CTRL] & 1) { + if (new_mm != eth->duplex_mismatch) { + if (new_mm) { + printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n", + mac_duplex, phy_duplex); + } else { + printf("HW: ETH duplex ok.\n"); + } + } + eth->duplex_mismatch = new_mm; + } } static uint64_t eth_read(void *opaque, hwaddr addr, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t r = 0; - - addr >>= 2; - - switch (addr) { - case R_STAT: - r = eth->mdio_bus.mdio & 1; - break; - default: - r = eth->regs[addr]; - D(printf ("%s %x\n", __func__, addr * 4)); - break; - } - return r; + struct fs_eth *eth = opaque; + uint32_t r = 0; + + addr >>= 2; + + switch (addr) { + case R_STAT: + r = eth->mdio_bus.mdio & 1; + break; + default: + r = eth->regs[addr]; + D(printf("%s %x\n", __func__, addr * 4)); + break; + } + return r; } static void eth_update_ma(struct fs_eth *eth, int ma) { - int reg; - int i = 0; - - ma &= 1; - - reg = RW_MA0_LO; - if (ma) - reg = RW_MA1_LO; - - eth->macaddr[ma][i++] = eth->regs[reg]; - eth->macaddr[ma][i++] = eth->regs[reg] >> 8; - eth->macaddr[ma][i++] = eth->regs[reg] >> 16; - eth->macaddr[ma][i++] = eth->regs[reg] >> 24; - eth->macaddr[ma][i++] = eth->regs[reg + 1]; - eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; - - D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, - eth->macaddr[ma][0], eth->macaddr[ma][1], - eth->macaddr[ma][2], eth->macaddr[ma][3], - eth->macaddr[ma][4], eth->macaddr[ma][5])); + int reg; + int i = 0; + + ma &= 1; + + reg = RW_MA0_LO; + if (ma) { + reg = RW_MA1_LO; + } + + eth->macaddr[ma][i++] = eth->regs[reg]; + eth->macaddr[ma][i++] = eth->regs[reg] >> 8; + eth->macaddr[ma][i++] = eth->regs[reg] >> 16; + eth->macaddr[ma][i++] = eth->regs[reg] >> 24; + eth->macaddr[ma][i++] = eth->regs[reg + 1]; + eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; + + D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, + eth->macaddr[ma][0], eth->macaddr[ma][1], + eth->macaddr[ma][2], eth->macaddr[ma][3], + eth->macaddr[ma][4], eth->macaddr[ma][5])); } static void eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t value = val64; - - addr >>= 2; - switch (addr) - { - case RW_MA0_LO: - case RW_MA0_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 0); - break; - case RW_MA1_LO: - case RW_MA1_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 1); - break; - - case RW_MGM_CTRL: - /* Attach an MDIO/PHY abstraction. */ - if (value & 2) - eth->mdio_bus.mdio = value & 1; - if (eth->mdio_bus.mdc != (value & 4)) { - mdio_cycle(ð->mdio_bus); - eth_validate_duplex(eth); - } - eth->mdio_bus.mdc = !!(value & 4); - eth->regs[addr] = value; - break; - - case RW_REC_CTRL: - eth->regs[addr] = value; - eth_validate_duplex(eth); - break; - - default: - eth->regs[addr] = value; - D(printf ("%s %x %x\n", - __func__, addr, value)); - break; - } + struct fs_eth *eth = opaque; + uint32_t value = val64; + + addr >>= 2; + switch (addr) { + case RW_MA0_LO: + case RW_MA0_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 0); + break; + case RW_MA1_LO: + case RW_MA1_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 1); + break; + + case RW_MGM_CTRL: + /* Attach an MDIO/PHY abstraction. */ + if (value & 2) { + eth->mdio_bus.mdio = value & 1; + } + if (eth->mdio_bus.mdc != (value & 4)) { + mdio_cycle(ð->mdio_bus); + eth_validate_duplex(eth); + } + eth->mdio_bus.mdc = !!(value & 4); + eth->regs[addr] = value; + break; + + case RW_REC_CTRL: + eth->regs[addr] = value; + eth_validate_duplex(eth); + break; + + default: + eth->regs[addr] = value; + D(printf("%s %x %x\n", __func__, addr, value)); + break; + } } /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom - filter dropping group addresses we have not joined. The filter has 64 - bits (m). The has function is a simple nible xor of the group addr. */ + filter dropping group addresses we have not joined. The filter has 64 + bits (m). The has function is a simple nible xor of the group addr. */ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) { - unsigned int hsh; - int m_individual = eth->regs[RW_REC_CTRL] & 4; - int match; - - /* First bit on the wire of a MAC address signals multicast or - physical address. */ - if (!m_individual && !(sa[0] & 1)) - return 0; - - /* Calculate the hash index for the GA registers. */ - hsh = 0; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - ++sa; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - - hsh &= 63; - if (hsh > 31) - match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); - else - match = eth->regs[RW_GA_LO] & (1 << hsh); - D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, - eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); - return match; + unsigned int hsh; + int m_individual = eth->regs[RW_REC_CTRL] & 4; + int match; + + /* First bit on the wire of a MAC address signals multicast or + physical address. */ + if (!m_individual && !(sa[0] & 1)) { + return 0; + } + + /* Calculate the hash index for the GA registers. */ + hsh = 0; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + ++sa; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + + hsh &= 63; + if (hsh > 31) { + match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); + } else { + match = eth->regs[RW_GA_LO] & (1 << hsh); + } + D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, + eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); + return match; } static int eth_can_receive(NetClientState *nc) { - return 1; + return 1; } static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - int use_ma0 = eth->regs[RW_REC_CTRL] & 1; - int use_ma1 = eth->regs[RW_REC_CTRL] & 2; - int r_bcast = eth->regs[RW_REC_CTRL] & 8; - - if (size < 12) - return -1; - - D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - use_ma0, use_ma1, r_bcast)); - - /* Does the frame get through the address filters? */ - if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) - && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) - && (!r_bcast || memcmp(buf, sa_bcast, 6)) - && !eth_match_groupaddr(eth, buf)) - return size; - - /* FIXME: Find another way to pass on the fake csum. */ - etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); + unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + int use_ma0 = eth->regs[RW_REC_CTRL] & 1; + int use_ma1 = eth->regs[RW_REC_CTRL] & 2; + int r_bcast = eth->regs[RW_REC_CTRL] & 8; + + if (size < 12) { + return -1; + } + + D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + use_ma0, use_ma1, r_bcast)); + + /* Does the frame get through the address filters? */ + if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) + && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) + && (!r_bcast || memcmp(buf, sa_bcast, 6)) + && !eth_match_groupaddr(eth, buf)) { + return size; + } + + /* FIXME: Find another way to pass on the fake csum. */ + etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); return size; } static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) { - struct fs_eth *eth = opaque; + struct fs_eth *eth = opaque; - D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(ð->nic->nc, buf, len); - return len; + D(printf("%s buf=%p len=%d\n", __func__, buf, len)); + qemu_send_packet(ð->nic->nc, buf, len); + return len; } static void eth_set_link(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - D(printf("%s %d\n", __func__, nc->link_down)); - eth->phy.link = !nc->link_down; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + D(printf("%s %d\n", __func__, nc->link_down)); + eth->phy.link = !nc->link_down; } static const MemoryRegionOps eth_ops = { - .read = eth_read, - .write = eth_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } + .read = eth_read, + .write = eth_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static void eth_cleanup(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - /* Disconnect the client. */ - eth->dma_out->client.push = NULL; - eth->dma_out->client.opaque = NULL; - eth->dma_in->client.opaque = NULL; - eth->dma_in->client.pull = NULL; + /* Disconnect the client. */ + eth->dma_out->client.push = NULL; + eth->dma_out->client.opaque = NULL; + eth->dma_in->client.opaque = NULL; + eth->dma_in->client.pull = NULL; g_free(eth); } static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .can_receive = eth_can_receive, - .receive = eth_receive, - .cleanup = eth_cleanup, - .link_status_changed = eth_set_link, + .type = NET_CLIENT_OPTIONS_KIND_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, + .link_status_changed = eth_set_link, }; static int fs_eth_init(SysBusDevice *dev) { - struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); + struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); - if (!s->dma_out || !s->dma_in) { - hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); - } + if (!s->dma_out || !s->dma_in) { + hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); + } - s->dma_out->client.push = eth_tx_push; - s->dma_out->client.opaque = s; - s->dma_in->client.opaque = s; - s->dma_in->client.pull = NULL; + s->dma_out->client.push = eth_tx_push; + s->dma_out->client.opaque = s; + s->dma_in->client.opaque = s; + s->dma_in->client.pull = NULL; - memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); - sysbus_init_mmio(dev, &s->mmio); + memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); + sysbus_init_mmio(dev, &s->mmio); - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - object_get_typename(OBJECT(s)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, + object_get_typename(OBJECT(s)), dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); - tdk_init(&s->phy); - mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); - return 0; + tdk_init(&s->phy); + mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); + return 0; } static Property etraxfs_eth_properties[] = { |