* * Wake-on-LAN is not implemented.
*/
-#include <stdbool.h> /* bool */
#include <stddef.h> /* offsetof */
#include "hw.h"
#include "pci.h"
typedef struct {
PCIDevice dev;
- uint8_t mult[8]; /* multicast mask array */
+ /* Hash register (multicast mask array, multiple individual addresses). */
+ uint8_t mult[8];
int mmio_index;
NICState *nic;
NICConf conf;
/* PCI Latency Timer */
pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
/* Capability Pointer is set by PCI framework. */
+ /* Interrupt Line */
+ /* Interrupt Pin */
+ pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1); /* interrupt pin A */
/* Minimum Grant */
pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
/* Maximum Latency */
if (e100_device->power_management) {
/* Power Management Capabilities */
- int cfg_offset;
- pci_reserve_capability(&s->dev, PCI_CONFIG_HEADER_SIZE,
- 0xdc - PCI_CONFIG_HEADER_SIZE);
- cfg_offset = pci_add_capability(&s->dev, PCI_CAP_ID_PM, PCI_PM_SIZEOF);
- assert(cfg_offset == 0xdc);
- if (cfg_offset > 0) {
- /* Power Management Capabilities */
- pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
+ int cfg_offset = 0xdc;
+ int r = pci_add_capability_at_offset(&s->dev, PCI_CAP_ID_PM,
+ cfg_offset, PCI_PM_SIZEOF);
+ assert(r >= 0);
+ pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
#if 0 /* TODO: replace dummy code for power management emulation. */
- /* TODO: Power Management Control / Status. */
- pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
- /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
- pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
+ /* TODO: Power Management Control / Status. */
+ pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
+ /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
+ pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
#endif
- }
}
#if EEPROM_SIZE > 0
{
EEPRO100State *s = opaque;
TRACE(OTHER, logout("%p\n", s));
- /* TODO: Clearing of multicast table for selective reset, too? */
+ /* TODO: Clearing of hash register for selective reset, too? */
memset(&s->mult[0], 0, sizeof(s->mult));
nic_selective_reset(s);
}
case CmdConfigure:
cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
sizeof(s->configuration));
- TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[16],
+ ARRAY_SIZE(s->configuration) - 16)));
+ if (s->configuration[20] & BIT(6)) {
+ TRACE(OTHER, logout("Multiple IA bit\n"));
+ }
break;
case CmdMulticastList:
set_multicast_list(s);
"size=0x%08"FMT_PCIBUS", type=%d\n",
region_num, addr, size, type));
- if (region_num == 0) {
- /* Map control / status registers. */
- cpu_register_physical_memory(addr, size, s->mmio_index);
- s->region[region_num] = addr;
- }
+ assert(region_num == 0 || region_num == 2);
+
+ /* Map control / status registers and flash. */
+ cpu_register_physical_memory(addr, size, s->mmio_index);
+ s->region[region_num] = addr;
}
static int nic_can_receive(VLANClientState *nc)
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- /* TODO: check multiple IA bit. */
- if (s->configuration[20] & BIT(6)) {
- missing("Multiple IA bit");
- return -1;
- }
-
if (s->configuration[8] & 0x80) {
/* CSMA is disabled. */
logout("%p received while CSMA is disabled\n", s);
/* Promiscuous: receive all. */
TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
rfd_status |= 0x0004;
+ } else if (s->configuration[20] & BIT(6)) {
+ /* Multiple IA bit set. */
+ unsigned mcast_idx = compute_mcast_idx(buf);
+ assert(mcast_idx < 64);
+ if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+ TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+ } else {
+ TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+ return -1;
+ }
} else {
TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
nic_dump(buf, size)));
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
cpu_unregister_io_memory(s->mmio_index);
- vmstate_unregister(s->vmstate, s);
- eeprom93xx_free(s->eeprom);
+ vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+ eeprom93xx_free(&pci_dev->qdev, s->eeprom);
qemu_del_vlan_client(&s->nic->nc);
return 0;
}
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
* i82559 and later support 64 or 256 word EEPROM. */
- s->eeprom = eeprom93xx_new(EEPROM_SIZE);
+ s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
/* Handler for memory-mapped I/O */
s->mmio_index =
s->vmstate = qemu_malloc(sizeof(vmstate_eepro100));
memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
s->vmstate->name = s->nic->nc.model;
- vmstate_register(-1, s->vmstate, s);
+ vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
return 0;
}