typedef struct E1000State_st {
PCIDevice dev;
VLANClientState *vc;
- NICInfo *nd;
int mmio_index;
uint32_t mac_reg[0x8000];
if (val)
val |= E1000_ICR_INT_ASSERTED;
s->mac_reg[ICR] = val;
+ s->mac_reg[ICS] = val;
qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
}
return 2048;
}
+static void
+set_ctrl(E1000State *s, int index, uint32_t val)
+{
+ /* RST is self clearing */
+ s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+}
+
static void
set_rx_control(E1000State *s, int index, uint32_t val)
{
}
if (!(val & E1000_EECD_CS)) { // rising, no CS (EEPROM reset)
memset(&s->eecd_state, 0, sizeof s->eecd_state);
+ /*
+ * restore old_eecd's E1000_EECD_SK (known to be on)
+ * to avoid false detection of a clock edge
+ */
+ s->eecd_state.old_eecd = E1000_EECD_SK;
return;
}
s->eecd_state.val_in <<= 1;
{
unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
+ if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
+ return (s->mac_reg[EERD]);
+
if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
- return 0;
- return (s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
- E1000_EEPROM_RW_REG_DONE | r;
+ return (E1000_EEPROM_RW_REG_DONE | r);
+
+ return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
+ E1000_EEPROM_RW_REG_DONE | r);
}
static void
n = E1000_ICS_RXT0;
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
rdt += s->mac_reg[RDLEN] / sizeof(desc);
- if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) << s->rxbuf_min_shift >=
- s->mac_reg[RDLEN])
+ if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
+ s->rxbuf_min_shift)
n |= E1000_ICS_RXDMT0;
set_ics(s, 0, n);
getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
- getreg(RDH), getreg(RDT), getreg(VET),
+ getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
[TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
[GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4,
static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
- putreg(RDBAL), putreg(LEDCTL), putreg(CTRL), putreg(VET),
+ putreg(RDBAL), putreg(LEDCTL), putreg(VET),
[TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
[TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
- [EECD] = set_eecd, [RCTL] = set_rx_control,
+ [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
[RA ... RA+31] = &mac_writereg,
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
excluded_regs[i] - 4);
}
-void
+static void
+e1000_cleanup(VLANClientState *vc)
+{
+ E1000State *d = vc->opaque;
+
+ unregister_savevm("e1000", d);
+}
+
+static int
+pci_e1000_uninit(PCIDevice *dev)
+{
+ E1000State *d = (E1000State *) dev;
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ return 0;
+}
+
+PCIDevice *
pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
{
E1000State *d;
d = (E1000State *)pci_register_device(bus, "e1000",
sizeof(E1000State), devfn, NULL, NULL);
+ if (!d)
+ return NULL;
+
pci_conf = d->dev.config;
- memset(pci_conf, 0, 256);
- *(uint16_t *)(pci_conf+0x00) = cpu_to_le16(0x8086);
- *(uint16_t *)(pci_conf+0x02) = cpu_to_le16(E1000_DEVID);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, E1000_DEVID);
*(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407);
*(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
pci_conf[0x08] = 0x03;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0c] = 0x10;
pci_conf[0x3d] = 1; // interrupt pin 0
pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE,
PCI_ADDRESS_SPACE_IO, ioport_map);
- d->nd = nd;
memmove(d->eeprom_data, e1000_eeprom_template,
sizeof e1000_eeprom_template);
for (i = 0; i < 3; i++)
memset(&d->tx, 0, sizeof d->tx);
d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- e1000_receive, e1000_can_receive, d);
+ e1000_receive, e1000_can_receive,
+ e1000_cleanup, d);
d->vc->link_status_changed = e1000_set_link_status;
- qemu_format_nic_info_str(d->vc, d->nd->macaddr);
+ qemu_format_nic_info_str(d->vc, nd->macaddr);
register_savevm(info_str, -1, 2, nic_save, nic_load, d);
+ d->dev.unregister = pci_e1000_uninit;
+
+ return (PCIDevice *)d;
}