*/
-#include "hw.h"
-#include "pci.h"
-#include "net.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
#include "net/checksum.h"
-#include "loader.h"
-#include "sysemu.h"
-#include "dma.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
-#include "e1000_hw.h"
+#include "hw/e1000_hw.h"
#define E1000_DEBUG
#define PNPMMIO_SIZE 0x20000
#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+/* this is the size past which hardware will drop packets when setting LPE=1 */
+#define MAXIMUM_ETHERNET_LPE_SIZE 16384
+
/*
* HW models:
* E1000_DEV_ID_82540EM works with Windows and Linux
uint32_t rxbuf_size;
uint32_t rxbuf_min_shift;
- int check_rxov;
struct e1000_tx {
unsigned char header[256];
unsigned char vlan_header[4];
} eecd_state;
QEMUTimer *autoneg_timer;
+
+/* Compatibility flags for migration to/from qemu 1.3.0 and older */
+#define E1000_FLAG_AUTONEG_BIT 0
+#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
+ uint32_t compat_flags;
} E1000State;
#define defreg(x) x = (E1000_##x>>2)
static void
set_phy_ctrl(E1000State *s, int index, uint16_t val)
{
+ /*
+ * QEMU 1.3 does not support link auto-negotiation emulation, so if we
+ * migrate during auto negotiation, after migration the link will be
+ * down.
+ */
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return;
+ }
if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
- s->nic->nc.link_down = true;
e1000_link_down(s);
s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
DBGOUT(PHY, "Start link auto negotiation\n");
e1000_autoneg_timer(void *opaque)
{
E1000State *s = opaque;
- s->nic->nc.link_down = false;
- e1000_link_up(s);
+ if (!qemu_get_queue(s->nic)->link_down) {
+ e1000_link_up(s);
+ }
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
DBGOUT(PHY, "Auto negotiation is completed\n");
}
val |= E1000_ICR_INT_ASSERTED;
}
s->mac_reg[ICR] = val;
+
+ /*
+ * Make sure ICR and ICS registers have the same value.
+ * The spec says that the ICS register is write-only. However in practice,
+ * on real hardware ICS is readable, and for reads it has the same value as
+ * ICR (except that ICS does not have the clear on read behaviour of ICR).
+ *
+ * The VxWorks PRO/1000 driver uses this behaviour.
+ */
s->mac_reg[ICS] = val;
+
qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
}
static void e1000_reset(void *opaque)
{
E1000State *d = opaque;
+ uint8_t *macaddr = d->conf.macaddr.a;
+ int i;
qemu_del_timer(d->autoneg_timer);
memset(d->phy_reg, 0, sizeof d->phy_reg);
d->rxbuf_min_shift = 1;
memset(&d->tx, 0, sizeof d->tx);
- if (d->nic->nc.link_down) {
+ if (qemu_get_queue(d->nic)->link_down) {
e1000_link_down(d);
}
+
+ /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
+ d->mac_reg[RA] = 0;
+ d->mac_reg[RA + 1] = E1000_RAH_AV;
+ for (i = 0; i < 4; i++) {
+ d->mac_reg[RA] |= macaddr[i] << (8 * i);
+ d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
+ }
}
static void
s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
s->mac_reg[RCTL]);
- qemu_flush_queued_packets(&s->nic->nc);
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
}
static void
static void
e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
{
+ NetClientState *nc = qemu_get_queue(s->nic);
if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
- s->nic->nc.info->receive(&s->nic->nc, buf, size);
+ nc->info->receive(nc, buf, size);
} else {
- qemu_send_packet(&s->nic->nc, buf, size);
+ qemu_send_packet(nc, buf, size);
}
}
static void
e1000_set_link_status(NetClientState *nc)
{
- E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ E1000State *s = qemu_get_nic_opaque(nc);
uint32_t old_status = s->mac_reg[STATUS];
if (nc->link_down) {
int bufs;
/* Fast-path short packets */
if (total_size <= s->rxbuf_size) {
- return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
+ return s->mac_reg[RDH] != s->mac_reg[RDT];
}
if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
- } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
+ } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
s->mac_reg[RDT] - s->mac_reg[RDH];
} else {
static int
e1000_can_receive(NetClientState *nc)
{
- E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ E1000State *s = qemu_get_nic_opaque(nc);
- return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
+ return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
+ (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
}
static uint64_t rx_desc_base(E1000State *s)
static ssize_t
e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
- E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ E1000State *s = qemu_get_nic_opaque(nc);
struct e1000_rx_desc desc;
dma_addr_t base;
unsigned int n, rdt;
size_t desc_size;
size_t total_size;
- if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
+ if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
return -1;
+ }
+
+ if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
+ return -1;
+ }
/* Pad to minimum Ethernet frame length */
if (size < sizeof(min_buf)) {
size = sizeof(min_buf);
}
+ /* Discard oversized packets if !LPE and !SBP. */
+ if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
+ (size > MAXIMUM_ETHERNET_VLAN_SIZE
+ && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
+ && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
+ return size;
+ }
+
if (!receive_filter(s, buf, size))
return size;
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
s->mac_reg[RDH] = 0;
- s->check_rxov = 1;
/* see comment in start_xmit; same here */
if (s->mac_reg[RDH] == rdh_start) {
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
static void
set_rdt(E1000State *s, int index, uint32_t val)
{
- s->check_rxov = 0;
s->mac_reg[index] = val & 0xffff;
if (e1000_has_rxbufs(s, 1)) {
- qemu_flush_queued_packets(&s->nic->nc);
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
}
}
enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
static void
-e1000_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val,
+e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
E1000State *s = opaque;
}
static uint64_t
-e1000_mmio_read(void *opaque, target_phys_addr_t addr, unsigned size)
+e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
E1000State *s = opaque;
unsigned int index = (addr & 0x1ffff) >> 2;
},
};
-static uint64_t e1000_io_read(void *opaque, target_phys_addr_t addr,
+static uint64_t e1000_io_read(void *opaque, hwaddr addr,
unsigned size)
{
E1000State *s = opaque;
return 0;
}
-static void e1000_io_write(void *opaque, target_phys_addr_t addr,
+static void e1000_io_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
E1000State *s = opaque;
return version_id == 1;
}
+static void e1000_pre_save(void *opaque)
+{
+ E1000State *s = opaque;
+ NetClientState *nc = qemu_get_queue(s->nic);
+
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return;
+ }
+
+ /*
+ * If link is down and auto-negotiation is ongoing, complete
+ * auto-negotiation immediately. This allows is to look at
+ * MII_SR_AUTONEG_COMPLETE to infer link status on load.
+ */
+ if (nc->link_down &&
+ s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
+ s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
+ s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
+ }
+}
+
static int e1000_post_load(void *opaque, int version_id)
{
E1000State *s = opaque;
+ NetClientState *nc = qemu_get_queue(s->nic);
/* nc.link_down can't be migrated, so infer link_down according
- * to link status bit in mac_reg[STATUS] */
- s->nic->nc.link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
+ * to link status bit in mac_reg[STATUS].
+ * Alternatively, restart link negotiation if it was in progress. */
+ nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
+
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return 0;
+ }
+
+ if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
+ s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
+ !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
+ nc->link_down = false;
+ qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
+ }
return 0;
}
.version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .pre_save = e1000_pre_save,
.post_load = e1000_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, E1000State),
static void
e1000_cleanup(NetClientState *nc)
{
- E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ E1000State *s = qemu_get_nic_opaque(nc);
s->nic = NULL;
}
qemu_free_timer(d->autoneg_timer);
memory_region_destroy(&d->mmio);
memory_region_destroy(&d->io);
- qemu_del_net_client(&d->nic->nc);
+ qemu_del_nic(d->nic);
}
static NetClientInfo net_e1000_info = {
d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
- qemu_format_nic_info_str(&d->nic->nc, macaddr);
+ qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
static Property e1000_properties[] = {
DEFINE_NIC_PROPERTIES(E1000State, conf),
+ DEFINE_PROP_BIT("autonegotiation", E1000State,
+ compat_flags, E1000_FLAG_AUTONEG_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
k->init = pci_e1000_init;
k->exit = pci_e1000_uninit;
- k->romfile = "pxe-e1000.rom";
+ k->romfile = "efi-e1000.rom";
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = E1000_DEVID;
k->revision = 0x03;
dc->props = e1000_properties;
}
-static TypeInfo e1000_info = {
+static const TypeInfo e1000_info = {
.name = "e1000",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(E1000State),