[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] eepro100: Improve handling of different devices
From: |
Stefan Weil |
Subject: |
[Qemu-devel] [PATCH] eepro100: Improve handling of different devices |
Date: |
Sun, 20 Sep 2009 19:48:56 +0200 |
* Fix size of statistical counters and add this size to device state.
* Fix handling of statistical counters.
* Add flag for extended tcb support to device state.
* Fix a number of PCI configuration values.
* Add setup code for new devices.
This patch is a step to synchronize my maintainer version
of eepro100.c (git://repo.or.cz/qemu/ar7.git) with the
version integrated in QEMU.
Signed-off-by: Stefan Weil <address@hidden>
---
hw/eepro100.c | 206 +++++++++++++++++++++++++++++++++++++++++++--------------
1 files changed, 157 insertions(+), 49 deletions(-)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 6aafbef..ba17e8e 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -73,7 +73,10 @@
#define TRACE(flag, command) ((flag) ? (command) : (void)0)
-#define missing(text) assert(!"feature is missing in this emulation: "
text)
+#define UNEXPECTED() logout("%s:%u unexpected\n", __FILE__, __LINE__)
+
+//~ #define missing(text) assert(!"feature is missing in this emulation:
" text)
+#define missing(text) logout("feature is missing in this emulation: "
text "\n")
#define MAX_ETH_FRAME_SIZE 1514
@@ -164,14 +167,15 @@ typedef struct {
typedef struct {
uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
- tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
- tx_multiple_collisions, tx_total_collisions;
+ tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+ tx_multiple_collisions, tx_total_collisions;
uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
- rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
- rx_short_frame_errors;
+ rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+ rx_short_frame_errors;
uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
uint16_t xmt_tco_frames, rcv_tco_frames;
- uint32_t complete;
+ /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
+ uint32_t reserved[4];
} eepro100_stats_t;
typedef enum {
@@ -191,14 +195,12 @@ typedef enum {
typedef struct {
PCIDevice dev;
-#if 1
uint8_t cmd;
uint32_t start;
uint32_t stop;
uint8_t mult[8]; /* multicast mask array */
int mmio_index;
VLANClientState *vc;
-#endif
uint8_t scb_stat; /* SCB stat/ack byte */
uint8_t int_stat; /* PCI interrupt status */
uint32_t region[3]; /* PCI region addresses */
@@ -221,20 +223,22 @@ typedef struct {
/* Statistical counters. Also used for wake-up packet (i82559). */
eepro100_stats_t statistics;
-#if 0
- uint16_t status;
-#endif
/* Configuration bytes. */
uint8_t configuration[22];
/* Data in mem is always in the byte order of the controller (le). */
uint8_t mem[PCI_MEM_SIZE];
+
+ /* Quasi static device properties (no need to save them). */
+ uint16_t stats_size;
+ bool has_extended_tcb_support;
} EEPRO100State;
/* Parameters for nic_save, nic_load. */
static const int eepro100_instance = -1;
-static const int eepro100_version = 20090807;
+/* TODO: Set eepro100_version to 4 as soon as EEPRO100State is finished. */
+static const int eepro100_version = 20090920;
/* Default values for MDI (PHY) registers */
static const uint16_t eepro100_mdi_default[] = {
@@ -255,6 +259,13 @@ static const uint16_t eepro100_mdi_mask[] = {
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
+/* XXX: optimize */
+static void stl_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+ val = cpu_to_le32(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val));
+}
+
#define POLYNOMIAL 0x04c11db6
/* From FreeBSD */
@@ -398,6 +409,7 @@ static void pci_reset(EEPRO100State * s)
{
uint32_t device = s->device;
uint8_t *pci_conf = s->dev.config;
+ bool power_management = 1;
TRACE(OTHER, logout("%p\n", s));
@@ -407,35 +419,18 @@ static void pci_reset(EEPRO100State * s)
/* PCI Command */
PCI_CONFIG_16(PCI_COMMAND, 0x0000);
/* PCI Status */
- PCI_CONFIG_16(PCI_STATUS, 0x2800);
- /* PCI Revision ID */
- PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+ PCI_CONFIG_16(PCI_STATUS, 0x0280);
+ /* PCI Revision ID depends on device. */
/* PCI Class Code */
PCI_CONFIG_8(0x09, 0x00);
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
/* PCI Cache Line Size */
- /* check cache line size!!! */
- //~ PCI_CONFIG_8(0x0c, 0x00);
+ /* Only bit 3 and bit 4 are writable (not emulated). */
/* PCI Latency Timer */
PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks
/* PCI Header Type */
+ PCI_CONFIG_8(PCI_HEADER_TYPE, 0x00);
/* BIST (built-in self test) */
-#if defined(TARGET_I386)
-// !!! workaround for buggy bios
-//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0
-#endif
-#if 0
- /* PCI Base Address Registers */
- /* CSR Memory Mapped Base Address */
- PCI_CONFIG_32(PCI_BASE_ADDRESS_0,
- PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH);
- /* CSR I/O Mapped Base Address */
- PCI_CONFIG_32(PCI_BASE_ADDRESS_1, PCI_ADDRESS_SPACE_IO);
-#if 0
- /* Flash Memory Mapped Base Address */
- PCI_CONFIG_32(PCI_BASE_ADDRESS_2, 0xfffe0000 | PCI_ADDRESS_SPACE_MEM);
-#endif
-#endif
/* Expansion ROM Base Address (depends on boot disable!!!) */
PCI_CONFIG_32(0x30, 0x00000000);
/* Capability Pointer */
@@ -447,50 +442,158 @@ static void pci_reset(EEPRO100State * s)
PCI_CONFIG_8(0x3e, 0x08);
/* Maximum Latency */
PCI_CONFIG_8(0x3f, 0x18);
- /* Power Management Capabilities / Next Item Pointer / Capability ID */
- PCI_CONFIG_32(0xdc, 0x7e210001);
switch (device) {
+ case i82550:
+ // TODO: check device id.
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
+ /* Revision ID: 0x0c, 0x0d, 0x0e. */
+ PCI_CONFIG_8(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:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
+ /* Revision ID: 0x0f, 0x10. */
PCI_CONFIG_8(PCI_REVISION_ID, 0x0f);
+ // TODO: check size of statistical counters.
+ s->stats_size = 80;
+ // TODO: check extended tcb support.
+ s->has_extended_tcb_support = 1;
+ break;
+ case i82557A:
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x01);
+ PCI_CONFIG_8(0x34, 0x00);
+ power_management = 0;
break;
case i82557B:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
PCI_CONFIG_8(PCI_REVISION_ID, 0x02);
+ PCI_CONFIG_8(0x34, 0x00);
+ power_management = 0;
break;
case i82557C:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
PCI_CONFIG_8(PCI_REVISION_ID, 0x03);
+ PCI_CONFIG_8(0x34, 0x00);
+ power_management = 0;
+ break;
+ case i82558A:
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x04);
+ s->stats_size = 76;
+ s->has_extended_tcb_support = 1;
break;
case i82558B:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
- PCI_CONFIG_16(PCI_STATUS, 0x2810);
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
PCI_CONFIG_8(PCI_REVISION_ID, 0x05);
+ s->stats_size = 76;
+ s->has_extended_tcb_support = 1;
+ break;
+ case i82559A:
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x06);
+ s->stats_size = 80;
+ s->has_extended_tcb_support = 1;
+ break;
+ case i82559B:
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x07);
+ s->stats_size = 80;
+ s->has_extended_tcb_support = 1;
break;
case i82559C:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
- PCI_CONFIG_16(PCI_STATUS, 0x2810);
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
+ // TODO: Windows wants revision id 0x0c.
//~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x0c);
+#if EEPROM_SIZE > 0
+ PCI_CONFIG_16(PCI_SUBSYSTEM_VENDOR_ID, 0x8086);
+ PCI_CONFIG_16(PCI_SUBSYSTEM_ID, 0x0040);
+#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_CONFIG_16(PCI_STATUS, 0x2810);
+ //~ pci_config_set_device_id(pci_conf, 0x1030); /* 82559
InBusiness 10/100 !!! */
+ PCI_CONFIG_16(PCI_STATUS, 0x0290);
PCI_CONFIG_8(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_CONFIG_8(PCI_REVISION_ID, 0x0e);
+ s->stats_size = 80;
+ s->has_extended_tcb_support = 1;
break;
- //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029);
- //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030); /* 82559 InBusiness 10/100
*/
default:
logout("Device %X is undefined!\n", device);
}
+ s->configuration[6] |= BIT(5);
+
+ if (s->stats_size == 80) {
+ /* TODO: check TCO Statistical Counters bit. Documentation not clear.
*/
+ if (s->configuration[6] & BIT(2)) {
+ /* TCO statistical counters. */
+ assert(s->configuration[6] & BIT(5));
+ } else {
+ if (s->configuration[6] & BIT(5)) {
+ /* No extended statistical counters, i82557 compatible. */
+ s->stats_size = 64;
+ } else {
+ /* i82558 compatible. */
+ s->stats_size = 76;
+ }
+ }
+ } else {
+ if (s->configuration[6] & BIT(5)) {
+ /* No extended statistical counters. */
+ s->stats_size = 64;
+ }
+ }
+ assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
+
+ if (power_management) {
+ /* Power Management Capabilities */
+ PCI_CONFIG_8(0xdc, 0x01);
+ /* Next Item Pointer */
+ /* Capability ID */
+ PCI_CONFIG_16(0xde, 0x7e21);
+ /* TODO: Power Management Control / Status. */
+ /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
+ }
+
+#if EEPROM_SIZE > 0
if (device == i82557C || device == i82558B || device == i82559C) {
+ // TODO: get vendor id from EEPROM for i82557C or later.
+ // TODO: get device id from EEPROM for i82557C or later.
+ // TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
+ // TODO: header type is determined by EEPROM for i82559.
+ // TODO: get subsystem id from EEPROM for i82557C or later.
+ // TODO: get subsystem vendor id from EEPROM for i82557C or later.
+ // TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
+ // TODO: capability pointer depends on EEPROM for i82558.
logout("Get device id and revision from EEPROM!!!\n");
}
+#endif /* EEPROM_SIZE > 0 */
}
static void nic_selective_reset(EEPRO100State * s)
{
+#if EEPROM_SIZE > 0
size_t i;
uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
//~ eeprom93xx_reset(s->eeprom);
@@ -502,6 +605,7 @@ static void nic_selective_reset(EEPRO100State * s)
}
eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE -
1]));
+#endif /* EEPROM_SIZE > 0 */
memset(s->mem, 0, sizeof(s->mem));
uint32_t val = BIT(21);
@@ -579,11 +683,6 @@ static uint16_t eepro100_read_command(EEPRO100State * s)
}
#endif
-static bool device_supports_eTxCB(EEPRO100State * s)
-{
- return (s->device != i82557B && s->device != i82557C);
-}
-
/* Commands that can be put in a command list entry. */
enum commands {
CmdNOp = 0,
@@ -628,7 +727,8 @@ static void dump_statistics(EEPRO100State * s)
* values which really matter.
* Number of data should check configuration!!!
*/
- cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64);
+ cpu_physical_memory_write(s->statsaddr,
+ (uint8_t *) & s->statistics, s->stats_size);
stl_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
stl_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
stl_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
@@ -673,10 +773,13 @@ static void tx_command(EEPRO100State *s)
}
if (tbd_array == 0xffffffff) {
/* Simplified mode. Was already handled by code above. */
+ } else if (!s->has_extended_tcb_support) {
+ /* Device does not support extend TCB. */
+ UNEXPECTED();
} else {
/* Flexible mode. */
uint8_t tbd_count = 0;
- if (device_supports_eTxCB(s) && !(s->configuration[6] & BIT(4))) {
+ if (!(s->configuration[6] & BIT(4))) {
/* Extended Flexible TCB. */
assert(tcb_bytes == 0);
for (; tbd_count < 2; tbd_count++) {
@@ -848,6 +951,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t
val)
/* Dump statistical counters. */
TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
dump_statistics(s);
+ stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
break;
case CU_CMD_BASE:
/* Load CU base. */
@@ -858,6 +962,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t
val)
/* Dump and reset statistical counters. */
TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
dump_statistics(s);
+ stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
memset(&s->statistics, 0, sizeof(s->statistics));
break;
case CU_SRESUME:
@@ -1682,7 +1787,6 @@ static int nic_load(QEMUFile * f, void *opaque, int
version_id)
qemu_get_be32s(f, &s->statistics.fc_rcv_unsupported);
qemu_get_be16s(f, &s->statistics.xmt_tco_frames);
qemu_get_be16s(f, &s->statistics.rcv_tco_frames);
- qemu_get_be32s(f, &s->statistics.complete);
#if 0
qemu_get_be16s(f, &s->status);
#endif
@@ -1746,7 +1850,6 @@ static void nic_save(QEMUFile * f, void *opaque)
qemu_put_be32s(f, &s->statistics.fc_rcv_unsupported);
qemu_put_be16s(f, &s->statistics.xmt_tco_frames);
qemu_put_be16s(f, &s->statistics.rcv_tco_frames);
- qemu_put_be32s(f, &s->statistics.complete);
#if 0
qemu_put_be16s(f, &s->status);
#endif
@@ -1785,9 +1888,11 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device)
pci_reset(s);
+#if EEPROM_SIZE > 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);
+#endif
/* Handler for memory-mapped I/O */
s->mmio_index =
@@ -1818,6 +1923,7 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device)
register_savevm(s->vc->model, eepro100_instance, eepro100_version,
nic_save, nic_load, s);
+
return 0;
}
@@ -1941,3 +2047,5 @@ static void eepro100_register_devices(void)
}
device_init(eepro100_register_devices)
+
+/* eof */
--
1.5.6.5
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH] eepro100: Improve handling of different devices,
Stefan Weil <=