* * Wake-on-LAN is not implemented.
*/
-#include <stddef.h> /* offsetof */
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
#include "hw/nvram/eeprom93xx.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
+#include "qemu/bitops.h"
/* QEMU sends frames smaller than 60 bytes to ethernet nics.
* Such frames are rejected by real nics and their emulations.
#define PCI_IO_SIZE 64
#define PCI_FLASH_SIZE (128 * KiB)
-#define BIT(n) (1 << (n))
#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
/* The SCB accepts the following controls for the Tx and Rx units: */
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
{
assert(!((uintptr_t)&s->mem[addr] & 1));
- return le16_to_cpup((uint16_t *)&s->mem[addr]);
+ return lduw_le_p(&s->mem[addr]);
}
/* Read a 32 bit control/status (CSR) register. */
static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
{
assert(!((uintptr_t)&s->mem[addr] & 3));
- return le32_to_cpup((uint32_t *)&s->mem[addr]);
+ return ldl_le_p(&s->mem[addr]);
}
/* Write a 16 bit control/status (CSR) register. */
uint16_t val)
{
assert(!((uintptr_t)&s->mem[addr] & 1));
- cpu_to_le16w((uint16_t *)&s->mem[addr], val);
+ stw_le_p(&s->mem[addr], val);
}
/* Read a 32 bit control/status (CSR) register. */
uint32_t val)
{
assert(!((uintptr_t)&s->mem[addr] & 3));
- cpu_to_le32w((uint32_t *)&s->mem[addr], val);
+ stl_le_p(&s->mem[addr], val);
}
#if defined(DEBUG_EEPRO100)
{
if (s->int_stat) {
TRACE(INT, logout("interrupt disabled\n"));
- qemu_irq_lower(s->dev.irq[0]);
+ pci_irq_deassert(&s->dev);
s->int_stat = 0;
}
}
{
if (!s->int_stat) {
TRACE(INT, logout("interrupt enabled\n"));
- qemu_irq_raise(s->dev.irq[0]);
+ pci_irq_assert(&s->dev);
s->int_stat = 1;
}
}
#if 0
uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
#endif
+ if (tx_buffer_size == 0) {
+ /* Prevent an endless loop. */
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
+ break;
+ }
tbd_address += 8;
TRACE(RXTX, logout
("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
static void action_command(EEPRO100State *s)
{
+ /* The loop below won't stop if it gets special handcrafted data.
+ Therefore we limit the number of iterations. */
+ unsigned max_loop_count = 16;
+
for (;;) {
bool bit_el;
bool bit_s;
#if 0
bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
#endif
+
+ if (max_loop_count-- == 0) {
+ /* Prevent an endless loop. */
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
+ break;
+ }
+
s->cu_offset = s->tx.link;
TRACE(OTHER,
logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
break;
case 1: /* Status Register */
missing("not writable");
- data = s->mdimem[reg];
break;
case 2: /* PHY Identification Register (Word 1) */
case 3: /* PHY Identification Register (Word 2) */
default:
missing("not implemented");
}
- s->mdimem[reg] = data;
+ s->mdimem[reg] &= eepro100_mdi_mask[reg];
+ s->mdimem[reg] |= data & ~eepro100_mdi_mask[reg];
} else if (opcode == 2) {
/* MDI read */
switch (reg) {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static int nic_can_receive(NetClientState *nc)
-{
- EEPRO100State *s = qemu_get_nic_opaque(nc);
- TRACE(RXTX, logout("%p\n", s));
- return get_ru_state(s) == ru_ready;
-#if 0
- return !eepro100_buffer_full(s);
-#endif
-}
-
static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
{
/* TODO:
static const VMStateDescription vmstate_eepro100 = {
.version_id = 3,
.minimum_version_id = 2,
- .minimum_version_id_old = 2,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, EEPRO100State),
VMSTATE_UNUSED(32),
VMSTATE_BUFFER(mult, EEPRO100State),
}
};
-static void nic_cleanup(NetClientState *nc)
-{
- EEPRO100State *s = qemu_get_nic_opaque(nc);
-
- s->nic = NULL;
-}
-
static void pci_nic_uninit(PCIDevice *pci_dev)
{
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
- memory_region_destroy(&s->mmio_bar);
- memory_region_destroy(&s->io_bar);
- memory_region_destroy(&s->flash_bar);
vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+ g_free(s->vmstate);
eeprom93xx_free(&pci_dev->qdev, s->eeprom);
qemu_del_nic(s->nic);
}
static NetClientInfo net_eepro100_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
- .can_receive = nic_can_receive,
.receive = nic_receive,
- .cleanup = nic_cleanup,
};
-static int e100_nic_init(PCIDevice *pci_dev)
+static void e100_nic_realize(PCIDevice *pci_dev, Error **errp)
{
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
E100PCIDeviceInfo *info = eepro100_get_class(s);
memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
s->vmstate->name = qemu_get_queue(s->nic)->model;
vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
+}
- add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
-
- return 0;
+static void eepro100_instance_init(Object *obj)
+{
+ EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, PCI_DEVICE(obj));
+ device_add_bootindex_property(obj, &s->conf.bootindex,
+ "bootindex", "/ethernet-phy@0",
+ DEVICE(s), NULL);
}
static E100PCIDeviceInfo e100_devices[] = {
info = eepro100_get_class_by_name(object_class_get_name(klass));
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->props = e100_properties;
dc->desc = info->desc;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
k->romfile = "pxe-eepro100.rom";
- k->init = e100_nic_init;
+ k->realize = e100_nic_realize;
k->exit = pci_nic_uninit;
k->device_id = info->device_id;
k->revision = info->revision;
type_info.parent = TYPE_PCI_DEVICE;
type_info.class_init = eepro100_class_init;
type_info.instance_size = sizeof(EEPRO100State);
-
+ type_info.instance_init = eepro100_instance_init;
+
type_register(&type_info);
}
}