Merge remote branch 'mst/for_anthony' into staging
This commit is contained in:
commit
bf3de7f16f
534
hw/eepro100.c
534
hw/eepro100.c
|
@ -87,6 +87,7 @@
|
||||||
#define i82559C 0x82559c
|
#define i82559C 0x82559c
|
||||||
#define i82559ER 0x82559e
|
#define i82559ER 0x82559e
|
||||||
#define i82562 0x82562
|
#define i82562 0x82562
|
||||||
|
#define i82801 0x82801
|
||||||
|
|
||||||
/* Use 64 word EEPROM. TODO: could be a runtime option. */
|
/* Use 64 word EEPROM. TODO: could be a runtime option. */
|
||||||
#define EEPROM_SIZE 64
|
#define EEPROM_SIZE 64
|
||||||
|
@ -117,6 +118,16 @@
|
||||||
#define INT_MASK 0x0100
|
#define INT_MASK 0x0100
|
||||||
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
|
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PCIDeviceInfo pci;
|
||||||
|
uint32_t device;
|
||||||
|
uint16_t device_id;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t stats_size;
|
||||||
|
bool has_extended_tcb_support;
|
||||||
|
bool power_management;
|
||||||
|
} E100PCIDeviceInfo;
|
||||||
|
|
||||||
/* Offsets to the various registers.
|
/* Offsets to the various registers.
|
||||||
All accesses need not be longword aligned. */
|
All accesses need not be longword aligned. */
|
||||||
enum speedo_offsets {
|
enum speedo_offsets {
|
||||||
|
@ -237,10 +248,6 @@ typedef struct {
|
||||||
/* Statistical counters. Also used for wake-up packet (i82559). */
|
/* Statistical counters. Also used for wake-up packet (i82559). */
|
||||||
eepro100_stats_t statistics;
|
eepro100_stats_t statistics;
|
||||||
|
|
||||||
#if 0
|
|
||||||
uint16_t status;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Configuration bytes. */
|
/* Configuration bytes. */
|
||||||
uint8_t configuration[22];
|
uint8_t configuration[22];
|
||||||
|
|
||||||
|
@ -447,136 +454,65 @@ static void eepro100_fcp_interrupt(EEPRO100State * s)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void pci_reset(EEPRO100State * s)
|
static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
|
||||||
{
|
{
|
||||||
uint32_t device = s->device;
|
uint32_t device = s->device;
|
||||||
uint8_t *pci_conf = s->dev.config;
|
uint8_t *pci_conf = s->dev.config;
|
||||||
bool power_management = 1;
|
|
||||||
|
|
||||||
TRACE(OTHER, logout("%p\n", s));
|
TRACE(OTHER, logout("%p\n", s));
|
||||||
|
|
||||||
/* PCI Vendor ID */
|
/* PCI Vendor ID */
|
||||||
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
|
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
|
||||||
/* PCI Device ID depends on device and is set below. */
|
/* PCI Device ID */
|
||||||
|
pci_config_set_device_id(pci_conf, e100_device->device_id);
|
||||||
/* PCI Status */
|
/* PCI Status */
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK);
|
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
||||||
|
PCI_STATUS_FAST_BACK);
|
||||||
/* PCI Revision ID */
|
/* PCI Revision ID */
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08);
|
pci_config_set_revision(pci_conf, e100_device->revision);
|
||||||
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
|
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
|
||||||
/* PCI Latency Timer */
|
/* PCI Latency Timer */
|
||||||
pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
|
pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
|
||||||
/* Capability Pointer */
|
/* Capability Pointer is set by PCI framework. */
|
||||||
/* TODO: revisions with power_management 1 use this but
|
/* Interrupt Line */
|
||||||
* do not set new capability list bit in status register. */
|
/* Interrupt Pin */
|
||||||
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc);
|
pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1); /* interrupt pin A */
|
||||||
/* Minimum Grant */
|
/* Minimum Grant */
|
||||||
pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
|
pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
|
||||||
/* Maximum Latency */
|
/* Maximum Latency */
|
||||||
pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
|
pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
|
||||||
|
|
||||||
|
s->stats_size = e100_device->stats_size;
|
||||||
|
s->has_extended_tcb_support = e100_device->has_extended_tcb_support;
|
||||||
|
|
||||||
switch (device) {
|
switch (device) {
|
||||||
case i82550:
|
case i82550:
|
||||||
/* TODO: check device id. */
|
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
|
|
||||||
/* Revision ID: 0x0c, 0x0d, 0x0e. */
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
|
|
||||||
/* TODO: check size of statistical counters. */
|
|
||||||
s->stats_size = 80;
|
|
||||||
/* TODO: check extended tcb support. */
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82551:
|
case i82551:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
|
|
||||||
/* Revision ID: 0x0f, 0x10. */
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0f);
|
|
||||||
/* TODO: check size of statistical counters. */
|
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82557A:
|
case i82557A:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x01);
|
|
||||||
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
|
|
||||||
power_management = 0;
|
|
||||||
break;
|
|
||||||
case i82557B:
|
case i82557B:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x02);
|
|
||||||
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
|
|
||||||
power_management = 0;
|
|
||||||
break;
|
|
||||||
case i82557C:
|
case i82557C:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x03);
|
|
||||||
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
|
|
||||||
power_management = 0;
|
|
||||||
break;
|
|
||||||
case i82558A:
|
case i82558A:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x04);
|
|
||||||
s->stats_size = 76;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82558B:
|
case i82558B:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x05);
|
|
||||||
s->stats_size = 76;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82559A:
|
case i82559A:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x06);
|
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82559B:
|
case i82559B:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
case i82559ER:
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
case i82562:
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
case i82801:
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x07);
|
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
break;
|
||||||
case i82559C:
|
case i82559C:
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
|
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08);
|
|
||||||
/* TODO: Windows wants revision id 0x0c. */
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0c);
|
|
||||||
#if EEPROM_SIZE > 0
|
#if EEPROM_SIZE > 0
|
||||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x8086);
|
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_INTEL);
|
||||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
|
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
|
||||||
#endif
|
#endif
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82559ER:
|
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
|
|
||||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
|
|
||||||
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x09);
|
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
|
||||||
case i82562:
|
|
||||||
/* TODO: check device id. */
|
|
||||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
|
|
||||||
/* TODO: wrong revision id. */
|
|
||||||
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
|
|
||||||
s->stats_size = 80;
|
|
||||||
s->has_extended_tcb_support = 1;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logout("Device %X is undefined!\n", device);
|
logout("Device %X is undefined!\n", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Standard TxCB. */
|
||||||
|
s->configuration[6] |= BIT(4);
|
||||||
|
|
||||||
|
/* Standard statistical counters. */
|
||||||
s->configuration[6] |= BIT(5);
|
s->configuration[6] |= BIT(5);
|
||||||
|
|
||||||
if (s->stats_size == 80) {
|
if (s->stats_size == 80) {
|
||||||
|
@ -601,14 +537,19 @@ static void pci_reset(EEPRO100State * s)
|
||||||
}
|
}
|
||||||
assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
|
assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
|
||||||
|
|
||||||
if (power_management) {
|
if (e100_device->power_management) {
|
||||||
/* Power Management Capabilities */
|
/* Power Management Capabilities */
|
||||||
pci_set_byte(pci_conf + 0xdc, 0x01);
|
int cfg_offset = 0xdc;
|
||||||
/* Next Item Pointer */
|
int r = pci_add_capability_at_offset(&s->dev, PCI_CAP_ID_PM,
|
||||||
/* Capability ID */
|
cfg_offset, PCI_PM_SIZEOF);
|
||||||
pci_set_word(pci_conf + 0xde, 0x7e21);
|
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. */
|
/* TODO: Power Management Control / Status. */
|
||||||
|
pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
|
||||||
/* TODO: Ethernet Power Consumption Registers (i82559 and later). */
|
/* 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
|
#if EEPROM_SIZE > 0
|
||||||
|
@ -693,21 +634,6 @@ static char *regname(uint32_t addr)
|
||||||
}
|
}
|
||||||
#endif /* DEBUG_EEPRO100 */
|
#endif /* DEBUG_EEPRO100 */
|
||||||
|
|
||||||
#if 0
|
|
||||||
static uint16_t eepro100_read_status(EEPRO100State * s)
|
|
||||||
{
|
|
||||||
uint16_t val = s->status;
|
|
||||||
TRACE(OTHER, logout("val=0x%04x\n", val));
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eepro100_write_status(EEPRO100State * s, uint16_t val)
|
|
||||||
{
|
|
||||||
TRACE(OTHER, logout("val=0x%04x\n", val));
|
|
||||||
s->status = val;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* Command emulation.
|
* Command emulation.
|
||||||
|
@ -901,7 +827,7 @@ static void action_command(EEPRO100State *s)
|
||||||
bool bit_s;
|
bool bit_s;
|
||||||
bool bit_i;
|
bool bit_i;
|
||||||
bool bit_nc;
|
bool bit_nc;
|
||||||
bool success = true;
|
uint16_t ok_status = STATUS_OK;
|
||||||
s->cb_address = s->cu_base + s->cu_offset;
|
s->cb_address = s->cu_base + s->cu_offset;
|
||||||
read_cb(s);
|
read_cb(s);
|
||||||
bit_el = ((s->tx.command & COMMAND_EL) != 0);
|
bit_el = ((s->tx.command & COMMAND_EL) != 0);
|
||||||
|
@ -934,7 +860,7 @@ static void action_command(EEPRO100State *s)
|
||||||
case CmdTx:
|
case CmdTx:
|
||||||
if (bit_nc) {
|
if (bit_nc) {
|
||||||
missing("CmdTx: NC = 0");
|
missing("CmdTx: NC = 0");
|
||||||
success = false;
|
ok_status = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tx_command(s);
|
tx_command(s);
|
||||||
|
@ -951,11 +877,11 @@ static void action_command(EEPRO100State *s)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
missing("undefined command");
|
missing("undefined command");
|
||||||
success = false;
|
ok_status = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Write new status. */
|
/* Write new status. */
|
||||||
stw_phys(s->cb_address, s->tx.status | STATUS_C | (success ? STATUS_OK : 0));
|
stw_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
|
||||||
if (bit_i) {
|
if (bit_i) {
|
||||||
/* CU completed action. */
|
/* CU completed action. */
|
||||||
eepro100_cx_interrupt(s);
|
eepro100_cx_interrupt(s);
|
||||||
|
@ -1364,15 +1290,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
#if 0
|
|
||||||
val = eepro100_read_status(s);
|
|
||||||
#endif
|
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
|
||||||
break;
|
|
||||||
case SCBAck:
|
case SCBAck:
|
||||||
#if 0
|
|
||||||
val = eepro100_read_status(s);
|
|
||||||
#endif
|
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBCmd:
|
case SCBCmd:
|
||||||
|
@ -1415,9 +1333,6 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
#if 0
|
|
||||||
val = eepro100_read_status(s);
|
|
||||||
#endif
|
|
||||||
case SCBCmd:
|
case SCBCmd:
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
|
@ -1441,9 +1356,6 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
#if 0
|
|
||||||
val = eepro100_read_status(s);
|
|
||||||
#endif
|
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBPointer:
|
case SCBPointer:
|
||||||
|
@ -1468,7 +1380,8 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
|
||||||
|
|
||||||
static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
|
static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
/* SCBStatus is readonly. */
|
||||||
|
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&s->mem[addr], &val, sizeof(val));
|
memcpy(&s->mem[addr], &val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1476,9 +1389,6 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
#if 0
|
|
||||||
eepro100_write_status(s, val);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SCBAck:
|
case SCBAck:
|
||||||
eepro100_acknowledge(s);
|
eepro100_acknowledge(s);
|
||||||
|
@ -1510,7 +1420,8 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
|
||||||
|
|
||||||
static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
|
static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
|
||||||
{
|
{
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
/* SCBStatus is readonly. */
|
||||||
|
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&s->mem[addr], &val, sizeof(val));
|
memcpy(&s->mem[addr], &val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1518,9 +1429,7 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
#if 0
|
s->mem[SCBAck] = (val >> 8);
|
||||||
eepro100_write_status(s, val);
|
|
||||||
#endif
|
|
||||||
eepro100_acknowledge(s);
|
eepro100_acknowledge(s);
|
||||||
break;
|
break;
|
||||||
case SCBCmd:
|
case SCBCmd:
|
||||||
|
@ -1711,11 +1620,11 @@ static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
|
||||||
"size=0x%08"FMT_PCIBUS", type=%d\n",
|
"size=0x%08"FMT_PCIBUS", type=%d\n",
|
||||||
region_num, addr, size, type));
|
region_num, addr, size, type));
|
||||||
|
|
||||||
if (region_num == 0) {
|
assert(region_num == 0 || region_num == 2);
|
||||||
/* Map control / status registers. */
|
|
||||||
cpu_register_physical_memory(addr, size, s->mmio_index);
|
/* Map control / status registers and flash. */
|
||||||
s->region[region_num] = addr;
|
cpu_register_physical_memory(addr, size, s->mmio_index);
|
||||||
}
|
s->region[region_num] = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nic_can_receive(VLANClientState *nc)
|
static int nic_can_receive(VLANClientState *nc)
|
||||||
|
@ -1908,9 +1817,6 @@ static const VMStateDescription vmstate_eepro100 = {
|
||||||
VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
|
VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
|
||||||
VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
|
VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
|
||||||
VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
|
VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
|
||||||
#if 0
|
|
||||||
VMSTATE_UINT16(status, EEPRO100State),
|
|
||||||
#endif
|
|
||||||
/* Configuration bytes. */
|
/* Configuration bytes. */
|
||||||
VMSTATE_BUFFER(configuration, EEPRO100State),
|
VMSTATE_BUFFER(configuration, EEPRO100State),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@ -1943,15 +1849,17 @@ static NetClientInfo net_eepro100_info = {
|
||||||
.cleanup = nic_cleanup,
|
.cleanup = nic_cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nic_init(PCIDevice *pci_dev, uint32_t device)
|
static int e100_nic_init(PCIDevice *pci_dev)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
|
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
|
||||||
|
E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
|
||||||
|
pci_dev->qdev.info);
|
||||||
|
|
||||||
TRACE(OTHER, logout("\n"));
|
TRACE(OTHER, logout("\n"));
|
||||||
|
|
||||||
s->device = device;
|
s->device = e100_device->device;
|
||||||
|
|
||||||
pci_reset(s);
|
e100_pci_reset(s, e100_device);
|
||||||
|
|
||||||
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
|
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
|
||||||
* i82559 and later support 64 or 256 word EEPROM. */
|
* i82559 and later support 64 or 256 word EEPROM. */
|
||||||
|
@ -1991,207 +1899,161 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_i82550_init(PCIDevice *pci_dev)
|
static E100PCIDeviceInfo e100_devices[] = {
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82550);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82551_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82551);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82557a_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82557A);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82557b_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82557B);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82557c_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82557C);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82558a_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82558A);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82558b_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82558B);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82559a_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82559A);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82559b_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82559B);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82559c_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82559C);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82559er_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82559ER);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_i82562_init(PCIDevice *pci_dev)
|
|
||||||
{
|
|
||||||
return nic_init(pci_dev, i82562);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PCIDeviceInfo eepro100_info[] = {
|
|
||||||
{
|
{
|
||||||
.qdev.name = "i82550",
|
.pci.qdev.name = "i82550",
|
||||||
.qdev.desc = "Intel i82550 Ethernet",
|
.pci.qdev.desc = "Intel i82550 Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82550,
|
||||||
.init = pci_i82550_init,
|
/* TODO: check device id. */
|
||||||
.exit = pci_nic_uninit,
|
.device_id = PCI_DEVICE_ID_INTEL_82551IT,
|
||||||
.romfile = "gpxe-eepro100-80861209.rom",
|
/* Revision ID: 0x0c, 0x0d, 0x0e. */
|
||||||
.qdev.props = (Property[]) {
|
.revision = 0x0e,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
/* TODO: check size of statistical counters. */
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
.stats_size = 80,
|
||||||
},
|
/* TODO: check extended tcb support. */
|
||||||
|
.has_extended_tcb_support = true,
|
||||||
|
.power_management = true,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82551",
|
.pci.qdev.name = "i82551",
|
||||||
.qdev.desc = "Intel i82551 Ethernet",
|
.pci.qdev.desc = "Intel i82551 Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82551,
|
||||||
.init = pci_i82551_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82551IT,
|
||||||
.exit = pci_nic_uninit,
|
/* Revision ID: 0x0f, 0x10. */
|
||||||
.romfile = "gpxe-eepro100-80861209.rom",
|
.revision = 0x0f,
|
||||||
.qdev.props = (Property[]) {
|
/* TODO: check size of statistical counters. */
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.stats_size = 80,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
.has_extended_tcb_support = true,
|
||||||
},
|
.power_management = true,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82557a",
|
.pci.qdev.name = "i82557a",
|
||||||
.qdev.desc = "Intel i82557A Ethernet",
|
.pci.qdev.desc = "Intel i82557A Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82557A,
|
||||||
.init = pci_i82557a_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x01,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.power_management = false,
|
||||||
.qdev.props = (Property[]) {
|
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82557b",
|
.pci.qdev.name = "i82557b",
|
||||||
.qdev.desc = "Intel i82557B Ethernet",
|
.pci.qdev.desc = "Intel i82557B Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82557B,
|
||||||
.init = pci_i82557b_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x02,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.power_management = false,
|
||||||
.qdev.props = (Property[]) {
|
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82557c",
|
.pci.qdev.name = "i82557c",
|
||||||
.qdev.desc = "Intel i82557C Ethernet",
|
.pci.qdev.desc = "Intel i82557C Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82557C,
|
||||||
.init = pci_i82557c_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x03,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.power_management = false,
|
||||||
.qdev.props = (Property[]) {
|
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82558a",
|
.pci.qdev.name = "i82558a",
|
||||||
.qdev.desc = "Intel i82558A Ethernet",
|
.pci.qdev.desc = "Intel i82558A Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82558A,
|
||||||
.init = pci_i82558a_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x04,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.stats_size = 76,
|
||||||
.qdev.props = (Property[]) {
|
.has_extended_tcb_support = true,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.power_management = true,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82558b",
|
.pci.qdev.name = "i82558b",
|
||||||
.qdev.desc = "Intel i82558B Ethernet",
|
.pci.qdev.desc = "Intel i82558B Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82558B,
|
||||||
.init = pci_i82558b_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x05,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.stats_size = 76,
|
||||||
.qdev.props = (Property[]) {
|
.has_extended_tcb_support = true,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.power_management = true,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82559a",
|
.pci.qdev.name = "i82559a",
|
||||||
.qdev.desc = "Intel i82559A Ethernet",
|
.pci.qdev.desc = "Intel i82559A Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82559A,
|
||||||
.init = pci_i82559a_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x06,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.stats_size = 80,
|
||||||
.qdev.props = (Property[]) {
|
.has_extended_tcb_support = true,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.power_management = true,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82559b",
|
.pci.qdev.name = "i82559b",
|
||||||
.qdev.desc = "Intel i82559B Ethernet",
|
.pci.qdev.desc = "Intel i82559B Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82559B,
|
||||||
.init = pci_i82559b_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x07,
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.stats_size = 80,
|
||||||
.qdev.props = (Property[]) {
|
.has_extended_tcb_support = true,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.power_management = true,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82559c",
|
.pci.qdev.name = "i82559c",
|
||||||
.qdev.desc = "Intel i82559C Ethernet",
|
.pci.qdev.desc = "Intel i82559C Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82559C,
|
||||||
.init = pci_i82559c_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82557,
|
||||||
.exit = pci_nic_uninit,
|
#if 0
|
||||||
.romfile = "gpxe-eepro100-80861229.rom",
|
.revision = 0x08,
|
||||||
.qdev.props = (Property[]) {
|
#endif
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
/* TODO: Windows wants revision id 0x0c. */
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
.revision = 0x0c,
|
||||||
},
|
.stats_size = 80,
|
||||||
|
.has_extended_tcb_support = true,
|
||||||
|
.power_management = true,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82559er",
|
.pci.qdev.name = "i82559er",
|
||||||
.qdev.desc = "Intel i82559ER Ethernet",
|
.pci.qdev.desc = "Intel i82559ER Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82559ER,
|
||||||
.init = pci_i82559er_init,
|
.device_id = PCI_DEVICE_ID_INTEL_82551IT,
|
||||||
.exit = pci_nic_uninit,
|
.revision = 0x09,
|
||||||
.romfile = "gpxe-eepro100-80861209.rom",
|
.stats_size = 80,
|
||||||
.qdev.props = (Property[]) {
|
.has_extended_tcb_support = true,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.power_management = true,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
},
|
|
||||||
},{
|
},{
|
||||||
.qdev.name = "i82562",
|
.pci.qdev.name = "i82562",
|
||||||
.qdev.desc = "Intel i82562 Ethernet",
|
.pci.qdev.desc = "Intel i82562 Ethernet",
|
||||||
.qdev.size = sizeof(EEPRO100State),
|
.device = i82562,
|
||||||
.init = pci_i82562_init,
|
/* TODO: check device id. */
|
||||||
.exit = pci_nic_uninit,
|
.device_id = PCI_DEVICE_ID_INTEL_82551IT,
|
||||||
.romfile = "gpxe-eepro100-80861209.rom",
|
/* TODO: wrong revision id. */
|
||||||
.qdev.props = (Property[]) {
|
.revision = 0x0e,
|
||||||
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
.stats_size = 80,
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
.has_extended_tcb_support = true,
|
||||||
},
|
.power_management = true,
|
||||||
},{
|
},{
|
||||||
/* end of list */
|
/* Toshiba Tecra 8200. */
|
||||||
|
.pci.qdev.name = "i82801",
|
||||||
|
.pci.qdev.desc = "Intel i82801 Ethernet",
|
||||||
|
.device = i82801,
|
||||||
|
.device_id = 0x2449,
|
||||||
|
.revision = 0x03,
|
||||||
|
.stats_size = 80,
|
||||||
|
.has_extended_tcb_support = true,
|
||||||
|
.power_management = true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Property e100_properties[] = {
|
||||||
|
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void eepro100_register_devices(void)
|
static void eepro100_register_devices(void)
|
||||||
{
|
{
|
||||||
pci_qdev_register_many(eepro100_info);
|
size_t i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
|
||||||
|
PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
|
||||||
|
switch (e100_devices[i].device_id) {
|
||||||
|
case PCI_DEVICE_ID_INTEL_82551IT:
|
||||||
|
pci_dev->romfile = "gpxe-eepro100-80861209.rom";
|
||||||
|
break;
|
||||||
|
case PCI_DEVICE_ID_INTEL_82557:
|
||||||
|
pci_dev->romfile = "gpxe-eepro100-80861229.rom";
|
||||||
|
break;
|
||||||
|
case 0x2449:
|
||||||
|
pci_dev->romfile = "gpxe-eepro100-80862449.rom";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pci_dev->init = e100_nic_init;
|
||||||
|
pci_dev->exit = pci_nic_uninit;
|
||||||
|
pci_dev->qdev.props = e100_properties;
|
||||||
|
pci_dev->qdev.size = sizeof(EEPRO100State);
|
||||||
|
pci_qdev_register(pci_dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device_init(eepro100_register_devices)
|
device_init(eepro100_register_devices)
|
||||||
|
|
17
hw/pci.c
17
hw/pci.c
|
@ -1789,12 +1789,10 @@ static int pci_add_option_rom(PCIDevice *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve space and add capability to the linked list in pci config space */
|
/* Reserve space and add capability to the linked list in pci config space */
|
||||||
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,
|
||||||
|
uint8_t offset, uint8_t size)
|
||||||
{
|
{
|
||||||
uint8_t offset = pci_find_space(pdev, size);
|
|
||||||
uint8_t *config = pdev->config + offset;
|
uint8_t *config = pdev->config + offset;
|
||||||
if (!offset)
|
|
||||||
return -ENOSPC;
|
|
||||||
config[PCI_CAP_LIST_ID] = cap_id;
|
config[PCI_CAP_LIST_ID] = cap_id;
|
||||||
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
|
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
|
||||||
pdev->config[PCI_CAPABILITY_LIST] = offset;
|
pdev->config[PCI_CAPABILITY_LIST] = offset;
|
||||||
|
@ -1807,6 +1805,17 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find and reserve space and add capability to the linked list
|
||||||
|
* in pci config space */
|
||||||
|
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
||||||
|
{
|
||||||
|
uint8_t offset = pci_find_space(pdev, size);
|
||||||
|
if (!offset) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
return pci_add_capability_at_offset(pdev, cap_id, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Unlink capability from the pci config space. */
|
/* Unlink capability from the pci config space. */
|
||||||
void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
||||||
{
|
{
|
||||||
|
|
2
hw/pci.h
2
hw/pci.h
|
@ -190,6 +190,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
|
||||||
PCIMapIORegionFunc *map_func);
|
PCIMapIORegionFunc *map_func);
|
||||||
|
|
||||||
int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
|
int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
|
||||||
|
int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
|
||||||
|
uint8_t cap_offset, uint8_t cap_size);
|
||||||
|
|
||||||
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
|
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue