blob: 7db6fb5a706d42bf286a6df0855d484d559bb65e [file] [log] [blame]
ths663e8e52007-04-02 12:35:34 +00001/*
2 * QEMU i8255x (PRO100) emulation
3 *
Stefan Weil230a1672010-03-02 22:37:47 +01004 * Copyright (C) 2006-2010 Stefan Weil
ths663e8e52007-04-02 12:35:34 +00005 *
6 * Portions of the code are copies from grub / etherboot eepro100.c
7 * and linux e100.c.
8 *
Stefan Weil230a1672010-03-02 22:37:47 +01009 * This program is free software: you can redistribute it and/or modify
ths663e8e52007-04-02 12:35:34 +000010 * it under the terms of the GNU General Public License as published by
Stefan Weil230a1672010-03-02 22:37:47 +010011 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) version 3 or any later version.
ths663e8e52007-04-02 12:35:34 +000013 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
Stefan Weil230a1672010-03-02 22:37:47 +010020 * along with this program. If not, see <http://www.gnu.org/licenses/>.
ths663e8e52007-04-02 12:35:34 +000021 *
22 * Tested features (i82559):
Stefan Weil6cded3a2010-03-02 22:37:43 +010023 * PXE boot (i386) ok
ths663e8e52007-04-02 12:35:34 +000024 * Linux networking (i386) ok
25 *
26 * Untested:
27 * non-i386 platforms
28 * Windows networking
29 *
30 * References:
31 *
32 * Intel 8255x 10/100 Mbps Ethernet Controller Family
33 * Open Source Software Developer Manual
Stefan Weilba19f2d2010-03-02 22:37:46 +010034 *
35 * TODO:
36 * * PHY emulation should be separated from nic emulation.
37 * Most nic emulations could share the same phy code.
38 * * i82550 is untested. It is programmed like the i82559.
39 * * i82562 is untested. It is programmed like the i82559.
40 * * Power management (i82558 and later) is not implemented.
41 * * Wake-on-LAN is not implemented.
ths663e8e52007-04-02 12:35:34 +000042 */
43
Stefan Weil78728c92010-03-02 22:38:00 +010044#include <stdbool.h> /* bool */
ths663e8e52007-04-02 12:35:34 +000045#include <stddef.h> /* offsetof */
pbrook87ecb682007-11-17 17:14:51 +000046#include "hw.h"
47#include "pci.h"
48#include "net.h"
ths663e8e52007-04-02 12:35:34 +000049#include "eeprom93xx.h"
50
ths663e8e52007-04-02 12:35:34 +000051#define KiB 1024
52
Stefan Weilaac443e2009-09-19 12:11:36 +020053/* Debug EEPRO100 card. */
Stefan Weilce0e58b2010-03-02 22:37:41 +010054#if 0
55# define DEBUG_EEPRO100
56#endif
ths663e8e52007-04-02 12:35:34 +000057
58#ifdef DEBUG_EEPRO100
Blue Swirl001faf32009-05-13 17:53:17 +000059#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
ths663e8e52007-04-02 12:35:34 +000060#else
Blue Swirl001faf32009-05-13 17:53:17 +000061#define logout(fmt, ...) ((void)0)
ths663e8e52007-04-02 12:35:34 +000062#endif
63
64/* Set flags to 0 to disable debug output. */
Stefan Weilaac443e2009-09-19 12:11:36 +020065#define INT 1 /* interrupt related actions */
66#define MDI 1 /* mdi related actions */
67#define OTHER 1
68#define RXTX 1
69#define EEPROM 1 /* eeprom related actions */
ths663e8e52007-04-02 12:35:34 +000070
71#define TRACE(flag, command) ((flag) ? (command) : (void)0)
72
Kevin Wolf7f1e9d42009-09-23 17:42:42 +020073#define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
ths663e8e52007-04-02 12:35:34 +000074
75#define MAX_ETH_FRAME_SIZE 1514
76
77/* This driver supports several different devices which are declared here. */
Stefan Weilc4c270e2009-09-19 13:02:09 +020078#define i82550 0x82550
ths663e8e52007-04-02 12:35:34 +000079#define i82551 0x82551
Stefan Weilc4c270e2009-09-19 13:02:09 +020080#define i82557A 0x82557a
ths663e8e52007-04-02 12:35:34 +000081#define i82557B 0x82557b
82#define i82557C 0x82557c
Stefan Weilc4c270e2009-09-19 13:02:09 +020083#define i82558A 0x82558a
ths663e8e52007-04-02 12:35:34 +000084#define i82558B 0x82558b
Stefan Weilc4c270e2009-09-19 13:02:09 +020085#define i82559A 0x82559a
86#define i82559B 0x82559b
ths663e8e52007-04-02 12:35:34 +000087#define i82559C 0x82559c
88#define i82559ER 0x82559e
89#define i82562 0x82562
90
Stefan Weilaac443e2009-09-19 12:11:36 +020091/* Use 64 word EEPROM. TODO: could be a runtime option. */
ths663e8e52007-04-02 12:35:34 +000092#define EEPROM_SIZE 64
93
94#define PCI_MEM_SIZE (4 * KiB)
95#define PCI_IO_SIZE 64
96#define PCI_FLASH_SIZE (128 * KiB)
97
98#define BIT(n) (1 << (n))
99#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
100
101/* The SCB accepts the following controls for the Tx and Rx units: */
102#define CU_NOP 0x0000 /* No operation. */
103#define CU_START 0x0010 /* CU start. */
104#define CU_RESUME 0x0020 /* CU resume. */
105#define CU_STATSADDR 0x0040 /* Load dump counters address. */
106#define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */
107#define CU_CMD_BASE 0x0060 /* Load CU base address. */
108#define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */
109#define CU_SRESUME 0x00a0 /* CU static resume. */
110
111#define RU_NOP 0x0000
112#define RX_START 0x0001
113#define RX_RESUME 0x0002
Stefan Weile8240122010-03-02 22:37:53 +0100114#define RU_ABORT 0x0004
ths663e8e52007-04-02 12:35:34 +0000115#define RX_ADDR_LOAD 0x0006
116#define RX_RESUMENR 0x0007
117#define INT_MASK 0x0100
118#define DRVR_INT 0x0200 /* Driver generated interrupt. */
119
ths663e8e52007-04-02 12:35:34 +0000120/* Offsets to the various registers.
121 All accesses need not be longword aligned. */
122enum speedo_offsets {
Stefan Weil0908bba2010-03-02 22:37:42 +0100123 SCBStatus = 0, /* Status Word. */
ths663e8e52007-04-02 12:35:34 +0000124 SCBAck = 1,
125 SCBCmd = 2, /* Rx/Command Unit command and status. */
126 SCBIntmask = 3,
127 SCBPointer = 4, /* General purpose pointer. */
128 SCBPort = 8, /* Misc. commands and operands. */
Stefan Weil0908bba2010-03-02 22:37:42 +0100129 SCBflash = 12, /* Flash memory control. */
130 SCBeeprom = 14, /* EEPROM control. */
ths663e8e52007-04-02 12:35:34 +0000131 SCBCtrlMDI = 16, /* MDI interface control. */
132 SCBEarlyRx = 20, /* Early receive byte count. */
Stefan Weil0908bba2010-03-02 22:37:42 +0100133 SCBFlow = 24, /* Flow Control. */
134 SCBpmdr = 27, /* Power Management Driver. */
135 SCBgctrl = 28, /* General Control. */
136 SCBgstat = 29, /* General Status. */
ths663e8e52007-04-02 12:35:34 +0000137};
138
139/* A speedo3 transmit buffer descriptor with two buffers... */
140typedef struct {
141 uint16_t status;
142 uint16_t command;
143 uint32_t link; /* void * */
Stefan Weil7b8737d2009-12-20 16:52:24 +0100144 uint32_t tbd_array_addr; /* transmit buffer descriptor array address. */
ths663e8e52007-04-02 12:35:34 +0000145 uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */
146 uint8_t tx_threshold; /* transmit threshold */
147 uint8_t tbd_count; /* TBD number */
Stefan Weile7493b22010-03-02 22:37:59 +0100148#if 0
149 /* This constitutes two "TBD" entries: hdr and data */
150 uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */
151 int32_t tx_buf_size0; /* Length of Tx hdr. */
152 uint32_t tx_buf_addr1; /* void *, data to be transmitted. */
153 int32_t tx_buf_size1; /* Length of Tx data. */
154#endif
Anthony Liguoric227f092009-10-01 16:12:16 -0500155} eepro100_tx_t;
ths663e8e52007-04-02 12:35:34 +0000156
157/* Receive frame descriptor. */
158typedef struct {
159 int16_t status;
160 uint16_t command;
161 uint32_t link; /* struct RxFD * */
162 uint32_t rx_buf_addr; /* void * */
163 uint16_t count;
164 uint16_t size;
165 char packet[MAX_ETH_FRAME_SIZE + 4];
Anthony Liguoric227f092009-10-01 16:12:16 -0500166} eepro100_rx_t;
ths663e8e52007-04-02 12:35:34 +0000167
Stefan Weilced52962010-03-02 22:37:49 +0100168typedef enum {
169 COMMAND_EL = BIT(15),
170 COMMAND_S = BIT(14),
171 COMMAND_I = BIT(13),
172 COMMAND_NC = BIT(4),
173 COMMAND_SF = BIT(3),
174 COMMAND_CMD = BITS(2, 0),
175} scb_command_bit;
176
177typedef enum {
178 STATUS_C = BIT(15),
179 STATUS_OK = BIT(13),
180} scb_status_bit;
181
ths663e8e52007-04-02 12:35:34 +0000182typedef struct {
183 uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
Stefan Weilcc02c662010-03-02 22:37:55 +0100184 tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
185 tx_multiple_collisions, tx_total_collisions;
ths663e8e52007-04-02 12:35:34 +0000186 uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
Stefan Weilcc02c662010-03-02 22:37:55 +0100187 rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
188 rx_short_frame_errors;
ths663e8e52007-04-02 12:35:34 +0000189 uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
190 uint16_t xmt_tco_frames, rcv_tco_frames;
Stefan Weilba42b642009-10-30 13:36:21 +0100191 /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
192 uint32_t reserved[4];
Anthony Liguoric227f092009-10-01 16:12:16 -0500193} eepro100_stats_t;
ths663e8e52007-04-02 12:35:34 +0000194
195typedef enum {
196 cu_idle = 0,
197 cu_suspended = 1,
198 cu_active = 2,
199 cu_lpq_active = 2,
200 cu_hqp_active = 3
Anthony Liguoric227f092009-10-01 16:12:16 -0500201} cu_state_t;
ths663e8e52007-04-02 12:35:34 +0000202
203typedef enum {
204 ru_idle = 0,
205 ru_suspended = 1,
206 ru_no_resources = 2,
207 ru_ready = 4
Anthony Liguoric227f092009-10-01 16:12:16 -0500208} ru_state_t;
ths663e8e52007-04-02 12:35:34 +0000209
ths663e8e52007-04-02 12:35:34 +0000210typedef struct {
Juan Quintela273a2142009-08-24 18:42:37 +0200211 PCIDevice dev;
ths663e8e52007-04-02 12:35:34 +0000212 uint8_t mult[8]; /* multicast mask array */
213 int mmio_index;
Mark McLoughline00e3652009-11-25 18:49:16 +0000214 NICState *nic;
Gerd Hoffmann508ef932009-10-21 15:25:36 +0200215 NICConf conf;
ths663e8e52007-04-02 12:35:34 +0000216 uint8_t scb_stat; /* SCB stat/ack byte */
217 uint8_t int_stat; /* PCI interrupt status */
Stefan Weil3706c432009-10-09 19:49:58 +0200218 /* region must not be saved by nic_save. */
ths663e8e52007-04-02 12:35:34 +0000219 uint32_t region[3]; /* PCI region addresses */
ths663e8e52007-04-02 12:35:34 +0000220 uint16_t mdimem[32];
Anthony Liguoric227f092009-10-01 16:12:16 -0500221 eeprom_t *eeprom;
ths663e8e52007-04-02 12:35:34 +0000222 uint32_t device; /* device variant */
223 uint32_t pointer;
224 /* (cu_base + cu_offset) address the next command block in the command block list. */
225 uint32_t cu_base; /* CU base address */
226 uint32_t cu_offset; /* CU address offset */
227 /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
228 uint32_t ru_base; /* RU base address */
229 uint32_t ru_offset; /* RU address offset */
Anthony Liguoric227f092009-10-01 16:12:16 -0500230 uint32_t statsaddr; /* pointer to eepro100_stats_t */
Stefan Weilba42b642009-10-30 13:36:21 +0100231
Stefan Weilf3a52e52009-12-20 16:52:22 +0100232 /* Temporary status information (no need to save these values),
233 * used while processing CU commands. */
234 eepro100_tx_t tx; /* transmit buffer descriptor */
235 uint32_t cb_address; /* = cu_base + cu_offset */
236
Stefan Weilba42b642009-10-30 13:36:21 +0100237 /* Statistical counters. Also used for wake-up packet (i82559). */
238 eepro100_stats_t statistics;
239
ths663e8e52007-04-02 12:35:34 +0000240#if 0
241 uint16_t status;
242#endif
243
244 /* Configuration bytes. */
245 uint8_t configuration[22];
246
247 /* Data in mem is always in the byte order of the controller (le). */
248 uint8_t mem[PCI_MEM_SIZE];
Juan Quintela151b2982009-10-19 15:37:57 +0200249 /* vmstate for each particular nic */
250 VMStateDescription *vmstate;
Stefan Weilba42b642009-10-30 13:36:21 +0100251
252 /* Quasi static device properties (no need to save them). */
253 uint16_t stats_size;
254 bool has_extended_tcb_support;
ths663e8e52007-04-02 12:35:34 +0000255} EEPRO100State;
256
Stefan Weil6cded3a2010-03-02 22:37:43 +0100257/* Word indices in EEPROM. */
258typedef enum {
259 EEPROM_CNFG_MDIX = 0x03,
260 EEPROM_ID = 0x05,
261 EEPROM_PHY_ID = 0x06,
262 EEPROM_VENDOR_ID = 0x0c,
263 EEPROM_CONFIG_ASF = 0x0d,
264 EEPROM_DEVICE_ID = 0x23,
265 EEPROM_SMBUS_ADDR = 0x90,
266} EEPROMOffset;
267
Stefan Weilb1e87012010-03-02 22:37:51 +0100268/* Bit values for EEPROM ID word. */
269typedef enum {
270 EEPROM_ID_MDM = BIT(0), /* Modem */
271 EEPROM_ID_STB = BIT(1), /* Standby Enable */
272 EEPROM_ID_WMR = BIT(2), /* ??? */
273 EEPROM_ID_WOL = BIT(5), /* Wake on LAN */
274 EEPROM_ID_DPD = BIT(6), /* Deep Power Down */
275 EEPROM_ID_ALT = BIT(7), /* */
276 /* BITS(10, 8) device revision */
277 EEPROM_ID_BD = BIT(11), /* boot disable */
278 EEPROM_ID_ID = BIT(13), /* id bit */
279 /* BITS(15, 14) signature */
280 EEPROM_ID_VALID = BIT(14), /* signature for valid eeprom */
281} eeprom_id_bit;
282
ths663e8e52007-04-02 12:35:34 +0000283/* Default values for MDI (PHY) registers */
284static const uint16_t eepro100_mdi_default[] = {
285 /* MDI Registers 0 - 6, 7 */
286 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
287 /* MDI Registers 8 - 15 */
288 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
289 /* MDI Registers 16 - 31 */
290 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
291 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
292};
293
294/* Readonly mask for MDI (PHY) registers */
295static const uint16_t eepro100_mdi_mask[] = {
296 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
297 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
298 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
299 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
300};
301
Stefan Weilba42b642009-10-30 13:36:21 +0100302/* XXX: optimize */
303static void stl_le_phys(target_phys_addr_t addr, uint32_t val)
304{
305 val = cpu_to_le32(val);
306 cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val));
307}
308
ths663e8e52007-04-02 12:35:34 +0000309#define POLYNOMIAL 0x04c11db6
310
311/* From FreeBSD */
312/* XXX: optimize */
Stefan Weil7b8737d2009-12-20 16:52:24 +0100313static unsigned compute_mcast_idx(const uint8_t * ep)
ths663e8e52007-04-02 12:35:34 +0000314{
315 uint32_t crc;
316 int carry, i, j;
317 uint8_t b;
318
319 crc = 0xffffffff;
320 for (i = 0; i < 6; i++) {
321 b = *ep++;
322 for (j = 0; j < 8; j++) {
323 carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
324 crc <<= 1;
325 b >>= 1;
Stefan Weilaac443e2009-09-19 12:11:36 +0200326 if (carry) {
ths663e8e52007-04-02 12:35:34 +0000327 crc = ((crc ^ POLYNOMIAL) | carry);
Stefan Weilaac443e2009-09-19 12:11:36 +0200328 }
ths663e8e52007-04-02 12:35:34 +0000329 }
330 }
Stefan Weil7b8737d2009-12-20 16:52:24 +0100331 return (crc & BITS(7, 2)) >> 2;
ths663e8e52007-04-02 12:35:34 +0000332}
333
334#if defined(DEBUG_EEPRO100)
335static const char *nic_dump(const uint8_t * buf, unsigned size)
336{
337 static char dump[3 * 16 + 1];
338 char *p = &dump[0];
Stefan Weilaac443e2009-09-19 12:11:36 +0200339 if (size > 16) {
ths663e8e52007-04-02 12:35:34 +0000340 size = 16;
Stefan Weilaac443e2009-09-19 12:11:36 +0200341 }
ths663e8e52007-04-02 12:35:34 +0000342 while (size-- > 0) {
343 p += sprintf(p, " %02x", *buf++);
344 }
345 return dump;
346}
347#endif /* DEBUG_EEPRO100 */
348
349enum scb_stat_ack {
350 stat_ack_not_ours = 0x00,
351 stat_ack_sw_gen = 0x04,
352 stat_ack_rnr = 0x10,
353 stat_ack_cu_idle = 0x20,
354 stat_ack_frame_rx = 0x40,
355 stat_ack_cu_cmd_done = 0x80,
356 stat_ack_not_present = 0xFF,
357 stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
358 stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
359};
360
361static void disable_interrupt(EEPRO100State * s)
362{
363 if (s->int_stat) {
Stefan Weilaac443e2009-09-19 12:11:36 +0200364 TRACE(INT, logout("interrupt disabled\n"));
Juan Quintela273a2142009-08-24 18:42:37 +0200365 qemu_irq_lower(s->dev.irq[0]);
ths663e8e52007-04-02 12:35:34 +0000366 s->int_stat = 0;
367 }
368}
369
370static void enable_interrupt(EEPRO100State * s)
371{
372 if (!s->int_stat) {
Stefan Weilaac443e2009-09-19 12:11:36 +0200373 TRACE(INT, logout("interrupt enabled\n"));
Juan Quintela273a2142009-08-24 18:42:37 +0200374 qemu_irq_raise(s->dev.irq[0]);
ths663e8e52007-04-02 12:35:34 +0000375 s->int_stat = 1;
376 }
377}
378
379static void eepro100_acknowledge(EEPRO100State * s)
380{
381 s->scb_stat &= ~s->mem[SCBAck];
382 s->mem[SCBAck] = s->scb_stat;
383 if (s->scb_stat == 0) {
384 disable_interrupt(s);
385 }
386}
387
Stefan Weile715c8e2010-03-02 22:37:52 +0100388static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
ths663e8e52007-04-02 12:35:34 +0000389{
390 uint8_t mask = ~s->mem[SCBIntmask];
Stefan Weile715c8e2010-03-02 22:37:52 +0100391 s->mem[SCBAck] |= status;
392 status = s->scb_stat = s->mem[SCBAck];
393 status &= (mask | 0x0f);
Stefan Weile7493b22010-03-02 22:37:59 +0100394#if 0
395 status &= (~s->mem[SCBIntmask] | 0x0xf);
396#endif
Stefan Weile715c8e2010-03-02 22:37:52 +0100397 if (status && (mask & 0x01)) {
ths663e8e52007-04-02 12:35:34 +0000398 /* SCB mask and SCB Bit M do not disable interrupt. */
399 enable_interrupt(s);
400 } else if (s->int_stat) {
401 disable_interrupt(s);
402 }
403}
404
405static void eepro100_cx_interrupt(EEPRO100State * s)
406{
407 /* CU completed action command. */
408 /* Transmit not ok (82557 only, not in emulation). */
409 eepro100_interrupt(s, 0x80);
410}
411
412static void eepro100_cna_interrupt(EEPRO100State * s)
413{
414 /* CU left the active state. */
415 eepro100_interrupt(s, 0x20);
416}
417
418static void eepro100_fr_interrupt(EEPRO100State * s)
419{
420 /* RU received a complete frame. */
421 eepro100_interrupt(s, 0x40);
422}
423
ths663e8e52007-04-02 12:35:34 +0000424static void eepro100_rnr_interrupt(EEPRO100State * s)
425{
426 /* RU is not ready. */
427 eepro100_interrupt(s, 0x10);
428}
ths663e8e52007-04-02 12:35:34 +0000429
430static void eepro100_mdi_interrupt(EEPRO100State * s)
431{
432 /* MDI completed read or write cycle. */
433 eepro100_interrupt(s, 0x08);
434}
435
436static void eepro100_swi_interrupt(EEPRO100State * s)
437{
438 /* Software has requested an interrupt. */
439 eepro100_interrupt(s, 0x04);
440}
441
442#if 0
443static void eepro100_fcp_interrupt(EEPRO100State * s)
444{
445 /* Flow control pause interrupt (82558 and later). */
446 eepro100_interrupt(s, 0x01);
447}
448#endif
449
450static void pci_reset(EEPRO100State * s)
451{
452 uint32_t device = s->device;
Juan Quintela273a2142009-08-24 18:42:37 +0200453 uint8_t *pci_conf = s->dev.config;
Stefan Weilba42b642009-10-30 13:36:21 +0100454 bool power_management = 1;
ths663e8e52007-04-02 12:35:34 +0000455
Stefan Weilaac443e2009-09-19 12:11:36 +0200456 TRACE(OTHER, logout("%p\n", s));
ths663e8e52007-04-02 12:35:34 +0000457
458 /* PCI Vendor ID */
aliguorideb54392009-01-26 15:37:35 +0000459 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
Stefan Weild6fd1e62009-09-01 22:16:10 +0200460 /* PCI Device ID depends on device and is set below. */
ths663e8e52007-04-02 12:35:34 +0000461 /* PCI Status */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200462 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK);
ths663e8e52007-04-02 12:35:34 +0000463 /* PCI Revision ID */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200464 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08);
blueswir1173a5432009-02-01 19:26:20 +0000465 pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
ths663e8e52007-04-02 12:35:34 +0000466 /* PCI Latency Timer */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200467 pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
ths663e8e52007-04-02 12:35:34 +0000468 /* Capability Pointer */
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200469 /* TODO: revisions with power_management 1 use this but
470 * do not set new capability list bit in status register. */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200471 pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc);
ths663e8e52007-04-02 12:35:34 +0000472 /* Minimum Grant */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200473 pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
ths663e8e52007-04-02 12:35:34 +0000474 /* Maximum Latency */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200475 pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
ths663e8e52007-04-02 12:35:34 +0000476
477 switch (device) {
Stefan Weilba42b642009-10-30 13:36:21 +0100478 case i82550:
Stefan Weile7493b22010-03-02 22:37:59 +0100479 /* TODO: check device id. */
Stefan Weilba42b642009-10-30 13:36:21 +0100480 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
481 /* Revision ID: 0x0c, 0x0d, 0x0e. */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200482 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
Stefan Weile7493b22010-03-02 22:37:59 +0100483 /* TODO: check size of statistical counters. */
Stefan Weilba42b642009-10-30 13:36:21 +0100484 s->stats_size = 80;
Stefan Weile7493b22010-03-02 22:37:59 +0100485 /* TODO: check extended tcb support. */
Stefan Weilba42b642009-10-30 13:36:21 +0100486 s->has_extended_tcb_support = 1;
487 break;
ths663e8e52007-04-02 12:35:34 +0000488 case i82551:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200489 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
Stefan Weilba42b642009-10-30 13:36:21 +0100490 /* Revision ID: 0x0f, 0x10. */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200491 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0f);
Stefan Weile7493b22010-03-02 22:37:59 +0100492 /* TODO: check size of statistical counters. */
Stefan Weilba42b642009-10-30 13:36:21 +0100493 s->stats_size = 80;
494 s->has_extended_tcb_support = 1;
495 break;
496 case i82557A:
497 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200498 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x01);
499 pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
Stefan Weilba42b642009-10-30 13:36:21 +0100500 power_management = 0;
ths663e8e52007-04-02 12:35:34 +0000501 break;
502 case i82557B:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200503 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200504 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x02);
505 pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
Stefan Weilba42b642009-10-30 13:36:21 +0100506 power_management = 0;
ths663e8e52007-04-02 12:35:34 +0000507 break;
508 case i82557C:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200509 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200510 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x03);
511 pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
Stefan Weilba42b642009-10-30 13:36:21 +0100512 power_management = 0;
513 break;
514 case i82558A:
515 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200516 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200517 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200518 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x04);
Stefan Weilba42b642009-10-30 13:36:21 +0100519 s->stats_size = 76;
520 s->has_extended_tcb_support = 1;
ths663e8e52007-04-02 12:35:34 +0000521 break;
522 case i82558B:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200523 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200524 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200525 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200526 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x05);
Stefan Weilba42b642009-10-30 13:36:21 +0100527 s->stats_size = 76;
528 s->has_extended_tcb_support = 1;
529 break;
530 case i82559A:
531 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200532 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200533 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200534 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x06);
Stefan Weilba42b642009-10-30 13:36:21 +0100535 s->stats_size = 80;
536 s->has_extended_tcb_support = 1;
537 break;
538 case i82559B:
539 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200540 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200541 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200542 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x07);
Stefan Weilba42b642009-10-30 13:36:21 +0100543 s->stats_size = 80;
544 s->has_extended_tcb_support = 1;
ths663e8e52007-04-02 12:35:34 +0000545 break;
546 case i82559C:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200547 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200548 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200549 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200550 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08);
Stefan Weile7493b22010-03-02 22:37:59 +0100551 /* TODO: Windows wants revision id 0x0c. */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200552 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0c);
Stefan Weilba42b642009-10-30 13:36:21 +0100553#if EEPROM_SIZE > 0
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200554 pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x8086);
555 pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
Stefan Weilba42b642009-10-30 13:36:21 +0100556#endif
557 s->stats_size = 80;
558 s->has_extended_tcb_support = 1;
ths663e8e52007-04-02 12:35:34 +0000559 break;
560 case i82559ER:
Stefan Weild6fd1e62009-09-01 22:16:10 +0200561 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200562 pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
Michael S. Tsirkin508cc6b2009-12-10 17:52:10 +0200563 PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200564 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x09);
Stefan Weilba42b642009-10-30 13:36:21 +0100565 s->stats_size = 80;
566 s->has_extended_tcb_support = 1;
ths663e8e52007-04-02 12:35:34 +0000567 break;
Stefan Weilba42b642009-10-30 13:36:21 +0100568 case i82562:
Stefan Weile7493b22010-03-02 22:37:59 +0100569 /* TODO: check device id. */
Stefan Weilba42b642009-10-30 13:36:21 +0100570 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
571 /* TODO: wrong revision id. */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200572 pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
Stefan Weilba42b642009-10-30 13:36:21 +0100573 s->stats_size = 80;
574 s->has_extended_tcb_support = 1;
575 break;
ths663e8e52007-04-02 12:35:34 +0000576 default:
577 logout("Device %X is undefined!\n", device);
578 }
579
Stefan Weilba42b642009-10-30 13:36:21 +0100580 s->configuration[6] |= BIT(5);
581
582 if (s->stats_size == 80) {
583 /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
584 if (s->configuration[6] & BIT(2)) {
585 /* TCO statistical counters. */
586 assert(s->configuration[6] & BIT(5));
587 } else {
588 if (s->configuration[6] & BIT(5)) {
589 /* No extended statistical counters, i82557 compatible. */
590 s->stats_size = 64;
591 } else {
592 /* i82558 compatible. */
593 s->stats_size = 76;
594 }
595 }
596 } else {
597 if (s->configuration[6] & BIT(5)) {
598 /* No extended statistical counters. */
599 s->stats_size = 64;
600 }
601 }
602 assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
603
604 if (power_management) {
605 /* Power Management Capabilities */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200606 pci_set_byte(pci_conf + 0xdc, 0x01);
Stefan Weilba42b642009-10-30 13:36:21 +0100607 /* Next Item Pointer */
608 /* Capability ID */
Michael S. Tsirkin15e89f52010-03-03 14:00:21 +0200609 pci_set_word(pci_conf + 0xde, 0x7e21);
Stefan Weilba42b642009-10-30 13:36:21 +0100610 /* TODO: Power Management Control / Status. */
611 /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
612 }
613
614#if EEPROM_SIZE > 0
ths663e8e52007-04-02 12:35:34 +0000615 if (device == i82557C || device == i82558B || device == i82559C) {
Stefan Weile7493b22010-03-02 22:37:59 +0100616 /*
617 TODO: get vendor id from EEPROM for i82557C or later.
618 TODO: get device id from EEPROM for i82557C or later.
619 TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
620 TODO: header type is determined by EEPROM for i82559.
621 TODO: get subsystem id from EEPROM for i82557C or later.
622 TODO: get subsystem vendor id from EEPROM for i82557C or later.
623 TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
624 TODO: capability pointer depends on EEPROM for i82558.
625 */
ths663e8e52007-04-02 12:35:34 +0000626 logout("Get device id and revision from EEPROM!!!\n");
627 }
Stefan Weilba42b642009-10-30 13:36:21 +0100628#endif /* EEPROM_SIZE > 0 */
ths663e8e52007-04-02 12:35:34 +0000629}
630
631static void nic_selective_reset(EEPRO100State * s)
632{
633 size_t i;
634 uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
Stefan Weile7493b22010-03-02 22:37:59 +0100635#if 0
636 eeprom93xx_reset(s->eeprom);
637#endif
Gerd Hoffmann508ef932009-10-21 15:25:36 +0200638 memcpy(eeprom_contents, s->conf.macaddr.a, 6);
Stefan Weilb1e87012010-03-02 22:37:51 +0100639 eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
=?UTF-8?q?Reimar=20D=C3=B6ffinger?=f4e94df2009-09-12 15:42:01 +0200640 if (s->device == i82557B || s->device == i82557C)
641 eeprom_contents[5] = 0x0100;
Stefan Weil6cded3a2010-03-02 22:37:43 +0100642 eeprom_contents[EEPROM_PHY_ID] = 1;
ths663e8e52007-04-02 12:35:34 +0000643 uint16_t sum = 0;
644 for (i = 0; i < EEPROM_SIZE - 1; i++) {
645 sum += eeprom_contents[i];
646 }
647 eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
Stefan Weilaac443e2009-09-19 12:11:36 +0200648 TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
ths663e8e52007-04-02 12:35:34 +0000649
650 memset(s->mem, 0, sizeof(s->mem));
651 uint32_t val = BIT(21);
652 memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
653
654 assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
655 memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
656}
657
658static void nic_reset(void *opaque)
659{
Juan Quintela769cf7a2009-08-24 18:42:36 +0200660 EEPRO100State *s = opaque;
Stefan Weilaac443e2009-09-19 12:11:36 +0200661 TRACE(OTHER, logout("%p\n", s));
Stefan Weil7b8737d2009-12-20 16:52:24 +0100662 /* TODO: Clearing of multicast table for selective reset, too? */
663 memset(&s->mult[0], 0, sizeof(s->mult));
ths663e8e52007-04-02 12:35:34 +0000664 nic_selective_reset(s);
665}
666
667#if defined(DEBUG_EEPRO100)
Stefan Weilb8f6ba02009-11-27 12:06:02 +0100668static const char * const e100_reg[PCI_IO_SIZE / 4] = {
ths663e8e52007-04-02 12:35:34 +0000669 "Command/Status",
670 "General Pointer",
671 "Port",
672 "EEPROM/Flash Control",
673 "MDI Control",
674 "Receive DMA Byte Count",
Stefan Weilb8f6ba02009-11-27 12:06:02 +0100675 "Flow Control",
ths663e8e52007-04-02 12:35:34 +0000676 "General Status/Control"
677};
678
679static char *regname(uint32_t addr)
680{
David Benjaminec169282009-11-25 21:20:10 -0500681 static char buf[32];
ths663e8e52007-04-02 12:35:34 +0000682 if (addr < PCI_IO_SIZE) {
Stefan Weilb8f6ba02009-11-27 12:06:02 +0100683 const char *r = e100_reg[addr / 4];
ths663e8e52007-04-02 12:35:34 +0000684 if (r != 0) {
Stefan Weil41cbc232009-09-19 12:29:59 +0200685 snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
ths663e8e52007-04-02 12:35:34 +0000686 } else {
Stefan Weil41cbc232009-09-19 12:29:59 +0200687 snprintf(buf, sizeof(buf), "0x%02x", addr);
ths663e8e52007-04-02 12:35:34 +0000688 }
689 } else {
Stefan Weil41cbc232009-09-19 12:29:59 +0200690 snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
ths663e8e52007-04-02 12:35:34 +0000691 }
692 return buf;
693}
694#endif /* DEBUG_EEPRO100 */
695
696#if 0
697static uint16_t eepro100_read_status(EEPRO100State * s)
698{
699 uint16_t val = s->status;
Stefan Weilaac443e2009-09-19 12:11:36 +0200700 TRACE(OTHER, logout("val=0x%04x\n", val));
ths663e8e52007-04-02 12:35:34 +0000701 return val;
702}
703
704static void eepro100_write_status(EEPRO100State * s, uint16_t val)
705{
Stefan Weilaac443e2009-09-19 12:11:36 +0200706 TRACE(OTHER, logout("val=0x%04x\n", val));
ths663e8e52007-04-02 12:35:34 +0000707 s->status = val;
708}
709#endif
710
711/*****************************************************************************
712 *
713 * Command emulation.
714 *
715 ****************************************************************************/
716
717#if 0
718static uint16_t eepro100_read_command(EEPRO100State * s)
719{
720 uint16_t val = 0xffff;
Stefan Weile7493b22010-03-02 22:37:59 +0100721 TRACE(OTHER, logout("val=0x%04x\n", val));
ths663e8e52007-04-02 12:35:34 +0000722 return val;
723}
724#endif
725
726/* Commands that can be put in a command list entry. */
727enum commands {
728 CmdNOp = 0,
729 CmdIASetup = 1,
730 CmdConfigure = 2,
731 CmdMulticastList = 3,
732 CmdTx = 4,
733 CmdTDR = 5, /* load microcode */
734 CmdDump = 6,
735 CmdDiagnose = 7,
736
737 /* And some extra flags: */
738 CmdSuspend = 0x4000, /* Suspend after completion. */
739 CmdIntr = 0x2000, /* Interrupt after completion. */
740 CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */
741};
742
Anthony Liguoric227f092009-10-01 16:12:16 -0500743static cu_state_t get_cu_state(EEPRO100State * s)
ths663e8e52007-04-02 12:35:34 +0000744{
Stefan Weilced52962010-03-02 22:37:49 +0100745 return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
ths663e8e52007-04-02 12:35:34 +0000746}
747
Anthony Liguoric227f092009-10-01 16:12:16 -0500748static void set_cu_state(EEPRO100State * s, cu_state_t state)
ths663e8e52007-04-02 12:35:34 +0000749{
Stefan Weilced52962010-03-02 22:37:49 +0100750 s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
ths663e8e52007-04-02 12:35:34 +0000751}
752
Anthony Liguoric227f092009-10-01 16:12:16 -0500753static ru_state_t get_ru_state(EEPRO100State * s)
ths663e8e52007-04-02 12:35:34 +0000754{
Stefan Weilced52962010-03-02 22:37:49 +0100755 return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
ths663e8e52007-04-02 12:35:34 +0000756}
757
Anthony Liguoric227f092009-10-01 16:12:16 -0500758static void set_ru_state(EEPRO100State * s, ru_state_t state)
ths663e8e52007-04-02 12:35:34 +0000759{
Stefan Weilced52962010-03-02 22:37:49 +0100760 s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
ths663e8e52007-04-02 12:35:34 +0000761}
762
763static void dump_statistics(EEPRO100State * s)
764{
765 /* Dump statistical data. Most data is never changed by the emulation
766 * and always 0, so we first just copy the whole block and then those
767 * values which really matter.
768 * Number of data should check configuration!!!
769 */
Stefan Weilba42b642009-10-30 13:36:21 +0100770 cpu_physical_memory_write(s->statsaddr,
771 (uint8_t *) & s->statistics, s->stats_size);
772 stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
773 stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
774 stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
775 stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
Stefan Weile7493b22010-03-02 22:37:59 +0100776#if 0
777 stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
778 stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
779 missing("CU dump statistical counters");
780#endif
ths663e8e52007-04-02 12:35:34 +0000781}
782
Stefan Weil3d0f4b92010-03-02 22:37:57 +0100783static void read_cb(EEPRO100State *s)
784{
785 cpu_physical_memory_read(s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
786 s->tx.status = le16_to_cpu(s->tx.status);
787 s->tx.command = le16_to_cpu(s->tx.command);
788 s->tx.link = le32_to_cpu(s->tx.link);
789 s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
790 s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
791}
792
Stefan Weilf3a52e52009-12-20 16:52:22 +0100793static void tx_command(EEPRO100State *s)
794{
Stefan Weil7b8737d2009-12-20 16:52:24 +0100795 uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
Stefan Weilf3a52e52009-12-20 16:52:22 +0100796 uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
797 /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
798 uint8_t buf[2600];
799 uint16_t size = 0;
800 uint32_t tbd_address = s->cb_address + 0x10;
801 TRACE(RXTX, logout
802 ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
803 tbd_array, tcb_bytes, s->tx.tbd_count));
804
805 if (tcb_bytes > 2600) {
806 logout("TCB byte count too large, using 2600\n");
807 tcb_bytes = 2600;
808 }
809 if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
810 logout
811 ("illegal values of TBD array address and TCB byte count!\n");
812 }
813 assert(tcb_bytes <= sizeof(buf));
814 while (size < tcb_bytes) {
815 uint32_t tx_buffer_address = ldl_phys(tbd_address);
816 uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
Stefan Weile7493b22010-03-02 22:37:59 +0100817#if 0
818 uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
819#endif
Stefan Weilf3a52e52009-12-20 16:52:22 +0100820 tbd_address += 8;
821 TRACE(RXTX, logout
822 ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
823 tx_buffer_address, tx_buffer_size));
824 tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
825 cpu_physical_memory_read(tx_buffer_address, &buf[size],
826 tx_buffer_size);
827 size += tx_buffer_size;
828 }
829 if (tbd_array == 0xffffffff) {
830 /* Simplified mode. Was already handled by code above. */
831 } else {
832 /* Flexible mode. */
833 uint8_t tbd_count = 0;
834 if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
835 /* Extended Flexible TCB. */
836 for (; tbd_count < 2; tbd_count++) {
837 uint32_t tx_buffer_address = ldl_phys(tbd_address);
838 uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
839 uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
840 tbd_address += 8;
841 TRACE(RXTX, logout
842 ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
843 tx_buffer_address, tx_buffer_size));
844 tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
845 cpu_physical_memory_read(tx_buffer_address, &buf[size],
846 tx_buffer_size);
847 size += tx_buffer_size;
848 if (tx_buffer_el & 1) {
849 break;
850 }
851 }
852 }
853 tbd_address = tbd_array;
854 for (; tbd_count < s->tx.tbd_count; tbd_count++) {
855 uint32_t tx_buffer_address = ldl_phys(tbd_address);
856 uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
857 uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
858 tbd_address += 8;
859 TRACE(RXTX, logout
860 ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
861 tx_buffer_address, tx_buffer_size));
862 tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
863 cpu_physical_memory_read(tx_buffer_address, &buf[size],
864 tx_buffer_size);
865 size += tx_buffer_size;
866 if (tx_buffer_el & 1) {
867 break;
868 }
869 }
870 }
871 TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
872 qemu_send_packet(&s->nic->nc, buf, size);
873 s->statistics.tx_good_frames++;
874 /* Transmit with bad status would raise an CX/TNO interrupt.
875 * (82557 only). Emulation never has bad status. */
Stefan Weile7493b22010-03-02 22:37:59 +0100876#if 0
877 eepro100_cx_interrupt(s);
878#endif
Stefan Weilf3a52e52009-12-20 16:52:22 +0100879}
880
Stefan Weil7b8737d2009-12-20 16:52:24 +0100881static void set_multicast_list(EEPRO100State *s)
882{
883 uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
884 uint16_t i;
885 memset(&s->mult[0], 0, sizeof(s->mult));
886 TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
887 for (i = 0; i < multicast_count; i += 6) {
888 uint8_t multicast_addr[6];
889 cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6);
890 TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
891 unsigned mcast_idx = compute_mcast_idx(multicast_addr);
892 assert(mcast_idx < 64);
893 s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
894 }
895}
896
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200897static void action_command(EEPRO100State *s)
ths663e8e52007-04-02 12:35:34 +0000898{
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200899 for (;;) {
Stefan Weil3d0f4b92010-03-02 22:37:57 +0100900 bool bit_el;
901 bool bit_s;
902 bool bit_i;
903 bool bit_nc;
Kevin Wolf7f1e9d42009-09-23 17:42:42 +0200904 bool success = true;
Stefan Weil3d0f4b92010-03-02 22:37:57 +0100905 s->cb_address = s->cu_base + s->cu_offset;
906 read_cb(s);
907 bit_el = ((s->tx.command & COMMAND_EL) != 0);
908 bit_s = ((s->tx.command & COMMAND_S) != 0);
909 bit_i = ((s->tx.command & COMMAND_I) != 0);
910 bit_nc = ((s->tx.command & COMMAND_NC) != 0);
911#if 0
912 bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
913#endif
914 s->cu_offset = s->tx.link;
915 TRACE(OTHER,
916 logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
917 s->tx.status, s->tx.command, s->tx.link));
918 switch (s->tx.command & COMMAND_CMD) {
ths663e8e52007-04-02 12:35:34 +0000919 case CmdNOp:
920 /* Do nothing. */
921 break;
922 case CmdIASetup:
Stefan Weilf3a52e52009-12-20 16:52:22 +0100923 cpu_physical_memory_read(s->cb_address + 8, &s->conf.macaddr.a[0], 6);
Stefan Weilce0e58b2010-03-02 22:37:41 +0100924 TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
ths663e8e52007-04-02 12:35:34 +0000925 break;
926 case CmdConfigure:
Stefan Weilf3a52e52009-12-20 16:52:22 +0100927 cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
ths663e8e52007-04-02 12:35:34 +0000928 sizeof(s->configuration));
Stefan Weilaac443e2009-09-19 12:11:36 +0200929 TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
ths663e8e52007-04-02 12:35:34 +0000930 break;
931 case CmdMulticastList:
Stefan Weil7b8737d2009-12-20 16:52:24 +0100932 set_multicast_list(s);
ths663e8e52007-04-02 12:35:34 +0000933 break;
934 case CmdTx:
Kevin Wolf7f1e9d42009-09-23 17:42:42 +0200935 if (bit_nc) {
936 missing("CmdTx: NC = 0");
937 success = false;
938 break;
939 }
Stefan Weilf3a52e52009-12-20 16:52:22 +0100940 tx_command(s);
ths663e8e52007-04-02 12:35:34 +0000941 break;
942 case CmdTDR:
Stefan Weilaac443e2009-09-19 12:11:36 +0200943 TRACE(OTHER, logout("load microcode\n"));
ths663e8e52007-04-02 12:35:34 +0000944 /* Starting with offset 8, the command contains
945 * 64 dwords microcode which we just ignore here. */
946 break;
Stefan Weilf80a7fc2010-03-02 22:37:58 +0100947 case CmdDiagnose:
948 TRACE(OTHER, logout("diagnose\n"));
949 /* Make sure error flag is not set. */
950 s->tx.status = 0;
951 break;
ths663e8e52007-04-02 12:35:34 +0000952 default:
953 missing("undefined command");
Kevin Wolf7f1e9d42009-09-23 17:42:42 +0200954 success = false;
955 break;
ths663e8e52007-04-02 12:35:34 +0000956 }
Kevin Wolf7f1e9d42009-09-23 17:42:42 +0200957 /* Write new status. */
Stefan Weilec1d02d2010-03-02 22:37:56 +0100958 stw_phys(s->cb_address, s->tx.status | STATUS_C | (success ? STATUS_OK : 0));
ths663e8e52007-04-02 12:35:34 +0000959 if (bit_i) {
960 /* CU completed action. */
961 eepro100_cx_interrupt(s);
962 }
963 if (bit_el) {
Stefan Weilaac443e2009-09-19 12:11:36 +0200964 /* CU becomes idle. Terminate command loop. */
ths663e8e52007-04-02 12:35:34 +0000965 set_cu_state(s, cu_idle);
966 eepro100_cna_interrupt(s);
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200967 break;
ths663e8e52007-04-02 12:35:34 +0000968 } else if (bit_s) {
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200969 /* CU becomes suspended. Terminate command loop. */
ths663e8e52007-04-02 12:35:34 +0000970 set_cu_state(s, cu_suspended);
971 eepro100_cna_interrupt(s);
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200972 break;
ths663e8e52007-04-02 12:35:34 +0000973 } else {
974 /* More entries in list. */
Stefan Weilaac443e2009-09-19 12:11:36 +0200975 TRACE(OTHER, logout("CU list with at least one more entry\n"));
ths663e8e52007-04-02 12:35:34 +0000976 }
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200977 }
978 TRACE(OTHER, logout("CU list empty\n"));
979 /* List is empty. Now CU is idle or suspended. */
980}
981
982static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
983{
Stefan Weilcb25a3f2010-03-02 22:37:54 +0100984 cu_state_t cu_state;
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200985 switch (val) {
986 case CU_NOP:
987 /* No operation. */
988 break;
989 case CU_START:
Stefan Weilcb25a3f2010-03-02 22:37:54 +0100990 cu_state = get_cu_state(s);
991 if (cu_state != cu_idle && cu_state != cu_suspended) {
992 /* Intel documentation says that CU must be idle or suspended
993 * for the CU start command. */
994 logout("unexpected CU state is %u\n", cu_state);
Stefan Weil5fa9a0a2009-10-19 21:03:26 +0200995 }
996 set_cu_state(s, cu_active);
997 s->cu_offset = s->pointer;
998 action_command(s);
ths663e8e52007-04-02 12:35:34 +0000999 break;
1000 case CU_RESUME:
1001 if (get_cu_state(s) != cu_suspended) {
1002 logout("bad CU resume from CU state %u\n", get_cu_state(s));
1003 /* Workaround for bad Linux eepro100 driver which resumes
1004 * from idle state. */
Stefan Weile7493b22010-03-02 22:37:59 +01001005#if 0
1006 missing("cu resume");
1007#endif
ths663e8e52007-04-02 12:35:34 +00001008 set_cu_state(s, cu_suspended);
1009 }
1010 if (get_cu_state(s) == cu_suspended) {
Stefan Weilaac443e2009-09-19 12:11:36 +02001011 TRACE(OTHER, logout("CU resuming\n"));
ths663e8e52007-04-02 12:35:34 +00001012 set_cu_state(s, cu_active);
Stefan Weil5fa9a0a2009-10-19 21:03:26 +02001013 action_command(s);
ths663e8e52007-04-02 12:35:34 +00001014 }
1015 break;
1016 case CU_STATSADDR:
1017 /* Load dump counters address. */
1018 s->statsaddr = s->pointer;
Stefan Weilaac443e2009-09-19 12:11:36 +02001019 TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
ths663e8e52007-04-02 12:35:34 +00001020 break;
1021 case CU_SHOWSTATS:
1022 /* Dump statistical counters. */
Stefan Weilaac443e2009-09-19 12:11:36 +02001023 TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
ths663e8e52007-04-02 12:35:34 +00001024 dump_statistics(s);
Stefan Weilba42b642009-10-30 13:36:21 +01001025 stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
ths663e8e52007-04-02 12:35:34 +00001026 break;
1027 case CU_CMD_BASE:
1028 /* Load CU base. */
Stefan Weilaac443e2009-09-19 12:11:36 +02001029 TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
ths663e8e52007-04-02 12:35:34 +00001030 s->cu_base = s->pointer;
1031 break;
1032 case CU_DUMPSTATS:
1033 /* Dump and reset statistical counters. */
Stefan Weilaac443e2009-09-19 12:11:36 +02001034 TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
ths663e8e52007-04-02 12:35:34 +00001035 dump_statistics(s);
Stefan Weilba42b642009-10-30 13:36:21 +01001036 stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
ths663e8e52007-04-02 12:35:34 +00001037 memset(&s->statistics, 0, sizeof(s->statistics));
1038 break;
1039 case CU_SRESUME:
1040 /* CU static resume. */
1041 missing("CU static resume");
1042 break;
1043 default:
1044 missing("Undefined CU command");
1045 }
1046}
1047
1048static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
1049{
1050 switch (val) {
1051 case RU_NOP:
1052 /* No operation. */
1053 break;
1054 case RX_START:
1055 /* RU start. */
1056 if (get_ru_state(s) != ru_idle) {
1057 logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
Stefan Weile7493b22010-03-02 22:37:59 +01001058#if 0
1059 assert(!"wrong RU state");
1060#endif
ths663e8e52007-04-02 12:35:34 +00001061 }
1062 set_ru_state(s, ru_ready);
1063 s->ru_offset = s->pointer;
Stefan Weilaac443e2009-09-19 12:11:36 +02001064 TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
ths663e8e52007-04-02 12:35:34 +00001065 break;
1066 case RX_RESUME:
1067 /* Restart RU. */
1068 if (get_ru_state(s) != ru_suspended) {
1069 logout("RU state is %u, should be %u\n", get_ru_state(s),
1070 ru_suspended);
Stefan Weile7493b22010-03-02 22:37:59 +01001071#if 0
1072 assert(!"wrong RU state");
1073#endif
ths663e8e52007-04-02 12:35:34 +00001074 }
1075 set_ru_state(s, ru_ready);
1076 break;
Stefan Weile8240122010-03-02 22:37:53 +01001077 case RU_ABORT:
1078 /* RU abort. */
1079 if (get_ru_state(s) == ru_ready) {
1080 eepro100_rnr_interrupt(s);
1081 }
1082 set_ru_state(s, ru_idle);
1083 break;
ths663e8e52007-04-02 12:35:34 +00001084 case RX_ADDR_LOAD:
1085 /* Load RU base. */
Stefan Weilaac443e2009-09-19 12:11:36 +02001086 TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
ths663e8e52007-04-02 12:35:34 +00001087 s->ru_base = s->pointer;
1088 break;
1089 default:
1090 logout("val=0x%02x (undefined RU command)\n", val);
1091 missing("Undefined SU command");
1092 }
1093}
1094
1095static void eepro100_write_command(EEPRO100State * s, uint8_t val)
1096{
1097 eepro100_ru_command(s, val & 0x0f);
1098 eepro100_cu_command(s, val & 0xf0);
1099 if ((val) == 0) {
Stefan Weilaac443e2009-09-19 12:11:36 +02001100 TRACE(OTHER, logout("val=0x%02x\n", val));
ths663e8e52007-04-02 12:35:34 +00001101 }
1102 /* Clear command byte after command was accepted. */
1103 s->mem[SCBCmd] = 0;
1104}
1105
1106/*****************************************************************************
1107 *
1108 * EEPROM emulation.
1109 *
1110 ****************************************************************************/
1111
1112#define EEPROM_CS 0x02
1113#define EEPROM_SK 0x01
1114#define EEPROM_DI 0x04
1115#define EEPROM_DO 0x08
1116
1117static uint16_t eepro100_read_eeprom(EEPRO100State * s)
1118{
1119 uint16_t val;
1120 memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
1121 if (eeprom93xx_read(s->eeprom)) {
1122 val |= EEPROM_DO;
1123 } else {
1124 val &= ~EEPROM_DO;
1125 }
Stefan Weilaac443e2009-09-19 12:11:36 +02001126 TRACE(EEPROM, logout("val=0x%04x\n", val));
ths663e8e52007-04-02 12:35:34 +00001127 return val;
1128}
1129
Anthony Liguoric227f092009-10-01 16:12:16 -05001130static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
ths663e8e52007-04-02 12:35:34 +00001131{
Stefan Weilaac443e2009-09-19 12:11:36 +02001132 TRACE(EEPROM, logout("val=0x%02x\n", val));
ths663e8e52007-04-02 12:35:34 +00001133
1134 /* mask unwriteable bits */
Stefan Weile7493b22010-03-02 22:37:59 +01001135#if 0
1136 val = SET_MASKED(val, 0x31, eeprom->value);
1137#endif
ths663e8e52007-04-02 12:35:34 +00001138
1139 int eecs = ((val & EEPROM_CS) != 0);
1140 int eesk = ((val & EEPROM_SK) != 0);
1141 int eedi = ((val & EEPROM_DI) != 0);
1142 eeprom93xx_write(eeprom, eecs, eesk, eedi);
1143}
1144
1145static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
1146{
1147 s->pointer = le32_to_cpu(val);
Stefan Weilaac443e2009-09-19 12:11:36 +02001148 TRACE(OTHER, logout("val=0x%08x\n", val));
ths663e8e52007-04-02 12:35:34 +00001149}
1150
1151/*****************************************************************************
1152 *
1153 * MDI emulation.
1154 *
1155 ****************************************************************************/
1156
1157#if defined(DEBUG_EEPRO100)
Reimar Döffinger6a0b9cc2009-09-12 15:20:24 +00001158static const char * const mdi_op_name[] = {
ths663e8e52007-04-02 12:35:34 +00001159 "opcode 0",
1160 "write",
1161 "read",
1162 "opcode 3"
1163};
1164
Reimar Döffinger6a0b9cc2009-09-12 15:20:24 +00001165static const char * const mdi_reg_name[] = {
ths663e8e52007-04-02 12:35:34 +00001166 "Control",
1167 "Status",
1168 "PHY Identification (Word 1)",
1169 "PHY Identification (Word 2)",
1170 "Auto-Negotiation Advertisement",
1171 "Auto-Negotiation Link Partner Ability",
1172 "Auto-Negotiation Expansion"
1173};
Stefan Weilaac443e2009-09-19 12:11:36 +02001174
1175static const char *reg2name(uint8_t reg)
1176{
1177 static char buffer[10];
1178 const char *p = buffer;
1179 if (reg < ARRAY_SIZE(mdi_reg_name)) {
1180 p = mdi_reg_name[reg];
1181 } else {
1182 snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
1183 }
1184 return p;
1185}
ths663e8e52007-04-02 12:35:34 +00001186#endif /* DEBUG_EEPRO100 */
1187
1188static uint32_t eepro100_read_mdi(EEPRO100State * s)
1189{
1190 uint32_t val;
1191 memcpy(&val, &s->mem[0x10], sizeof(val));
1192
1193#ifdef DEBUG_EEPRO100
1194 uint8_t raiseint = (val & BIT(29)) >> 29;
1195 uint8_t opcode = (val & BITS(27, 26)) >> 26;
1196 uint8_t phy = (val & BITS(25, 21)) >> 21;
1197 uint8_t reg = (val & BITS(20, 16)) >> 16;
1198 uint16_t data = (val & BITS(15, 0));
1199#endif
1200 /* Emulation takes no time to finish MDI transaction. */
1201 val |= BIT(28);
1202 TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
1203 val, raiseint, mdi_op_name[opcode], phy,
Stefan Weilaac443e2009-09-19 12:11:36 +02001204 reg2name(reg), data));
ths663e8e52007-04-02 12:35:34 +00001205 return val;
1206}
1207
ths663e8e52007-04-02 12:35:34 +00001208static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
1209{
1210 uint8_t raiseint = (val & BIT(29)) >> 29;
1211 uint8_t opcode = (val & BITS(27, 26)) >> 26;
1212 uint8_t phy = (val & BITS(25, 21)) >> 21;
1213 uint8_t reg = (val & BITS(20, 16)) >> 16;
1214 uint16_t data = (val & BITS(15, 0));
Stefan Weilaac443e2009-09-19 12:11:36 +02001215 TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
1216 val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
ths663e8e52007-04-02 12:35:34 +00001217 if (phy != 1) {
1218 /* Unsupported PHY address. */
Stefan Weile7493b22010-03-02 22:37:59 +01001219#if 0
1220 logout("phy must be 1 but is %u\n", phy);
1221#endif
ths663e8e52007-04-02 12:35:34 +00001222 data = 0;
1223 } else if (opcode != 1 && opcode != 2) {
1224 /* Unsupported opcode. */
1225 logout("opcode must be 1 or 2 but is %u\n", opcode);
1226 data = 0;
1227 } else if (reg > 6) {
1228 /* Unsupported register. */
1229 logout("register must be 0...6 but is %u\n", reg);
1230 data = 0;
1231 } else {
1232 TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
1233 val, raiseint, mdi_op_name[opcode], phy,
Stefan Weilaac443e2009-09-19 12:11:36 +02001234 reg2name(reg), data));
ths663e8e52007-04-02 12:35:34 +00001235 if (opcode == 1) {
1236 /* MDI write */
1237 switch (reg) {
1238 case 0: /* Control Register */
1239 if (data & 0x8000) {
1240 /* Reset status and control registers to default. */
1241 s->mdimem[0] = eepro100_mdi_default[0];
1242 s->mdimem[1] = eepro100_mdi_default[1];
1243 data = s->mdimem[reg];
1244 } else {
1245 /* Restart Auto Configuration = Normal Operation */
1246 data &= ~0x0200;
1247 }
1248 break;
1249 case 1: /* Status Register */
1250 missing("not writable");
1251 data = s->mdimem[reg];
1252 break;
1253 case 2: /* PHY Identification Register (Word 1) */
1254 case 3: /* PHY Identification Register (Word 2) */
1255 missing("not implemented");
1256 break;
1257 case 4: /* Auto-Negotiation Advertisement Register */
1258 case 5: /* Auto-Negotiation Link Partner Ability Register */
1259 break;
1260 case 6: /* Auto-Negotiation Expansion Register */
1261 default:
1262 missing("not implemented");
1263 }
1264 s->mdimem[reg] = data;
1265 } else if (opcode == 2) {
1266 /* MDI read */
1267 switch (reg) {
1268 case 0: /* Control Register */
1269 if (data & 0x8000) {
1270 /* Reset status and control registers to default. */
1271 s->mdimem[0] = eepro100_mdi_default[0];
1272 s->mdimem[1] = eepro100_mdi_default[1];
1273 }
1274 break;
1275 case 1: /* Status Register */
1276 s->mdimem[reg] |= 0x0020;
1277 break;
1278 case 2: /* PHY Identification Register (Word 1) */
1279 case 3: /* PHY Identification Register (Word 2) */
1280 case 4: /* Auto-Negotiation Advertisement Register */
1281 break;
1282 case 5: /* Auto-Negotiation Link Partner Ability Register */
1283 s->mdimem[reg] = 0x41fe;
1284 break;
1285 case 6: /* Auto-Negotiation Expansion Register */
1286 s->mdimem[reg] = 0x0001;
1287 break;
1288 }
1289 data = s->mdimem[reg];
1290 }
1291 /* Emulation takes no time to finish MDI transaction.
1292 * Set MDI bit in SCB status register. */
1293 s->mem[SCBAck] |= 0x08;
1294 val |= BIT(28);
1295 if (raiseint) {
1296 eepro100_mdi_interrupt(s);
1297 }
1298 }
1299 val = (val & 0xffff0000) + data;
1300 memcpy(&s->mem[0x10], &val, sizeof(val));
1301}
1302
1303/*****************************************************************************
1304 *
1305 * Port emulation.
1306 *
1307 ****************************************************************************/
1308
1309#define PORT_SOFTWARE_RESET 0
1310#define PORT_SELFTEST 1
1311#define PORT_SELECTIVE_RESET 2
1312#define PORT_DUMP 3
1313#define PORT_SELECTION_MASK 3
1314
1315typedef struct {
1316 uint32_t st_sign; /* Self Test Signature */
1317 uint32_t st_result; /* Self Test Results */
Anthony Liguoric227f092009-10-01 16:12:16 -05001318} eepro100_selftest_t;
ths663e8e52007-04-02 12:35:34 +00001319
1320static uint32_t eepro100_read_port(EEPRO100State * s)
1321{
1322 return 0;
1323}
1324
1325static void eepro100_write_port(EEPRO100State * s, uint32_t val)
1326{
1327 val = le32_to_cpu(val);
1328 uint32_t address = (val & ~PORT_SELECTION_MASK);
1329 uint8_t selection = (val & PORT_SELECTION_MASK);
1330 switch (selection) {
1331 case PORT_SOFTWARE_RESET:
1332 nic_reset(s);
1333 break;
1334 case PORT_SELFTEST:
Stefan Weilaac443e2009-09-19 12:11:36 +02001335 TRACE(OTHER, logout("selftest address=0x%08x\n", address));
Anthony Liguoric227f092009-10-01 16:12:16 -05001336 eepro100_selftest_t data;
ths663e8e52007-04-02 12:35:34 +00001337 cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
1338 data.st_sign = 0xffffffff;
1339 data.st_result = 0;
1340 cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
1341 break;
1342 case PORT_SELECTIVE_RESET:
Stefan Weilaac443e2009-09-19 12:11:36 +02001343 TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
ths663e8e52007-04-02 12:35:34 +00001344 nic_selective_reset(s);
1345 break;
1346 default:
1347 logout("val=0x%08x\n", val);
1348 missing("unknown port selection");
1349 }
1350}
1351
1352/*****************************************************************************
1353 *
1354 * General hardware emulation.
1355 *
1356 ****************************************************************************/
1357
1358static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
1359{
1360 uint8_t val;
1361 if (addr <= sizeof(s->mem) - sizeof(val)) {
1362 memcpy(&val, &s->mem[addr], sizeof(val));
1363 }
1364
1365 switch (addr) {
1366 case SCBStatus:
Stefan Weile7493b22010-03-02 22:37:59 +01001367#if 0
1368 val = eepro100_read_status(s);
1369#endif
Stefan Weilaac443e2009-09-19 12:11:36 +02001370 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001371 break;
1372 case SCBAck:
Stefan Weile7493b22010-03-02 22:37:59 +01001373#if 0
1374 val = eepro100_read_status(s);
1375#endif
Stefan Weilaac443e2009-09-19 12:11:36 +02001376 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001377 break;
1378 case SCBCmd:
Stefan Weilaac443e2009-09-19 12:11:36 +02001379 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
Stefan Weile7493b22010-03-02 22:37:59 +01001380#if 0
1381 val = eepro100_read_command(s);
1382#endif
ths663e8e52007-04-02 12:35:34 +00001383 break;
1384 case SCBIntmask:
Stefan Weilaac443e2009-09-19 12:11:36 +02001385 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001386 break;
1387 case SCBPort + 3:
Stefan Weilaac443e2009-09-19 12:11:36 +02001388 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001389 break;
1390 case SCBeeprom:
1391 val = eepro100_read_eeprom(s);
1392 break;
Stefan Weil0908bba2010-03-02 22:37:42 +01001393 case SCBpmdr: /* Power Management Driver Register */
ths663e8e52007-04-02 12:35:34 +00001394 val = 0;
Stefan Weilaac443e2009-09-19 12:11:36 +02001395 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001396 break;
Stefan Weil0908bba2010-03-02 22:37:42 +01001397 case SCBgstat: /* General Status Register */
ths663e8e52007-04-02 12:35:34 +00001398 /* 100 Mbps full duplex, valid link */
1399 val = 0x07;
Stefan Weilaac443e2009-09-19 12:11:36 +02001400 TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
ths663e8e52007-04-02 12:35:34 +00001401 break;
1402 default:
1403 logout("addr=%s val=0x%02x\n", regname(addr), val);
1404 missing("unknown byte read");
1405 }
1406 return val;
1407}
1408
1409static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
1410{
1411 uint16_t val;
1412 if (addr <= sizeof(s->mem) - sizeof(val)) {
1413 memcpy(&val, &s->mem[addr], sizeof(val));
1414 }
1415
ths663e8e52007-04-02 12:35:34 +00001416 switch (addr) {
1417 case SCBStatus:
Stefan Weile7493b22010-03-02 22:37:59 +01001418#if 0
1419 val = eepro100_read_status(s);
1420#endif
=?UTF-8?q?Reimar=20D=C3=B6ffinger?=dbbaaff2009-10-02 18:39:41 +02001421 case SCBCmd:
Stefan Weilaac443e2009-09-19 12:11:36 +02001422 TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001423 break;
1424 case SCBeeprom:
1425 val = eepro100_read_eeprom(s);
Stefan Weilaac443e2009-09-19 12:11:36 +02001426 TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001427 break;
1428 default:
1429 logout("addr=%s val=0x%04x\n", regname(addr), val);
1430 missing("unknown word read");
1431 }
1432 return val;
1433}
1434
1435static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
1436{
1437 uint32_t val;
1438 if (addr <= sizeof(s->mem) - sizeof(val)) {
1439 memcpy(&val, &s->mem[addr], sizeof(val));
1440 }
1441
1442 switch (addr) {
1443 case SCBStatus:
Stefan Weile7493b22010-03-02 22:37:59 +01001444#if 0
1445 val = eepro100_read_status(s);
1446#endif
Stefan Weilaac443e2009-09-19 12:11:36 +02001447 TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001448 break;
1449 case SCBPointer:
Stefan Weile7493b22010-03-02 22:37:59 +01001450#if 0
1451 val = eepro100_read_pointer(s);
1452#endif
Stefan Weilaac443e2009-09-19 12:11:36 +02001453 TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001454 break;
1455 case SCBPort:
1456 val = eepro100_read_port(s);
Stefan Weilaac443e2009-09-19 12:11:36 +02001457 TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001458 break;
1459 case SCBCtrlMDI:
1460 val = eepro100_read_mdi(s);
1461 break;
1462 default:
1463 logout("addr=%s val=0x%08x\n", regname(addr), val);
1464 missing("unknown longword read");
1465 }
1466 return val;
1467}
1468
1469static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
1470{
1471 if (addr <= sizeof(s->mem) - sizeof(val)) {
1472 memcpy(&s->mem[addr], &val, sizeof(val));
1473 }
1474
Stefan Weilaac443e2009-09-19 12:11:36 +02001475 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001476
1477 switch (addr) {
1478 case SCBStatus:
Stefan Weile7493b22010-03-02 22:37:59 +01001479#if 0
1480 eepro100_write_status(s, val);
1481#endif
ths663e8e52007-04-02 12:35:34 +00001482 break;
1483 case SCBAck:
1484 eepro100_acknowledge(s);
1485 break;
1486 case SCBCmd:
1487 eepro100_write_command(s, val);
1488 break;
1489 case SCBIntmask:
1490 if (val & BIT(1)) {
1491 eepro100_swi_interrupt(s);
1492 }
1493 eepro100_interrupt(s, 0);
1494 break;
1495 case SCBPort + 3:
Stefan Weilaac443e2009-09-19 12:11:36 +02001496 case SCBFlow: /* does not exist on 82557 */
ths3257d2b2007-09-14 22:22:13 +00001497 case SCBFlow + 1:
1498 case SCBFlow + 2:
Stefan Weil0908bba2010-03-02 22:37:42 +01001499 case SCBpmdr: /* does not exist on 82557 */
Stefan Weilaac443e2009-09-19 12:11:36 +02001500 TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001501 break;
1502 case SCBeeprom:
1503 eepro100_write_eeprom(s->eeprom, val);
1504 break;
1505 default:
1506 logout("addr=%s val=0x%02x\n", regname(addr), val);
1507 missing("unknown byte write");
1508 }
1509}
1510
1511static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
1512{
1513 if (addr <= sizeof(s->mem) - sizeof(val)) {
1514 memcpy(&s->mem[addr], &val, sizeof(val));
1515 }
1516
Stefan Weilaac443e2009-09-19 12:11:36 +02001517 TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001518
1519 switch (addr) {
1520 case SCBStatus:
Stefan Weile7493b22010-03-02 22:37:59 +01001521#if 0
1522 eepro100_write_status(s, val);
1523#endif
ths663e8e52007-04-02 12:35:34 +00001524 eepro100_acknowledge(s);
1525 break;
1526 case SCBCmd:
1527 eepro100_write_command(s, val);
1528 eepro100_write1(s, SCBIntmask, val >> 8);
1529 break;
1530 case SCBeeprom:
1531 eepro100_write_eeprom(s->eeprom, val);
1532 break;
1533 default:
1534 logout("addr=%s val=0x%04x\n", regname(addr), val);
1535 missing("unknown word write");
1536 }
1537}
1538
1539static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
1540{
1541 if (addr <= sizeof(s->mem) - sizeof(val)) {
1542 memcpy(&s->mem[addr], &val, sizeof(val));
1543 }
1544
1545 switch (addr) {
1546 case SCBPointer:
1547 eepro100_write_pointer(s, val);
1548 break;
1549 case SCBPort:
Stefan Weilaac443e2009-09-19 12:11:36 +02001550 TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
ths663e8e52007-04-02 12:35:34 +00001551 eepro100_write_port(s, val);
1552 break;
1553 case SCBCtrlMDI:
1554 eepro100_write_mdi(s, val);
1555 break;
1556 default:
1557 logout("addr=%s val=0x%08x\n", regname(addr), val);
1558 missing("unknown longword write");
1559 }
1560}
1561
Stefan Weilaac443e2009-09-19 12:11:36 +02001562/*****************************************************************************
1563 *
1564 * Port mapped I/O.
1565 *
1566 ****************************************************************************/
1567
ths663e8e52007-04-02 12:35:34 +00001568static uint32_t ioport_read1(void *opaque, uint32_t addr)
1569{
1570 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001571#if 0
1572 logout("addr=%s\n", regname(addr));
1573#endif
ths663e8e52007-04-02 12:35:34 +00001574 return eepro100_read1(s, addr - s->region[1]);
1575}
1576
1577static uint32_t ioport_read2(void *opaque, uint32_t addr)
1578{
1579 EEPRO100State *s = opaque;
1580 return eepro100_read2(s, addr - s->region[1]);
1581}
1582
1583static uint32_t ioport_read4(void *opaque, uint32_t addr)
1584{
1585 EEPRO100State *s = opaque;
1586 return eepro100_read4(s, addr - s->region[1]);
1587}
1588
1589static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
1590{
1591 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001592#if 0
1593 logout("addr=%s val=0x%02x\n", regname(addr), val);
1594#endif
ths663e8e52007-04-02 12:35:34 +00001595 eepro100_write1(s, addr - s->region[1], val);
1596}
1597
1598static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
1599{
1600 EEPRO100State *s = opaque;
1601 eepro100_write2(s, addr - s->region[1], val);
1602}
1603
1604static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
1605{
1606 EEPRO100State *s = opaque;
1607 eepro100_write4(s, addr - s->region[1], val);
1608}
1609
1610/***********************************************************/
1611/* PCI EEPRO100 definitions */
1612
ths663e8e52007-04-02 12:35:34 +00001613static void pci_map(PCIDevice * pci_dev, int region_num,
Isaku Yamahata6e355d92009-10-30 21:21:08 +09001614 pcibus_t addr, pcibus_t size, int type)
ths663e8e52007-04-02 12:35:34 +00001615{
Juan Quintela273a2142009-08-24 18:42:37 +02001616 EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
ths663e8e52007-04-02 12:35:34 +00001617
Isaku Yamahata89e8b132009-10-30 21:21:09 +09001618 TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
1619 "size=0x%08"FMT_PCIBUS", type=%d\n",
Stefan Weilaac443e2009-09-19 12:11:36 +02001620 region_num, addr, size, type));
ths663e8e52007-04-02 12:35:34 +00001621
1622 assert(region_num == 1);
1623 register_ioport_write(addr, size, 1, ioport_write1, s);
1624 register_ioport_read(addr, size, 1, ioport_read1, s);
1625 register_ioport_write(addr, size, 2, ioport_write2, s);
1626 register_ioport_read(addr, size, 2, ioport_read2, s);
1627 register_ioport_write(addr, size, 4, ioport_write4, s);
1628 register_ioport_read(addr, size, 4, ioport_read4, s);
1629
1630 s->region[region_num] = addr;
1631}
1632
Stefan Weilaac443e2009-09-19 12:11:36 +02001633/*****************************************************************************
1634 *
1635 * Memory mapped I/O.
1636 *
1637 ****************************************************************************/
1638
Anthony Liguoric227f092009-10-01 16:12:16 -05001639static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
ths663e8e52007-04-02 12:35:34 +00001640{
1641 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001642#if 0
1643 logout("addr=%s val=0x%02x\n", regname(addr), val);
1644#endif
ths663e8e52007-04-02 12:35:34 +00001645 eepro100_write1(s, addr, val);
1646}
1647
Anthony Liguoric227f092009-10-01 16:12:16 -05001648static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
ths663e8e52007-04-02 12:35:34 +00001649{
1650 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001651#if 0
1652 logout("addr=%s val=0x%02x\n", regname(addr), val);
1653#endif
ths663e8e52007-04-02 12:35:34 +00001654 eepro100_write2(s, addr, val);
1655}
1656
Anthony Liguoric227f092009-10-01 16:12:16 -05001657static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
ths663e8e52007-04-02 12:35:34 +00001658{
1659 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001660#if 0
1661 logout("addr=%s val=0x%02x\n", regname(addr), val);
1662#endif
ths663e8e52007-04-02 12:35:34 +00001663 eepro100_write4(s, addr, val);
1664}
1665
Anthony Liguoric227f092009-10-01 16:12:16 -05001666static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
ths663e8e52007-04-02 12:35:34 +00001667{
1668 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001669#if 0
1670 logout("addr=%s\n", regname(addr));
1671#endif
ths663e8e52007-04-02 12:35:34 +00001672 return eepro100_read1(s, addr);
1673}
1674
Anthony Liguoric227f092009-10-01 16:12:16 -05001675static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
ths663e8e52007-04-02 12:35:34 +00001676{
1677 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001678#if 0
1679 logout("addr=%s\n", regname(addr));
1680#endif
ths663e8e52007-04-02 12:35:34 +00001681 return eepro100_read2(s, addr);
1682}
1683
Anthony Liguoric227f092009-10-01 16:12:16 -05001684static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
ths663e8e52007-04-02 12:35:34 +00001685{
1686 EEPRO100State *s = opaque;
Stefan Weile7493b22010-03-02 22:37:59 +01001687#if 0
1688 logout("addr=%s\n", regname(addr));
1689#endif
ths663e8e52007-04-02 12:35:34 +00001690 return eepro100_read4(s, addr);
1691}
1692
Blue Swirld60efc62009-08-25 18:29:31 +00001693static CPUWriteMemoryFunc * const pci_mmio_write[] = {
ths663e8e52007-04-02 12:35:34 +00001694 pci_mmio_writeb,
1695 pci_mmio_writew,
1696 pci_mmio_writel
1697};
1698
Blue Swirld60efc62009-08-25 18:29:31 +00001699static CPUReadMemoryFunc * const pci_mmio_read[] = {
ths663e8e52007-04-02 12:35:34 +00001700 pci_mmio_readb,
1701 pci_mmio_readw,
1702 pci_mmio_readl
1703};
1704
1705static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
Isaku Yamahata6e355d92009-10-30 21:21:08 +09001706 pcibus_t addr, pcibus_t size, int type)
ths663e8e52007-04-02 12:35:34 +00001707{
Juan Quintela273a2142009-08-24 18:42:37 +02001708 EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
ths663e8e52007-04-02 12:35:34 +00001709
Isaku Yamahata89e8b132009-10-30 21:21:09 +09001710 TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
1711 "size=0x%08"FMT_PCIBUS", type=%d\n",
Stefan Weilaac443e2009-09-19 12:11:36 +02001712 region_num, addr, size, type));
ths663e8e52007-04-02 12:35:34 +00001713
1714 if (region_num == 0) {
1715 /* Map control / status registers. */
Juan Quintela273a2142009-08-24 18:42:37 +02001716 cpu_register_physical_memory(addr, size, s->mmio_index);
1717 s->region[region_num] = addr;
ths663e8e52007-04-02 12:35:34 +00001718 }
1719}
1720
Mark McLoughline00e3652009-11-25 18:49:16 +00001721static int nic_can_receive(VLANClientState *nc)
ths663e8e52007-04-02 12:35:34 +00001722{
Mark McLoughline00e3652009-11-25 18:49:16 +00001723 EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
Stefan Weilaac443e2009-09-19 12:11:36 +02001724 TRACE(RXTX, logout("%p\n", s));
ths663e8e52007-04-02 12:35:34 +00001725 return get_ru_state(s) == ru_ready;
Stefan Weile7493b22010-03-02 22:37:59 +01001726#if 0
1727 return !eepro100_buffer_full(s);
1728#endif
ths663e8e52007-04-02 12:35:34 +00001729}
1730
Mark McLoughline00e3652009-11-25 18:49:16 +00001731static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
ths663e8e52007-04-02 12:35:34 +00001732{
1733 /* TODO:
1734 * - Magic packets should set bit 30 in power management driver register.
1735 * - Interesting packets should set bit 29 in power management driver register.
1736 */
Mark McLoughline00e3652009-11-25 18:49:16 +00001737 EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
ths663e8e52007-04-02 12:35:34 +00001738 uint16_t rfd_status = 0xa000;
1739 static const uint8_t broadcast_macaddr[6] =
1740 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1741
1742 /* TODO: check multiple IA bit. */
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001743 if (s->configuration[20] & BIT(6)) {
1744 missing("Multiple IA bit");
1745 return -1;
1746 }
ths663e8e52007-04-02 12:35:34 +00001747
1748 if (s->configuration[8] & 0x80) {
1749 /* CSMA is disabled. */
1750 logout("%p received while CSMA is disabled\n", s);
Mark McLoughlin4f1c9422009-05-18 13:40:55 +01001751 return -1;
Stefan Weilced52962010-03-02 22:37:49 +01001752 } else if (size < 64 && (s->configuration[7] & BIT(0))) {
ths663e8e52007-04-02 12:35:34 +00001753 /* Short frame and configuration byte 7/0 (discard short receive) set:
1754 * Short frame is discarded */
Stefan Weil067d01d2009-09-19 12:37:51 +02001755 logout("%p received short frame (%zu byte)\n", s, size);
ths663e8e52007-04-02 12:35:34 +00001756 s->statistics.rx_short_frame_errors++;
Stefan Weile7493b22010-03-02 22:37:59 +01001757#if 0
1758 return -1;
1759#endif
Stefan Weilced52962010-03-02 22:37:49 +01001760 } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
ths663e8e52007-04-02 12:35:34 +00001761 /* Long frame and configuration byte 18/3 (long receive ok) not set:
1762 * Long frames are discarded. */
Stefan Weil067d01d2009-09-19 12:37:51 +02001763 logout("%p received long frame (%zu byte), ignored\n", s, size);
Mark McLoughlin4f1c9422009-05-18 13:40:55 +01001764 return -1;
Stefan Weile7493b22010-03-02 22:37:59 +01001765 } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) { /* !!! */
ths663e8e52007-04-02 12:35:34 +00001766 /* Frame matches individual address. */
1767 /* TODO: check configuration byte 15/4 (ignore U/L). */
Stefan Weil067d01d2009-09-19 12:37:51 +02001768 TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
ths663e8e52007-04-02 12:35:34 +00001769 } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
1770 /* Broadcast frame. */
Stefan Weil067d01d2009-09-19 12:37:51 +02001771 TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
ths663e8e52007-04-02 12:35:34 +00001772 rfd_status |= 0x0002;
Stefan Weil7b8737d2009-12-20 16:52:24 +01001773 } else if (buf[0] & 0x01) {
ths663e8e52007-04-02 12:35:34 +00001774 /* Multicast frame. */
Stefan Weil7b8737d2009-12-20 16:52:24 +01001775 TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001776 if (s->configuration[21] & BIT(3)) {
Stefan Weil7b8737d2009-12-20 16:52:24 +01001777 /* Multicast all bit is set, receive all multicast frames. */
1778 } else {
1779 unsigned mcast_idx = compute_mcast_idx(buf);
1780 assert(mcast_idx < 64);
1781 if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
1782 /* Multicast frame is allowed in hash table. */
Stefan Weilced52962010-03-02 22:37:49 +01001783 } else if (s->configuration[15] & BIT(0)) {
Stefan Weil7b8737d2009-12-20 16:52:24 +01001784 /* Promiscuous: receive all. */
1785 rfd_status |= 0x0004;
1786 } else {
1787 TRACE(RXTX, logout("%p multicast ignored\n", s));
1788 return -1;
1789 }
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001790 }
Stefan Weil7b8737d2009-12-20 16:52:24 +01001791 /* TODO: Next not for promiscuous mode? */
ths663e8e52007-04-02 12:35:34 +00001792 rfd_status |= 0x0002;
Stefan Weilced52962010-03-02 22:37:49 +01001793 } else if (s->configuration[15] & BIT(0)) {
ths663e8e52007-04-02 12:35:34 +00001794 /* Promiscuous: receive all. */
Stefan Weil067d01d2009-09-19 12:37:51 +02001795 TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
ths663e8e52007-04-02 12:35:34 +00001796 rfd_status |= 0x0004;
1797 } else {
Stefan Weil067d01d2009-09-19 12:37:51 +02001798 TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
Stefan Weilaac443e2009-09-19 12:11:36 +02001799 nic_dump(buf, size)));
Mark McLoughlin4f1c9422009-05-18 13:40:55 +01001800 return size;
ths663e8e52007-04-02 12:35:34 +00001801 }
1802
1803 if (get_ru_state(s) != ru_ready) {
Stefan Weilaac443e2009-09-19 12:11:36 +02001804 /* No resources available. */
1805 logout("no resources, state=%u\n", get_ru_state(s));
Stefan Weile8240122010-03-02 22:37:53 +01001806 /* TODO: RNR interrupt only at first failed frame? */
1807 eepro100_rnr_interrupt(s);
ths663e8e52007-04-02 12:35:34 +00001808 s->statistics.rx_resource_errors++;
Stefan Weile7493b22010-03-02 22:37:59 +01001809#if 0
1810 assert(!"no resources");
1811#endif
Mark McLoughlin4f1c9422009-05-18 13:40:55 +01001812 return -1;
ths663e8e52007-04-02 12:35:34 +00001813 }
Stefan Weile7493b22010-03-02 22:37:59 +01001814 /* !!! */
Anthony Liguoric227f092009-10-01 16:12:16 -05001815 eepro100_rx_t rx;
ths663e8e52007-04-02 12:35:34 +00001816 cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
Anthony Liguoric227f092009-10-01 16:12:16 -05001817 offsetof(eepro100_rx_t, packet));
ths663e8e52007-04-02 12:35:34 +00001818 uint16_t rfd_command = le16_to_cpu(rx.command);
1819 uint16_t rfd_size = le16_to_cpu(rx.size);
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001820
1821 if (size > rfd_size) {
1822 logout("Receive buffer (%" PRId16 " bytes) too small for data "
1823 "(%zu bytes); data truncated\n", rfd_size, size);
1824 size = rfd_size;
1825 }
ths663e8e52007-04-02 12:35:34 +00001826 if (size < 64) {
1827 rfd_status |= 0x0080;
1828 }
Stefan Weilaac443e2009-09-19 12:11:36 +02001829 TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
1830 rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
Anthony Liguoric227f092009-10-01 16:12:16 -05001831 stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
ths663e8e52007-04-02 12:35:34 +00001832 rfd_status);
Anthony Liguoric227f092009-10-01 16:12:16 -05001833 stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
ths663e8e52007-04-02 12:35:34 +00001834 /* Early receive interrupt not supported. */
Stefan Weile7493b22010-03-02 22:37:59 +01001835#if 0
1836 eepro100_er_interrupt(s);
1837#endif
ths663e8e52007-04-02 12:35:34 +00001838 /* Receive CRC Transfer not supported. */
Stefan Weilced52962010-03-02 22:37:49 +01001839 if (s->configuration[18] & BIT(2)) {
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001840 missing("Receive CRC Transfer");
1841 return -1;
1842 }
ths663e8e52007-04-02 12:35:34 +00001843 /* TODO: check stripping enable bit. */
Stefan Weile7493b22010-03-02 22:37:59 +01001844#if 0
1845 assert(!(s->configuration[17] & BIT(0)));
1846#endif
ths663e8e52007-04-02 12:35:34 +00001847 cpu_physical_memory_write(s->ru_base + s->ru_offset +
Anthony Liguoric227f092009-10-01 16:12:16 -05001848 offsetof(eepro100_rx_t, packet), buf, size);
ths663e8e52007-04-02 12:35:34 +00001849 s->statistics.rx_good_frames++;
1850 eepro100_fr_interrupt(s);
1851 s->ru_offset = le32_to_cpu(rx.link);
Stefan Weilced52962010-03-02 22:37:49 +01001852 if (rfd_command & COMMAND_EL) {
ths663e8e52007-04-02 12:35:34 +00001853 /* EL bit is set, so this was the last frame. */
Kevin Wolf7f1e9d42009-09-23 17:42:42 +02001854 logout("receive: Running out of frames\n");
1855 set_ru_state(s, ru_suspended);
ths663e8e52007-04-02 12:35:34 +00001856 }
Stefan Weilced52962010-03-02 22:37:49 +01001857 if (rfd_command & COMMAND_S) {
ths663e8e52007-04-02 12:35:34 +00001858 /* S bit is set. */
1859 set_ru_state(s, ru_suspended);
1860 }
Mark McLoughlin4f1c9422009-05-18 13:40:55 +01001861 return size;
ths663e8e52007-04-02 12:35:34 +00001862}
1863
Juan Quintela151b2982009-10-19 15:37:57 +02001864static const VMStateDescription vmstate_eepro100 = {
1865 .version_id = 3,
1866 .minimum_version_id = 2,
1867 .minimum_version_id_old = 2,
1868 .fields = (VMStateField []) {
1869 VMSTATE_PCI_DEVICE(dev, EEPRO100State),
1870 VMSTATE_UNUSED(32),
1871 VMSTATE_BUFFER(mult, EEPRO100State),
1872 VMSTATE_BUFFER(mem, EEPRO100State),
1873 /* Save all members of struct between scb_stat and mem. */
1874 VMSTATE_UINT8(scb_stat, EEPRO100State),
1875 VMSTATE_UINT8(int_stat, EEPRO100State),
1876 VMSTATE_UNUSED(3*4),
1877 VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
1878 VMSTATE_UNUSED(19*4),
1879 VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
1880 /* The eeprom should be saved and restored by its own routines. */
1881 VMSTATE_UINT32(device, EEPRO100State),
1882 /* TODO check device. */
1883 VMSTATE_UINT32(pointer, EEPRO100State),
1884 VMSTATE_UINT32(cu_base, EEPRO100State),
1885 VMSTATE_UINT32(cu_offset, EEPRO100State),
1886 VMSTATE_UINT32(ru_base, EEPRO100State),
1887 VMSTATE_UINT32(ru_offset, EEPRO100State),
1888 VMSTATE_UINT32(statsaddr, EEPRO100State),
Stefan Weilba42b642009-10-30 13:36:21 +01001889 /* Save eepro100_stats_t statistics. */
Juan Quintela151b2982009-10-19 15:37:57 +02001890 VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
1891 VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
1892 VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
1893 VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
1894 VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
1895 VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
1896 VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
1897 VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
1898 VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
1899 VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
1900 VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
1901 VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
1902 VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
1903 VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
1904 VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
1905 VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
1906 VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
1907 VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
1908 VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
1909 VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
1910 VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
balrog2657c662007-07-02 13:38:46 +00001911#if 0
Juan Quintela151b2982009-10-19 15:37:57 +02001912 VMSTATE_UINT16(status, EEPRO100State),
balrog2657c662007-07-02 13:38:46 +00001913#endif
Juan Quintela151b2982009-10-19 15:37:57 +02001914 /* Configuration bytes. */
1915 VMSTATE_BUFFER(configuration, EEPRO100State),
1916 VMSTATE_END_OF_LIST()
Stefan Weilaac443e2009-09-19 12:11:36 +02001917 }
Juan Quintela151b2982009-10-19 15:37:57 +02001918};
ths663e8e52007-04-02 12:35:34 +00001919
Mark McLoughline00e3652009-11-25 18:49:16 +00001920static void nic_cleanup(VLANClientState *nc)
aliguorib946a152009-04-17 17:11:08 +00001921{
Mark McLoughline00e3652009-11-25 18:49:16 +00001922 EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
aliguorib946a152009-04-17 17:11:08 +00001923
Mark McLoughline00e3652009-11-25 18:49:16 +00001924 s->nic = NULL;
aliguorib946a152009-04-17 17:11:08 +00001925}
1926
Stefan Weilc4c270e2009-09-19 13:02:09 +02001927static int pci_nic_uninit(PCIDevice *pci_dev)
aliguorib946a152009-04-17 17:11:08 +00001928{
Stefan Weilc4c270e2009-09-19 13:02:09 +02001929 EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
aliguorib946a152009-04-17 17:11:08 +00001930
1931 cpu_unregister_io_memory(s->mmio_index);
Juan Quintela151b2982009-10-19 15:37:57 +02001932 vmstate_unregister(s->vmstate, s);
Gerd Hoffmann508ef932009-10-21 15:25:36 +02001933 eeprom93xx_free(s->eeprom);
Mark McLoughline00e3652009-11-25 18:49:16 +00001934 qemu_del_vlan_client(&s->nic->nc);
aliguorib946a152009-04-17 17:11:08 +00001935 return 0;
1936}
1937
Mark McLoughline00e3652009-11-25 18:49:16 +00001938static NetClientInfo net_eepro100_info = {
1939 .type = NET_CLIENT_TYPE_NIC,
1940 .size = sizeof(NICState),
1941 .can_receive = nic_can_receive,
1942 .receive = nic_receive,
1943 .cleanup = nic_cleanup,
1944};
1945
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001946static int nic_init(PCIDevice *pci_dev, uint32_t device)
ths663e8e52007-04-02 12:35:34 +00001947{
Juan Quintela273a2142009-08-24 18:42:37 +02001948 EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
ths663e8e52007-04-02 12:35:34 +00001949
Stefan Weilaac443e2009-09-19 12:11:36 +02001950 TRACE(OTHER, logout("\n"));
ths663e8e52007-04-02 12:35:34 +00001951
ths663e8e52007-04-02 12:35:34 +00001952 s->device = device;
ths663e8e52007-04-02 12:35:34 +00001953
1954 pci_reset(s);
1955
1956 /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
1957 * i82559 and later support 64 or 256 word EEPROM. */
1958 s->eeprom = eeprom93xx_new(EEPROM_SIZE);
1959
1960 /* Handler for memory-mapped I/O */
Juan Quintela273a2142009-08-24 18:42:37 +02001961 s->mmio_index =
Avi Kivity1eed09c2009-06-14 11:38:51 +03001962 cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s);
ths663e8e52007-04-02 12:35:34 +00001963
Juan Quintela273a2142009-08-24 18:42:37 +02001964 pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
Isaku Yamahata0392a012009-10-30 21:21:03 +09001965 PCI_BASE_ADDRESS_SPACE_MEMORY |
1966 PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
1967 pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
ths663e8e52007-04-02 12:35:34 +00001968 pci_map);
Isaku Yamahata0392a012009-10-30 21:21:03 +09001969 pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
ths663e8e52007-04-02 12:35:34 +00001970 pci_mmio_map);
1971
Gerd Hoffmann508ef932009-10-21 15:25:36 +02001972 qemu_macaddr_default_if_unset(&s->conf.macaddr);
Stefan Weilce0e58b2010-03-02 22:37:41 +01001973 logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
ths663e8e52007-04-02 12:35:34 +00001974 assert(s->region[1] == 0);
1975
1976 nic_reset(s);
1977
Mark McLoughline00e3652009-11-25 18:49:16 +00001978 s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
1979 pci_dev->qdev.info->name, pci_dev->qdev.id, s);
ths663e8e52007-04-02 12:35:34 +00001980
Mark McLoughline00e3652009-11-25 18:49:16 +00001981 qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
1982 TRACE(OTHER, logout("%s\n", s->nic->nc.info_str));
ths663e8e52007-04-02 12:35:34 +00001983
Jan Kiszkaa08d4362009-06-27 09:25:07 +02001984 qemu_register_reset(nic_reset, s);
ths663e8e52007-04-02 12:35:34 +00001985
Juan Quintela151b2982009-10-19 15:37:57 +02001986 s->vmstate = qemu_malloc(sizeof(vmstate_eepro100));
1987 memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
Mark McLoughline00e3652009-11-25 18:49:16 +00001988 s->vmstate->name = s->nic->nc.model;
Juan Quintela151b2982009-10-19 15:37:57 +02001989 vmstate_register(-1, s->vmstate, s);
Stefan Weil4e9df062009-10-31 13:38:33 +01001990
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001991 return 0;
ths663e8e52007-04-02 12:35:34 +00001992}
1993
Stefan Weilc4c270e2009-09-19 13:02:09 +02001994static int pci_i82550_init(PCIDevice *pci_dev)
ths663e8e52007-04-02 12:35:34 +00001995{
Stefan Weilc4c270e2009-09-19 13:02:09 +02001996 return nic_init(pci_dev, i82550);
ths663e8e52007-04-02 12:35:34 +00001997}
1998
Stefan Weilc4c270e2009-09-19 13:02:09 +02001999static int pci_i82551_init(PCIDevice *pci_dev)
ths663e8e52007-04-02 12:35:34 +00002000{
Stefan Weilc4c270e2009-09-19 13:02:09 +02002001 return nic_init(pci_dev, i82551);
ths663e8e52007-04-02 12:35:34 +00002002}
2003
Stefan Weilc4c270e2009-09-19 13:02:09 +02002004static int pci_i82557a_init(PCIDevice *pci_dev)
ths663e8e52007-04-02 12:35:34 +00002005{
Stefan Weilc4c270e2009-09-19 13:02:09 +02002006 return nic_init(pci_dev, i82557A);
2007}
2008
2009static int pci_i82557b_init(PCIDevice *pci_dev)
2010{
2011 return nic_init(pci_dev, i82557B);
2012}
2013
2014static int pci_i82557c_init(PCIDevice *pci_dev)
2015{
2016 return nic_init(pci_dev, i82557C);
2017}
2018
2019static int pci_i82558a_init(PCIDevice *pci_dev)
2020{
2021 return nic_init(pci_dev, i82558A);
2022}
2023
2024static int pci_i82558b_init(PCIDevice *pci_dev)
2025{
2026 return nic_init(pci_dev, i82558B);
2027}
2028
2029static int pci_i82559a_init(PCIDevice *pci_dev)
2030{
2031 return nic_init(pci_dev, i82559A);
2032}
2033
2034static int pci_i82559b_init(PCIDevice *pci_dev)
2035{
2036 return nic_init(pci_dev, i82559B);
2037}
2038
2039static int pci_i82559c_init(PCIDevice *pci_dev)
2040{
2041 return nic_init(pci_dev, i82559C);
2042}
2043
2044static int pci_i82559er_init(PCIDevice *pci_dev)
2045{
2046 return nic_init(pci_dev, i82559ER);
2047}
2048
2049static int pci_i82562_init(PCIDevice *pci_dev)
2050{
2051 return nic_init(pci_dev, i82562);
ths663e8e52007-04-02 12:35:34 +00002052}
2053
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002054static PCIDeviceInfo eepro100_info[] = {
2055 {
Stefan Weilc4c270e2009-09-19 13:02:09 +02002056 .qdev.name = "i82550",
Stefan Weil762401e2010-03-02 22:37:48 +01002057 .qdev.desc = "Intel i82550 Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002058 .qdev.size = sizeof(EEPRO100State),
2059 .init = pci_i82550_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002060 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002061 .romfile = "gpxe-eepro100-80861209.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002062 .qdev.props = (Property[]) {
2063 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2064 DEFINE_PROP_END_OF_LIST(),
2065 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002066 },{
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002067 .qdev.name = "i82551",
Stefan Weil762401e2010-03-02 22:37:48 +01002068 .qdev.desc = "Intel i82551 Ethernet",
Juan Quintela273a2142009-08-24 18:42:37 +02002069 .qdev.size = sizeof(EEPRO100State),
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002070 .init = pci_i82551_init,
Gerd Hoffmanne3936fa2009-09-25 21:42:38 +02002071 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002072 .romfile = "gpxe-eepro100-80861209.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002073 .qdev.props = (Property[]) {
2074 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2075 DEFINE_PROP_END_OF_LIST(),
2076 },
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002077 },{
Stefan Weilc4c270e2009-09-19 13:02:09 +02002078 .qdev.name = "i82557a",
Stefan Weil762401e2010-03-02 22:37:48 +01002079 .qdev.desc = "Intel i82557A Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002080 .qdev.size = sizeof(EEPRO100State),
2081 .init = pci_i82557a_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002082 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002083 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002084 .qdev.props = (Property[]) {
2085 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2086 DEFINE_PROP_END_OF_LIST(),
2087 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002088 },{
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002089 .qdev.name = "i82557b",
Stefan Weil762401e2010-03-02 22:37:48 +01002090 .qdev.desc = "Intel i82557B Ethernet",
Juan Quintela273a2142009-08-24 18:42:37 +02002091 .qdev.size = sizeof(EEPRO100State),
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002092 .init = pci_i82557b_init,
Gerd Hoffmanne3936fa2009-09-25 21:42:38 +02002093 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002094 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002095 .qdev.props = (Property[]) {
2096 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2097 DEFINE_PROP_END_OF_LIST(),
2098 },
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002099 },{
Stefan Weilc4c270e2009-09-19 13:02:09 +02002100 .qdev.name = "i82557c",
Stefan Weil762401e2010-03-02 22:37:48 +01002101 .qdev.desc = "Intel i82557C Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002102 .qdev.size = sizeof(EEPRO100State),
2103 .init = pci_i82557c_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002104 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002105 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002106 .qdev.props = (Property[]) {
2107 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2108 DEFINE_PROP_END_OF_LIST(),
2109 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002110 },{
2111 .qdev.name = "i82558a",
Stefan Weil762401e2010-03-02 22:37:48 +01002112 .qdev.desc = "Intel i82558A Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002113 .qdev.size = sizeof(EEPRO100State),
2114 .init = pci_i82558a_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002115 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002116 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002117 .qdev.props = (Property[]) {
2118 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2119 DEFINE_PROP_END_OF_LIST(),
2120 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002121 },{
2122 .qdev.name = "i82558b",
Stefan Weil762401e2010-03-02 22:37:48 +01002123 .qdev.desc = "Intel i82558B Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002124 .qdev.size = sizeof(EEPRO100State),
2125 .init = pci_i82558b_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002126 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002127 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002128 .qdev.props = (Property[]) {
2129 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2130 DEFINE_PROP_END_OF_LIST(),
2131 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002132 },{
2133 .qdev.name = "i82559a",
Stefan Weil762401e2010-03-02 22:37:48 +01002134 .qdev.desc = "Intel i82559A Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002135 .qdev.size = sizeof(EEPRO100State),
2136 .init = pci_i82559a_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002137 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002138 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002139 .qdev.props = (Property[]) {
2140 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2141 DEFINE_PROP_END_OF_LIST(),
2142 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002143 },{
2144 .qdev.name = "i82559b",
Stefan Weil762401e2010-03-02 22:37:48 +01002145 .qdev.desc = "Intel i82559B Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002146 .qdev.size = sizeof(EEPRO100State),
2147 .init = pci_i82559b_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002148 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002149 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002150 .qdev.props = (Property[]) {
2151 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2152 DEFINE_PROP_END_OF_LIST(),
2153 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002154 },{
2155 .qdev.name = "i82559c",
Stefan Weil762401e2010-03-02 22:37:48 +01002156 .qdev.desc = "Intel i82559C Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002157 .qdev.size = sizeof(EEPRO100State),
2158 .init = pci_i82559c_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002159 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002160 .romfile = "gpxe-eepro100-80861229.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002161 .qdev.props = (Property[]) {
2162 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2163 DEFINE_PROP_END_OF_LIST(),
2164 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002165 },{
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002166 .qdev.name = "i82559er",
Stefan Weil762401e2010-03-02 22:37:48 +01002167 .qdev.desc = "Intel i82559ER Ethernet",
Juan Quintela273a2142009-08-24 18:42:37 +02002168 .qdev.size = sizeof(EEPRO100State),
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002169 .init = pci_i82559er_init,
Gerd Hoffmanne3936fa2009-09-25 21:42:38 +02002170 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002171 .romfile = "gpxe-eepro100-80861209.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002172 .qdev.props = (Property[]) {
2173 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2174 DEFINE_PROP_END_OF_LIST(),
2175 },
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002176 },{
Stefan Weilc4c270e2009-09-19 13:02:09 +02002177 .qdev.name = "i82562",
Stefan Weil762401e2010-03-02 22:37:48 +01002178 .qdev.desc = "Intel i82562 Ethernet",
Stefan Weilc4c270e2009-09-19 13:02:09 +02002179 .qdev.size = sizeof(EEPRO100State),
2180 .init = pci_i82562_init,
Stefan Weil6a90e302009-11-02 17:34:53 +01002181 .exit = pci_nic_uninit,
Stefan Weilda51e792010-03-02 22:37:44 +01002182 .romfile = "gpxe-eepro100-80861209.rom",
Gerd Hoffmann508ef932009-10-21 15:25:36 +02002183 .qdev.props = (Property[]) {
2184 DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
2185 DEFINE_PROP_END_OF_LIST(),
2186 },
Stefan Weilc4c270e2009-09-19 13:02:09 +02002187 },{
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002188 /* end of list */
2189 }
2190};
2191
Paul Brook9d07d752009-05-14 22:35:07 +01002192static void eepro100_register_devices(void)
2193{
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02002194 pci_qdev_register_many(eepro100_info);
Paul Brook9d07d752009-05-14 22:35:07 +01002195}
2196
2197device_init(eepro100_register_devices)