/*
* QEMU e1000 emulation
*
+ * Software developer's manual:
+ * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ *
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
#include "e1000_hw.h"
-#define DEBUG
+#define E1000_DEBUG
-#ifdef DEBUG
+#ifdef E1000_DEBUG
enum {
DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
struct e1000_tx {
unsigned char header[256];
unsigned char vlan_header[4];
+ /* Fields vlan and data must not be reordered or separated. */
unsigned char vlan[4];
unsigned char data[0x10000];
uint16_t size;
s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
+ if (!(E1000_EECD_CS & val)) // CS inactive; nothing to do
+ return;
+ if (E1000_EECD_CS & (val ^ oldval)) { // CS rise edge; reset state
+ s->eecd_state.val_in = 0;
+ s->eecd_state.bitnum_in = 0;
+ s->eecd_state.bitnum_out = 0;
+ s->eecd_state.reading = 0;
+ }
if (!(E1000_EECD_SK & (val ^ oldval))) // no clock edge
return;
if (!(E1000_EECD_SK & val)) { // falling edge
s->eecd_state.bitnum_out++;
return;
}
- 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;
if (val & E1000_EECD_DI)
s->eecd_state.val_in |= 1;
if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
if (tp->vlan_needed) {
- memmove(tp->vlan, tp->data, 12);
+ memmove(tp->vlan, tp->data, 4);
+ memmove(tp->data, tp->data + 4, 8);
memcpy(tp->data + 8, tp->vlan_header, 4);
qemu_send_packet(&s->nic->nc, tp->vlan, tp->size + 4);
} else
static int
receive_filter(E1000State *s, const uint8_t *buf, int size)
{
- static uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- static int mta_shift[] = {4, 3, 2, 0};
+ static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const int mta_shift[] = {4, 3, 2, 0};
uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
- memmove((void *)(buf + 4), buf, 12);
+ memmove((uint8_t *)buf + 4, buf, 12);
vlan_status = E1000_RXD_STAT_VP;
vlan_offset = 4;
size -= 4;
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;
+ /* TODO: we have no capabilities, so why is this bit set? */
+ pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
+ pci_conf[PCI_REVISION_ID] = 0x03;
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
- pci_conf[0x0c] = 0x10;
+ /* TODO: RST# value should be 0, PCI spec 6.2.4 */
+ pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
- pci_conf[0x3d] = 1; // interrupt pin 0
+ /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */
+ pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
e1000_mmio_write, d);
d->dev.qdev.info->name, d->dev.qdev.id, d);
qemu_format_nic_info_str(&d->nic->nc, macaddr);
-
- if (!pci_dev->qdev.hotplugged) {
- static int loaded = 0;
- if (!loaded) {
- rom_add_option("pxe-e1000.bin");
- loaded = 1;
- }
- }
return 0;
}
.qdev.vmsd = &vmstate_e1000,
.init = pci_e1000_init,
.exit = pci_e1000_uninit,
+ .romfile = "pxe-e1000.bin",
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(E1000State, conf),
DEFINE_PROP_END_OF_LIST(),