@@ -57,6 +57,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
#define PNPMMIO_SIZE 0x20000
#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
+#define REG_IOADDR 0x0
+#define REG_IODATA 0x4
+
/*
* HW models:
* E1000_DEV_ID_82540EM works with Windows and Linux
@@ -82,6 +85,8 @@ typedef struct E1000State_st {
NICState *nic;
NICConf conf;
int mmio_index;
+ int ioport_base;
+ uint32_t ioport_reg[2];
uint32_t mac_reg[0x8000];
uint16_t phy_reg[0x20];
@@ -149,13 +154,7 @@ static const char phy_regcap[0x20] = {
[PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R
};
-static void
-ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
- pcibus_t size, int type)
-{
- DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
- " size=0x%08"FMT_PCIBUS"\n", addr, size);
-}
+static void e1000_reset(void *opaque);
static void
set_interrupt_cause(E1000State *s, int index, uint32_t val)
@@ -201,6 +200,11 @@ rxbufsize(uint32_t v)
static void
set_ctrl(E1000State *s, int index, uint32_t val)
{
+ DBGOUT(IO, "set ctrl = %08x\n", val);
+ if (val & E1000_CTRL_RST) {
+ s->mac_reg[CTRL] = val;
+ e1000_reset(s);
+ }
/* RST is self clearing */
s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
}
@@ -623,7 +627,7 @@ e1000_can_receive(VLANClientState *nc)
{
E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
- return (s->mac_reg[RCTL] & E1000_RCTL_EN);
+ return (s->mac_reg[RCTL] & E1000_RCTL_EN && s->mac_reg[RDLEN] != 0);
}
static ssize_t
@@ -666,6 +670,11 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
size -= 4;
}
+ if (s->mac_reg[RDLEN] == 0) {
+ DBGOUT(RX, "receive descriptor buffer not set\n");
+ return -1;
+ }
+
rdh_start = s->mac_reg[RDH];
do {
if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
@@ -847,6 +856,60 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
static void
+e1000_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ E1000State *s = opaque;
+
+ if (addr == s->ioport_base + REG_IOADDR) {
+ DBGOUT(IO, "e1000_ioport_writel write base: 0x%04x\n", val);
+ s->ioport_reg[REG_IOADDR] = val & 0xfffff;
+ } else if (addr == (s->ioport_base + REG_IODATA)) {
+ unsigned int index = (s->ioport_reg[REG_IOADDR] & 0x1ffff) >> 2;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ DBGOUT(IO, "e1000_ioport_writel %x: 0x%04x\n", index, val);
+
+ if (index < NWRITEOPS && macreg_writeops[index]) {
+ macreg_writeops[index](s, index, val);
+ } else if (index < NREADOPS && macreg_readops[index]) {
+ DBGOUT(IO, "e1000_ioport_writel RO %x: 0x%04x\n", index << 2, val);
+ } else {
+ DBGOUT(UNKNOWN, "IO unknown write index=0x%08x,val=0x%08x\n",
+ index, val);
+ }
+ } else {
+ DBGOUT(UNKNOWN, "IO unknown write addr=0x%08x,val=0x%08x\n",
+ addr, val);
+ }
+}
+
+static uint32_t
+e1000_ioport_readl(void *opaque, uint32_t addr)
+{
+ E1000State *s = opaque;
+
+ if (addr == s->ioport_base + REG_IOADDR) {
+ return s->ioport_reg[REG_IOADDR] & 0xfffff;
+ } else if (addr == (s->ioport_base + REG_IODATA)) {
+ unsigned int index = (s->ioport_reg[REG_IOADDR] & 0x1ffff) >> 2;
+
+ if (index < NREADOPS && macreg_readops[index]) {
+ uint32_t val = macreg_readops[index](s, index);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+ }
+ DBGOUT(UNKNOWN, "IO unknown read addr=0x%08x\n", index<<2);
+ } else {
+ DBGOUT(UNKNOWN, "IO unknown read addr=0x%08x\n", addr);
+ }
+ return 0;
+}
+
+static void
e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
E1000State *s = opaque;
@@ -1031,6 +1094,30 @@ static const uint32_t mac_reg_init[] = {
/* PCI interface */
+static void
+e1000_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
+ pcibus_t size, int type)
+{
+ E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+
+ DBGOUT(IO, "e1000_ioport_map addr=0x%04" FMT_PCIBUS
+ " size=0x%08" FMT_PCIBUS "\n", addr, size);
+
+ d->ioport_base = addr;
+
+ /* Writes that are less than 32 bits are ignored on IOADDR.
+ * For the Flash access, a write can be less than 32 bits for
+ * IODATA register, but is not handled.
+ */
+
+ register_ioport_read(addr, size, 1, e1000_ioport_readl, d);
+
+ register_ioport_read(addr, size, 2, e1000_ioport_readl, d);
+
+ register_ioport_write(addr, size, 4, e1000_ioport_writel, d);
+ register_ioport_read(addr, size, 4, e1000_ioport_readl, d);
+}
+
static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
e1000_mmio_writeb, e1000_mmio_writew, e1000_mmio_writel
};
@@ -1085,6 +1172,7 @@ static void e1000_reset(void *opaque)
{
E1000State *d = opaque;
+ memset(d->ioport_reg, 0, sizeof d->ioport_reg);
memset(d->phy_reg, 0, sizeof d->phy_reg);
memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
memset(d->mac_reg, 0, sizeof d->mac_reg);
@@ -1131,7 +1219,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
- PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+ PCI_BASE_ADDRESS_SPACE_IO, e1000_ioport_map);
memmove(d->eeprom_data, e1000_eeprom_template,
sizeof e1000_eeprom_template);